umpire_indicator.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #include <furi.h>
  2. #include <gui/gui.h>
  3. #include <input/input.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. typedef enum {
  7. StateInstructions,
  8. StateCounter
  9. } AppState;
  10. typedef struct {
  11. int balls;
  12. int strikes;
  13. int outs;
  14. bool exit;
  15. AppState state;
  16. ViewPort* view_port;
  17. Gui* gui;
  18. } UmpireIndicatorState;
  19. char* int_to_char(int num) {
  20. static char buffer[2];
  21. snprintf(buffer, sizeof(buffer), "%d", num);
  22. return buffer;
  23. }
  24. void draw_instructions(Canvas* canvas) {
  25. canvas_clear(canvas);
  26. canvas_set_font(canvas, FontPrimary);
  27. canvas_draw_str(canvas, 2, 12, "Umpire Indicator");
  28. canvas_set_font(canvas, FontSecondary);
  29. canvas_draw_str(canvas, 2, 24, "Left: Ball Up: Strike");
  30. canvas_draw_str(canvas, 2, 34, "Right: Out Down: Undo");
  31. canvas_draw_str(canvas, 2, 44, "Back: Clear Hold: Exit");
  32. canvas_draw_str(canvas, 2, 54, "Press OK to start");
  33. }
  34. void draw_counter(Canvas* canvas, UmpireIndicatorState* state) {
  35. canvas_clear(canvas);
  36. // Define box dimensions and positions
  37. int box_width = 40;
  38. int box_height = 30;
  39. int ball_x = 2;
  40. int strike_x = 44;
  41. int out_x = 86;
  42. int box_y = 2;
  43. // Draw boxes
  44. canvas_draw_frame(canvas, ball_x, box_y, box_width, box_height);
  45. canvas_draw_frame(canvas, strike_x, box_y, box_width, box_height);
  46. canvas_draw_frame(canvas, out_x, box_y, box_width, box_height);
  47. // Draw labels
  48. canvas_set_font(canvas, FontPrimary);
  49. canvas_draw_str(canvas, ball_x + 2, box_y - 2, "B");
  50. canvas_draw_str(canvas, strike_x + 2, box_y - 2, "S");
  51. canvas_draw_str(canvas, out_x + 2, box_y - 2, "O");
  52. // Draw counts
  53. canvas_set_font(canvas, FontBigNumbers);
  54. canvas_draw_str(canvas, ball_x + 16, box_y + 22, int_to_char(state->balls));
  55. canvas_draw_str(canvas, strike_x + 16, box_y + 22, int_to_char(state->strikes));
  56. canvas_draw_str(canvas, out_x + 16, box_y + 22, int_to_char(state->outs));
  57. // Draw indicator circles
  58. canvas_set_font(canvas, FontSecondary);
  59. for(int i = 0; i < 4; i++) {
  60. if(i < state->balls)
  61. canvas_draw_disc(canvas, ball_x + 2 + (i * 9), box_y + box_height + 4, 3);
  62. else
  63. canvas_draw_circle(canvas, ball_x + 2 + (i * 9), box_y + box_height + 4, 3);
  64. }
  65. for(int i = 0; i < 3; i++) {
  66. if(i < state->strikes)
  67. canvas_draw_disc(canvas, strike_x + 2 + (i * 12), box_y + box_height + 4, 3);
  68. else
  69. canvas_draw_circle(canvas, strike_x + 2 + (i * 12), box_y + box_height + 4, 3);
  70. }
  71. for(int i = 0; i < 3; i++) {
  72. if(i < state->outs)
  73. canvas_draw_disc(canvas, out_x + 2 + (i * 12), box_y + box_height + 4, 3);
  74. else
  75. canvas_draw_circle(canvas, out_x + 2 + (i * 12), box_y + box_height + 4, 3);
  76. }
  77. }
  78. void draw_callback(Canvas* canvas, void* ctx) {
  79. UmpireIndicatorState* state = ctx;
  80. if(state->state == StateInstructions) {
  81. draw_instructions(canvas);
  82. } else {
  83. draw_counter(canvas, state);
  84. }
  85. }
  86. void input_callback(InputEvent* input_event, void* ctx) {
  87. furi_assert(ctx);
  88. UmpireIndicatorState* state = ctx;
  89. if(input_event->type == InputTypeShort) {
  90. switch(input_event->key) {
  91. case InputKeyOk:
  92. if(state->state == StateInstructions) {
  93. state->state = StateCounter;
  94. }
  95. break;
  96. case InputKeyLeft:
  97. if(state->state == StateCounter) {
  98. if(state->balls < 4) state->balls++;
  99. if(state->balls == 4) {
  100. state->balls = 0;
  101. state->strikes = 0;
  102. }
  103. }
  104. break;
  105. case InputKeyUp:
  106. if(state->state == StateCounter) {
  107. if(state->strikes < 3) state->strikes++;
  108. if(state->strikes == 3) {
  109. state->strikes = 0;
  110. state->balls = 0;
  111. if(state->outs < 2)
  112. state->outs++;
  113. else {
  114. state->outs = 0;
  115. }
  116. }
  117. }
  118. break;
  119. case InputKeyRight:
  120. if(state->state == StateCounter) {
  121. if(state->outs < 2)
  122. state->outs++;
  123. else {
  124. state->outs = 0;
  125. state->balls = 0;
  126. state->strikes = 0;
  127. }
  128. }
  129. break;
  130. case InputKeyDown:
  131. if(state->state == StateCounter) {
  132. if(state->balls > 0)
  133. state->balls--;
  134. else if(state->strikes > 0)
  135. state->strikes--;
  136. else if(state->outs > 0)
  137. state->outs--;
  138. }
  139. break;
  140. case InputKeyBack:
  141. if(state->state == StateCounter) {
  142. state->balls = 0;
  143. state->strikes = 0;
  144. state->outs = 0;
  145. }
  146. break;
  147. default:
  148. break;
  149. }
  150. view_port_update(state->view_port);
  151. } else if(input_event->type == InputTypeLong && input_event->key == InputKeyBack) {
  152. state->exit = true;
  153. }
  154. }
  155. int32_t umpire_indicator_app(void* p) {
  156. UNUSED(p);
  157. UmpireIndicatorState* state = malloc(sizeof(UmpireIndicatorState));
  158. state->balls = 0;
  159. state->strikes = 0;
  160. state->outs = 0;
  161. state->exit = false;
  162. state->state = StateInstructions;
  163. state->view_port = view_port_alloc();
  164. view_port_draw_callback_set(state->view_port, draw_callback, state);
  165. view_port_input_callback_set(state->view_port, input_callback, state);
  166. state->gui = furi_record_open(RECORD_GUI);
  167. gui_add_view_port(state->gui, state->view_port, GuiLayerFullscreen);
  168. while(!state->exit) {
  169. furi_delay_ms(100);
  170. }
  171. view_port_enabled_set(state->view_port, false);
  172. gui_remove_view_port(state->gui, state->view_port);
  173. view_port_free(state->view_port);
  174. furi_record_close(RECORD_GUI);
  175. free(state);
  176. return 0;
  177. }