view_build.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved
  2. * See the LICENSE file for information about the license. */
  3. #include "app.h"
  4. extern ProtoViewDecoder *Decoders[]; // Defined in signal.c.
  5. /* Our view private data. */
  6. typedef struct {
  7. ProtoViewDecoder *decoder; // Decoder we are using to create a message.
  8. uint32_t cur_decoder; // Decoder index when we are yet selecting
  9. // a decoder. Used when decoder is NULL.
  10. ProtoViewFieldSet *fieldset; // The fields to populate.
  11. uint32_t cur_field; // Field we are editing right now. This
  12. // is the index inside the 'fieldset'
  13. // fields.
  14. } BuildViewPrivData;
  15. /* Not all the decoders support message bulding, so we can't just
  16. * increment / decrement the cur_decoder index here. */
  17. static void select_next_decoder(ProtoViewApp *app) {
  18. BuildViewPrivData *privdata = app->view_privdata;
  19. do {
  20. privdata->cur_decoder++;
  21. if (Decoders[privdata->cur_decoder] == NULL)
  22. privdata->cur_decoder = 0;
  23. } while(Decoders[privdata->cur_decoder]->get_fields == NULL);
  24. }
  25. /* Like select_next_decoder() but goes backward. */
  26. static void select_prev_decoder(ProtoViewApp *app) {
  27. BuildViewPrivData *privdata = app->view_privdata;
  28. do {
  29. if (privdata->cur_decoder == 0) {
  30. /* Go one after the last one to wrap around. */
  31. while(Decoders[privdata->cur_decoder]) privdata->cur_decoder++;
  32. }
  33. privdata->cur_decoder--;
  34. } while(Decoders[privdata->cur_decoder]->get_fields == NULL);
  35. }
  36. /* Render the view to select the decoder, among the ones that
  37. * support message building. */
  38. static void render_view_select_decoder(Canvas *const canvas, ProtoViewApp *app) {
  39. BuildViewPrivData *privdata = app->view_privdata;
  40. canvas_set_font(canvas, FontPrimary);
  41. canvas_draw_str(canvas, 0, 9, "Signal builder");
  42. canvas_set_font(canvas, FontSecondary);
  43. canvas_draw_str(canvas, 0, 19, "up/down: select, ok: choose");
  44. // When entering the view, the current decoder is just set to zero.
  45. // Seek the next valid if needed.
  46. if (Decoders[privdata->cur_decoder]->get_fields == NULL)
  47. select_next_decoder(app);
  48. canvas_set_font(canvas, FontPrimary);
  49. canvas_draw_str(canvas, 0, 9, "Signal builder");
  50. canvas_draw_str_aligned(canvas,64,40,AlignCenter,AlignCenter,
  51. Decoders[privdata->cur_decoder]->name);
  52. }
  53. /* Render the view that allows the user to populate the fields needed
  54. * for the selected decoder to build a message. */
  55. static void render_view_set_fields(Canvas *const canvas, ProtoViewApp *app) {
  56. BuildViewPrivData *privdata = app->view_privdata;
  57. char buf[32];
  58. snprintf(buf,sizeof(buf), "%s field %d/%d",
  59. privdata->decoder->name, (int)privdata->cur_field,
  60. (int)privdata->fieldset->numfields);
  61. canvas_set_font(canvas, FontPrimary);
  62. canvas_draw_str(canvas, 0, 9, buf);
  63. canvas_set_font(canvas, FontSecondary);
  64. canvas_draw_str(canvas, 0, 19, "up/down: next field, ok: edit");
  65. canvas_draw_str(canvas, 0, 62, "Long press ok: create signal");
  66. }
  67. /* Render the build message view. */
  68. void render_view_build_message(Canvas *const canvas, ProtoViewApp *app) {
  69. BuildViewPrivData *privdata = app->view_privdata;
  70. if (privdata->decoder)
  71. render_view_set_fields(canvas,app);
  72. else
  73. render_view_select_decoder(canvas,app);
  74. }
  75. /* Handle input for the decoder selection. */
  76. static void process_input_select_decoder(ProtoViewApp *app, InputEvent input) {
  77. BuildViewPrivData *privdata = app->view_privdata;
  78. if (input.type == InputTypeShort) {
  79. if (input.key == InputKeyOk) {
  80. privdata->decoder = Decoders[privdata->cur_decoder];
  81. privdata->fieldset = fieldset_new();
  82. privdata->decoder->get_fields(privdata->fieldset);
  83. } else if (input.key == InputKeyDown) {
  84. select_next_decoder(app);
  85. } else if (input.key == InputKeyUp) {
  86. select_prev_decoder(app);
  87. }
  88. }
  89. }
  90. /* Handle input for fields editing mode. */
  91. static void process_input_set_fields(ProtoViewApp *app, InputEvent input) {
  92. UNUSED(app);
  93. UNUSED(input);
  94. }
  95. /* Handle input for the build message view. */
  96. void process_input_build_message(ProtoViewApp *app, InputEvent input) {
  97. BuildViewPrivData *privdata = app->view_privdata;
  98. if (privdata->decoder)
  99. process_input_set_fields(app,input);
  100. else
  101. process_input_select_decoder(app,input);
  102. }
  103. /* Called on exit for cleanup. */
  104. void view_exit_build_message(ProtoViewApp *app) {
  105. BuildViewPrivData *privdata = app->view_privdata;
  106. if (privdata->fieldset) fieldset_free(privdata->fieldset);
  107. }