app-template.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #pragma once
  2. #include "callback-connector.h"
  3. #include <furi.h>
  4. #include <furi-hal.h>
  5. #include <gui/gui.h>
  6. #include <input/input.h>
  7. // simple app class with template variables <state, events>
  8. template <class TState, class TEvent> class AppTemplate {
  9. public:
  10. ViewPort* view_port;
  11. osMessageQueueId_t event_queue;
  12. TState state;
  13. ValueMutex state_mutex;
  14. Gui* gui;
  15. AppTemplate();
  16. ~AppTemplate();
  17. void input_callback(InputEvent* input_event, void* ctx);
  18. void draw_callback(Canvas* canvas, void* ctx);
  19. virtual void render(Canvas* canvas) = 0;
  20. void acquire_state(void);
  21. void release_state(void);
  22. bool get_event(TEvent* event, uint32_t timeout);
  23. void app_ready(void);
  24. uint8_t exit(void);
  25. void update_gui(void);
  26. };
  27. template <class TState, class TEvent> AppTemplate<TState, TEvent>::AppTemplate() {
  28. // allocate events queue
  29. event_queue = osMessageQueueNew(10, sizeof(TEvent), NULL);
  30. // allocate valuemutex
  31. // TODO: use plain os mutex?
  32. if(!init_mutex(&state_mutex, &state, sizeof(TState))) {
  33. printf("cannot create mutex\n");
  34. furi_crash(NULL);
  35. }
  36. // open gui
  37. gui = (Gui*)furi_record_open("gui");
  38. // allocate view_port
  39. view_port = view_port_alloc();
  40. }
  41. template <class TState, class TEvent> AppTemplate<TState, TEvent>::~AppTemplate() {
  42. }
  43. // generic input callback
  44. template <class TState, class TEvent>
  45. void AppTemplate<TState, TEvent>::input_callback(InputEvent* input_event, void* ctx) {
  46. AppTemplate* app = static_cast<AppTemplate*>(ctx);
  47. TEvent event;
  48. event.type = TEvent::EventTypeKey;
  49. event.value.input = *input_event;
  50. osMessageQueuePut(app->event_queue, &event, 0, 0);
  51. }
  52. // generic draw callback
  53. template <class TState, class TEvent>
  54. void AppTemplate<TState, TEvent>::draw_callback(Canvas* canvas, void* ctx) {
  55. AppTemplate* app = static_cast<AppTemplate*>(ctx);
  56. app->acquire_state();
  57. canvas_clear(canvas);
  58. app->render(canvas);
  59. app->release_state();
  60. }
  61. template <class TState, class TEvent> void AppTemplate<TState, TEvent>::acquire_state(void) {
  62. acquire_mutex(&state_mutex, osWaitForever);
  63. }
  64. template <class TState, class TEvent> void AppTemplate<TState, TEvent>::release_state(void) {
  65. release_mutex(&state_mutex, &state);
  66. }
  67. template <class TState, class TEvent>
  68. bool AppTemplate<TState, TEvent>::get_event(TEvent* event, uint32_t timeout) {
  69. osStatus_t event_status = osMessageQueueGet(event_queue, event, NULL, timeout);
  70. return (event_status == osOK);
  71. }
  72. // signal that app is ready, and we can render something
  73. // also unblock dependent tasks
  74. template <class TState, class TEvent> void AppTemplate<TState, TEvent>::app_ready(void) {
  75. // connect view_port with input callback
  76. auto input_cb_ref = cbc::obtain_connector(this, &AppTemplate::input_callback);
  77. view_port_input_callback_set(view_port, input_cb_ref, this);
  78. // connect view_port with draw callback
  79. auto draw_cb_ref = cbc::obtain_connector(this, &AppTemplate::draw_callback);
  80. view_port_draw_callback_set(view_port, draw_cb_ref, this);
  81. // add view_port
  82. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  83. }
  84. template <class TState, class TEvent> uint8_t AppTemplate<TState, TEvent>::exit(void) {
  85. // TODO remove all view_ports create by app
  86. view_port_enabled_set(view_port, false);
  87. return 255;
  88. }
  89. template <class TState, class TEvent> void AppTemplate<TState, TEvent>::update_gui(void) {
  90. view_port_update(view_port);
  91. }