umpire_indicator.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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) canvas_draw_disc(canvas, ball_x + 2 + (i * 9), box_y + box_height + 4, 3);
  61. else canvas_draw_circle(canvas, ball_x + 2 + (i * 9), box_y + box_height + 4, 3);
  62. }
  63. for(int i = 0; i < 3; i++) {
  64. if(i < state->strikes) canvas_draw_disc(canvas, strike_x + 2 + (i * 12), box_y + box_height + 4, 3);
  65. else canvas_draw_circle(canvas, strike_x + 2 + (i * 12), box_y + box_height + 4, 3);
  66. }
  67. for(int i = 0; i < 3; i++) {
  68. if(i < state->outs) canvas_draw_disc(canvas, out_x + 2 + (i * 12), box_y + box_height + 4, 3);
  69. else canvas_draw_circle(canvas, out_x + 2 + (i * 12), box_y + box_height + 4, 3);
  70. }
  71. }
  72. void draw_callback(Canvas* canvas, void* ctx) {
  73. UmpireIndicatorState* state = ctx;
  74. if(state->state == StateInstructions) {
  75. draw_instructions(canvas);
  76. } else {
  77. draw_counter(canvas, state);
  78. }
  79. }
  80. void input_callback(InputEvent* input_event, void* ctx) {
  81. furi_assert(ctx);
  82. UmpireIndicatorState* state = ctx;
  83. if(input_event->type == InputTypeShort) {
  84. switch(input_event->key) {
  85. case InputKeyOk:
  86. if(state->state == StateInstructions) {
  87. state->state = StateCounter;
  88. }
  89. break;
  90. case InputKeyLeft:
  91. if(state->state == StateCounter) {
  92. if(state->balls < 4) state->balls++;
  93. if(state->balls == 4) {
  94. state->balls = 0;
  95. state->strikes = 0;
  96. }
  97. }
  98. break;
  99. case InputKeyUp:
  100. if(state->state == StateCounter) {
  101. if(state->strikes < 3) state->strikes++;
  102. if(state->strikes == 3) {
  103. state->strikes = 0;
  104. state->balls = 0;
  105. if(state->outs < 2) state->outs++;
  106. else {
  107. state->outs = 0;
  108. }
  109. }
  110. }
  111. break;
  112. case InputKeyRight:
  113. if(state->state == StateCounter) {
  114. if(state->outs < 2) state->outs++;
  115. else {
  116. state->outs = 0;
  117. state->balls = 0;
  118. state->strikes = 0;
  119. }
  120. }
  121. break;
  122. case InputKeyDown:
  123. if(state->state == StateCounter) {
  124. if(state->balls > 0) state->balls--;
  125. else if(state->strikes > 0) state->strikes--;
  126. else if(state->outs > 0) state->outs--;
  127. }
  128. break;
  129. case InputKeyBack:
  130. if(state->state == StateCounter) {
  131. state->balls = 0;
  132. state->strikes = 0;
  133. state->outs = 0;
  134. }
  135. break;
  136. default:
  137. break;
  138. }
  139. view_port_update(state->view_port);
  140. } else if(input_event->type == InputTypeLong && input_event->key == InputKeyBack) {
  141. state->exit = true;
  142. }
  143. }
  144. int32_t umpire_indicator_app(void* p) {
  145. UNUSED(p);
  146. UmpireIndicatorState* state = malloc(sizeof(UmpireIndicatorState));
  147. state->balls = 0;
  148. state->strikes = 0;
  149. state->outs = 0;
  150. state->exit = false;
  151. state->state = StateInstructions;
  152. state->view_port = view_port_alloc();
  153. view_port_draw_callback_set(state->view_port, draw_callback, state);
  154. view_port_input_callback_set(state->view_port, input_callback, state);
  155. state->gui = furi_record_open(RECORD_GUI);
  156. gui_add_view_port(state->gui, state->view_port, GuiLayerFullscreen);
  157. while(!state->exit) {
  158. furi_delay_ms(100);
  159. }
  160. view_port_enabled_set(state->view_port, false);
  161. gui_remove_view_port(state->gui, state->view_port);
  162. view_port_free(state->view_port);
  163. furi_record_close(RECORD_GUI);
  164. free(state);
  165. return 0;
  166. }