gui.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #include "gui_i.h"
  2. ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) {
  3. // Iterating backward
  4. ViewPortArray_it_t it;
  5. ViewPortArray_it_last(it, array);
  6. while(!ViewPortArray_end_p(it)) {
  7. ViewPort* view_port = *ViewPortArray_ref(it);
  8. if(view_port_is_enabled(view_port)) {
  9. return view_port;
  10. }
  11. ViewPortArray_previous(it);
  12. }
  13. return NULL;
  14. }
  15. void gui_update(Gui* gui) {
  16. furi_assert(gui);
  17. osThreadFlagsSet(gui->thread, GUI_THREAD_FLAG_DRAW);
  18. }
  19. void gui_input_events_callback(const void* value, void* ctx) {
  20. furi_assert(value);
  21. furi_assert(ctx);
  22. Gui* gui = ctx;
  23. osMessageQueuePut(gui->input_queue, value, 0, osWaitForever);
  24. osThreadFlagsSet(gui->thread, GUI_THREAD_FLAG_INPUT);
  25. }
  26. bool gui_redraw_fs(Gui* gui) {
  27. canvas_frame_set(gui->canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT);
  28. ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]);
  29. if(view_port) {
  30. view_port_draw(view_port, gui->canvas);
  31. return true;
  32. } else {
  33. return false;
  34. }
  35. }
  36. void gui_redraw_status_bar(Gui* gui) {
  37. ViewPortArray_it_t it;
  38. uint8_t x;
  39. uint8_t x_used = 0;
  40. uint8_t width;
  41. ViewPort* view_port;
  42. // Right side
  43. x = GUI_DISPLAY_WIDTH + 2;
  44. ViewPortArray_it(it, gui->layers[GuiLayerStatusBarRight]);
  45. while(!ViewPortArray_end_p(it) && x_used < GUI_STATUS_BAR_WIDTH) {
  46. // Render view_port;
  47. view_port = *ViewPortArray_ref(it);
  48. if(view_port_is_enabled(view_port)) {
  49. width = view_port_get_width(view_port);
  50. if(!width) width = 8;
  51. x_used += width;
  52. x -= (width + 2);
  53. canvas_frame_set(gui->canvas, x, GUI_STATUS_BAR_Y, width, GUI_STATUS_BAR_HEIGHT);
  54. view_port_draw(view_port, gui->canvas);
  55. }
  56. ViewPortArray_next(it);
  57. }
  58. // Left side
  59. x = 0;
  60. ViewPortArray_it(it, gui->layers[GuiLayerStatusBarLeft]);
  61. while(!ViewPortArray_end_p(it) && x_used < GUI_STATUS_BAR_WIDTH) {
  62. // Render view_port;
  63. view_port = *ViewPortArray_ref(it);
  64. if(view_port_is_enabled(view_port)) {
  65. width = view_port_get_width(view_port);
  66. if(!width) width = 8;
  67. x_used += width;
  68. canvas_frame_set(gui->canvas, x, GUI_STATUS_BAR_Y, width, GUI_STATUS_BAR_HEIGHT);
  69. view_port_draw(view_port, gui->canvas);
  70. x += (width + 2);
  71. }
  72. ViewPortArray_next(it);
  73. }
  74. }
  75. bool gui_redraw_normal(Gui* gui) {
  76. canvas_frame_set(gui->canvas, GUI_MAIN_X, GUI_MAIN_Y, GUI_MAIN_WIDTH, GUI_MAIN_HEIGHT);
  77. ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerMain]);
  78. if(view_port) {
  79. view_port_draw(view_port, gui->canvas);
  80. return true;
  81. }
  82. return false;
  83. }
  84. bool gui_redraw_none(Gui* gui) {
  85. canvas_frame_set(gui->canvas, GUI_MAIN_X, GUI_MAIN_Y, GUI_MAIN_WIDTH, GUI_MAIN_HEIGHT);
  86. ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerNone]);
  87. if(view_port) {
  88. view_port_draw(view_port, gui->canvas);
  89. return true;
  90. }
  91. return false;
  92. }
  93. void gui_redraw(Gui* gui) {
  94. furi_assert(gui);
  95. gui_lock(gui);
  96. canvas_reset(gui->canvas);
  97. if(!gui_redraw_fs(gui)) {
  98. if(!gui_redraw_normal(gui)) {
  99. gui_redraw_none(gui);
  100. }
  101. gui_redraw_status_bar(gui);
  102. }
  103. canvas_commit(gui->canvas);
  104. if(gui->canvas_callback) {
  105. gui->canvas_callback(
  106. canvas_get_buffer(gui->canvas),
  107. canvas_get_buffer_size(gui->canvas),
  108. gui->canvas_callback_context);
  109. }
  110. gui_unlock(gui);
  111. }
  112. void gui_input(Gui* gui, InputEvent* input_event) {
  113. furi_assert(gui);
  114. furi_assert(input_event);
  115. gui_lock(gui);
  116. ViewPort* view_port;
  117. view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]);
  118. if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerMain]);
  119. if(!view_port) view_port = gui_view_port_find_enabled(gui->layers[GuiLayerNone]);
  120. if(view_port) {
  121. view_port_input(view_port, input_event);
  122. }
  123. gui_unlock(gui);
  124. }
  125. void gui_lock(Gui* gui) {
  126. furi_assert(gui);
  127. furi_check(osMutexAcquire(gui->mutex, osWaitForever) == osOK);
  128. }
  129. void gui_unlock(Gui* gui) {
  130. furi_assert(gui);
  131. furi_check(osMutexRelease(gui->mutex) == osOK);
  132. }
  133. void gui_cli_screen_stream_callback(uint8_t* data, size_t size, void* context) {
  134. furi_assert(data);
  135. furi_assert(size == 1024);
  136. furi_assert(context);
  137. Gui* gui = context;
  138. uint8_t magic[] = {0xF0, 0xE1, 0xD2, 0xC3};
  139. cli_write(gui->cli, magic, sizeof(magic));
  140. cli_write(gui->cli, data, size);
  141. }
  142. void gui_cli_screen_stream(string_t args, void* context) {
  143. furi_assert(context);
  144. Gui* gui = context;
  145. gui_set_framebuffer_callback_context(gui, gui);
  146. gui_set_framebuffer_callback(gui, gui_cli_screen_stream_callback);
  147. cli_getc(gui->cli);
  148. gui_set_framebuffer_callback(gui, NULL);
  149. gui_set_framebuffer_callback_context(gui, NULL);
  150. }
  151. void gui_add_view_port(Gui* gui, ViewPort* view_port, GuiLayer layer) {
  152. furi_assert(gui);
  153. furi_assert(view_port);
  154. furi_check(layer < GuiLayerMAX);
  155. gui_lock(gui);
  156. // Verify that view port is not yet added
  157. ViewPortArray_it_t it;
  158. for(size_t i = 0; i < GuiLayerMAX; i++) {
  159. ViewPortArray_it(it, gui->layers[i]);
  160. while(!ViewPortArray_end_p(it)) {
  161. furi_assert(*ViewPortArray_ref(it) != view_port);
  162. ViewPortArray_next(it);
  163. }
  164. }
  165. // Add view port and link with gui
  166. ViewPortArray_push_back(gui->layers[layer], view_port);
  167. view_port_gui_set(view_port, gui);
  168. gui_unlock(gui);
  169. gui_update(gui);
  170. }
  171. void gui_remove_view_port(Gui* gui, ViewPort* view_port) {
  172. furi_assert(gui);
  173. furi_assert(view_port);
  174. gui_lock(gui);
  175. view_port_gui_set(view_port, NULL);
  176. ViewPortArray_it_t it;
  177. for(size_t i = 0; i < GuiLayerMAX; i++) {
  178. ViewPortArray_it(it, gui->layers[i]);
  179. while(!ViewPortArray_end_p(it)) {
  180. if(*ViewPortArray_ref(it) == view_port) {
  181. ViewPortArray_remove(gui->layers[i], it);
  182. } else {
  183. ViewPortArray_next(it);
  184. }
  185. }
  186. }
  187. gui_unlock(gui);
  188. }
  189. void gui_send_view_port_front(Gui* gui, ViewPort* view_port) {
  190. furi_assert(gui);
  191. furi_assert(view_port);
  192. gui_lock(gui);
  193. // Remove
  194. GuiLayer layer = GuiLayerMAX;
  195. ViewPortArray_it_t it;
  196. for(size_t i = 0; i < GuiLayerMAX; i++) {
  197. ViewPortArray_it(it, gui->layers[i]);
  198. while(!ViewPortArray_end_p(it)) {
  199. if(*ViewPortArray_ref(it) == view_port) {
  200. ViewPortArray_remove(gui->layers[i], it);
  201. furi_assert(layer == GuiLayerMAX);
  202. layer = i;
  203. } else {
  204. ViewPortArray_next(it);
  205. }
  206. }
  207. }
  208. furi_assert(layer != GuiLayerMAX);
  209. // Return to the top
  210. ViewPortArray_push_back(gui->layers[layer], view_port);
  211. gui_unlock(gui);
  212. }
  213. void gui_send_view_port_back(Gui* gui, ViewPort* view_port) {
  214. furi_assert(gui);
  215. furi_assert(view_port);
  216. gui_lock(gui);
  217. // Remove
  218. GuiLayer layer = GuiLayerMAX;
  219. ViewPortArray_it_t it;
  220. for(size_t i = 0; i < GuiLayerMAX; i++) {
  221. ViewPortArray_it(it, gui->layers[i]);
  222. while(!ViewPortArray_end_p(it)) {
  223. if(*ViewPortArray_ref(it) == view_port) {
  224. ViewPortArray_remove(gui->layers[i], it);
  225. furi_assert(layer == GuiLayerMAX);
  226. layer = i;
  227. } else {
  228. ViewPortArray_next(it);
  229. }
  230. }
  231. }
  232. furi_assert(layer != GuiLayerMAX);
  233. // Return to the top
  234. ViewPortArray_push_at(gui->layers[layer], 0, view_port);
  235. gui_unlock(gui);
  236. }
  237. void gui_set_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback) {
  238. furi_assert(gui);
  239. gui->canvas_callback = callback;
  240. }
  241. void gui_set_framebuffer_callback_context(Gui* gui, void* context) {
  242. furi_assert(gui);
  243. gui->canvas_callback_context = context;
  244. }
  245. Gui* gui_alloc() {
  246. Gui* gui = furi_alloc(sizeof(Gui));
  247. // Thread ID
  248. gui->thread = osThreadGetId();
  249. // Allocate mutex
  250. gui->mutex = osMutexNew(NULL);
  251. furi_check(gui->mutex);
  252. // Layers
  253. for(size_t i = 0; i < GuiLayerMAX; i++) {
  254. ViewPortArray_init(gui->layers[i]);
  255. }
  256. // Drawing canvas
  257. gui->canvas = canvas_init();
  258. // Input
  259. gui->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL);
  260. gui->input_events = furi_record_open("input_events");
  261. furi_check(gui->input_events);
  262. subscribe_pubsub(gui->input_events, gui_input_events_callback, gui);
  263. // Cli
  264. gui->cli = furi_record_open("cli");
  265. cli_add_command(gui->cli, "screen_stream", gui_cli_screen_stream, gui);
  266. return gui;
  267. }
  268. int32_t gui_task(void* p) {
  269. Gui* gui = gui_alloc();
  270. furi_record_create("gui", gui);
  271. while(1) {
  272. uint32_t flags = osThreadFlagsWait(GUI_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
  273. // Process and dispatch input
  274. if(flags & GUI_THREAD_FLAG_INPUT) {
  275. // Process till queue become empty
  276. InputEvent input_event;
  277. while(osMessageQueueGet(gui->input_queue, &input_event, NULL, 0) == osOK) {
  278. gui_input(gui, &input_event);
  279. }
  280. }
  281. // Process and dispatch draw call
  282. if(flags & GUI_THREAD_FLAG_DRAW) {
  283. // Clear flags that arrived on input step
  284. osThreadFlagsClear(GUI_THREAD_FLAG_DRAW);
  285. gui_redraw(gui);
  286. }
  287. }
  288. return 0;
  289. }