From e684869970ce5e4b9d785dd25ccd6620c82f441a Mon Sep 17 00:00:00 2001 From: aanper Date: Thu, 15 Oct 2020 18:05:28 +0300 Subject: [PATCH] refactor canvas --- applications/gui/canvas.c | 116 ++++++++++++++++++++++------------- applications/gui/canvas.h | 37 +++++++---- applications/gui/canvas_i.h | 4 +- applications/gui/gui.c | 49 ++++++++------- applications/gui/gui.h | 7 ++- applications/gui/gui_event.c | 18 +++--- applications/gui/gui_event.h | 14 ++--- applications/gui/gui_i.h | 2 +- applications/gui/widget.c | 21 ++++++- applications/gui/widget.h | 15 +---- applications/gui/widget_i.h | 2 +- applications/menu/menu.c | 3 +- 12 files changed, 169 insertions(+), 119 deletions(-) diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c index 6f1372843..2572bd233 100644 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -6,74 +6,104 @@ #include struct Canvas { - FuriRecordSubscriber* fb_record; - u8g2_t* fb; + u8g2_t fb; uint8_t offset_x; uint8_t offset_y; uint8_t width; uint8_t height; }; -Canvas* canvas_alloc() { - Canvas* canvas = furi_alloc(sizeof(Canvas)); - canvas->fb_record = furi_open_deprecated("u8g2_fb", false, false, NULL, NULL, NULL); - assert(canvas->fb_record); - return canvas; +uint8_t canvas_width(CanvasApi* api); +uint8_t canvas_height(CanvasApi* api); +void canvas_clear(CanvasApi* api); +void canvas_color_set(CanvasApi* api, uint8_t color); +void canvas_font_set(CanvasApi* api, Font font); +void canvas_str_draw(CanvasApi* api, uint8_t x, uint8_t y, const char* str); + +CanvasApi* canvas_api_init() { + CanvasApi* api = furi_alloc(sizeof(CanvasApi)); + + u8g2_t _u8g2; + u8g2_Setup_st7565_erc12864_alt_f( + &api->canvas.fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); + u8g2_InitDisplay( + &canvas->fb); // send init sequence to the display, display is in sleep mode after this + u8g2_SetContrast(&api->canvas.fb, 36); + + u8g2_SetPowerSave(&api->canvas.fb, 0); // wake up display + u8g2_SendBuffer(&api->canvas.fb); + + api->width = canvas_width; + api->height = canvas_height; + api->clear = canvas_clear; + api->canvas_color_set = canvas_color_set; + api->canvas_font_set = canvas_font_set; + api->draw_str = canvas_str_draw; + + api->fonts = { + .primary = u8g2_font_Born2bSportyV2_tr, + .secondary = u8g2_font_HelvetiPixel_tr, + }; + + return api; } -void canvas_free(Canvas* canvas) { - assert(canvas); - free(canvas); +void canvas_api_free(CanvasApi* api) { + assert(api); + free(api); } -void canvas_commit(Canvas* canvas) { - assert(canvas); - if(canvas->fb) { - furi_commit(canvas->fb_record); - canvas->fb = NULL; - } +void canvas_commit(CanvasApi* api) { + assert(api); + + u8g2_SetPowerSave(&api->canvas.fb, 0); // wake up display + u8g2_SendBuffer(&api->canvas.fb); } void canvas_frame_set( - Canvas* canvas, + CanvasApi* api, uint8_t offset_x, uint8_t offset_y, uint8_t width, uint8_t height) { - assert(canvas); - canvas->offset_x = offset_x; - canvas->offset_y = offset_y; - canvas->width = width; - canvas->height = height; + assert(api); + api->canvas.offset_x = offset_x; + api->canvas.offset_y = offset_y; + api->canvas.width = width; + api->canvas.height = height; } -u8g2_t* canvas_fb(Canvas* canvas) { - if(!canvas->fb) { - canvas->fb = furi_take(canvas->fb_record); - assert(canvas->fb); - } - return canvas->fb; +uint8_t canvas_width(CanvasApi* api) { + assert(api); + + return api->canvas.width; } -void canvas_clear(Canvas* canvas) { - u8g2_t* fb = canvas_fb(canvas); - u8g2_ClearBuffer(fb); +uint8_t canvas_height(CanvasApi* api) { + assert(api); + + return api->canvas.height; } -void canvas_color_set(Canvas* canvas, uint8_t color) { - u8g2_t* fb = canvas_fb(canvas); - u8g2_SetDrawColor(fb, 1); +void canvas_clear(CanvasApi* api) { + assert(api); + u8g2_ClearBuffer(&api->canvas.fb); } -void canvas_font_set(Canvas* canvas, font_t font) { - u8g2_t* fb = canvas_fb(canvas); - u8g2_SetFontMode(fb, 1); - u8g2_SetFont(fb, font); +void canvas_color_set(CanvasApi* api, Color color) { + assert(api); + u8g2_SetDrawColor(&api->canvas.fb, color); } -void canvas_str_draw(Canvas* canvas, uint8_t x, uint8_t y, const char* str) { - x += canvas->offset_x; - y += canvas->offset_y; - u8g2_t* fb = canvas_fb(canvas); - u8g2_DrawStr(fb, x, y, str); +void canvas_font_set(CanvasApi* api, Font font) { + assert(api); + u8g2_SetFontMode(&api->canvas.fb, 1); + u8g2_SetFont(&api->canvas.fb, font); +} + +void canvas_str_draw(CanvasApi* api, uint8_t x, uint8_t y, const char* str) { + assert(api); + x += api->canvas.offset_x; + y += api->canvas.offset_y; + u8g2_DrawStr(&api->canvas.fb, x, y, str); } diff --git a/applications/gui/canvas.h b/applications/gui/canvas.h index 3b0f547e0..d5692bf7b 100644 --- a/applications/gui/canvas.h +++ b/applications/gui/canvas.h @@ -1,24 +1,35 @@ #pragma once #include -#include -#define COLOR_WHITE 0x00 -#define COLOR_BLACK 0x01 - -#define CANVAS_FONT_PRIMARY u8g2_font_Born2bSportyV2_tr -#define CANVAS_FONT_SECONDARY u8g2_font_HelvetiPixel_tr +typedef enum { + ColorWhite = 0x00, + ColorBlack = 0x01, +} Color; typedef struct Canvas Canvas; -typedef const uint8_t* font_t; +typedef const uint8_t* Font; -uint8_t canvas_width(Canvas* canvas); -uint8_t canvas_height(Canvas* canvas); +struct _CanvasApi; -void canvas_clear(Canvas* canvas); +typedef struct _CanvasApi CanvasApi; -void canvas_color_set(Canvas* canvas, uint8_t color); +typedef struct { + Font primary; + Font secondary; +} Fonts; -void canvas_font_set(Canvas* canvas, font_t font); +struct { + Canvas canvas; + Fonts* fonts; + + uint8_t (*width)(CanvasApi* canvas); + uint8_t (*height)(CanvasApi* canvas); -void canvas_str_draw(Canvas* canvas, uint8_t x, uint8_t y, const char* str); + void (*clear)(CanvasApi* canvas); + + void (*canvas_color_set)(CanvasApi* canvas, Color color); + void (*canvas_font_set)(CanvasApi* canvas, Font font); + + void (*draw_str)(CanvasApi* canvas, uint8_t x, uint8_t y, const char* str); +} _CanvasApi; diff --git a/applications/gui/canvas_i.h b/applications/gui/canvas_i.h index c24b21029..b32eb0494 100644 --- a/applications/gui/canvas_i.h +++ b/applications/gui/canvas_i.h @@ -1,8 +1,8 @@ #pragma once -Canvas* canvas_alloc(); +CanvasApi* canvas_api_init(); -void canvas_free(Canvas* canvas); +void canvas_api_free(CanvasApi* api); void canvas_commit(Canvas* canvas); diff --git a/applications/gui/gui.c b/applications/gui/gui.c index 6724b97d2..75b9611d1 100644 --- a/applications/gui/gui.c +++ b/applications/gui/gui.c @@ -13,16 +13,16 @@ ARRAY_DEF(WidgetArray, Widget*, M_PTR_OPLIST); -struct GUI { - GUIEvent* event; - Canvas* canvas; +struct Gui { + GuiEvent* event; + CanvasApi* canvas_api; WidgetArray_t widgets_status_bar; WidgetArray_t widgets; WidgetArray_t widgets_fs; WidgetArray_t widgets_dialog; }; -void gui_add_widget(GUI* gui, Widget* widget, WidgetLayer layer) { +void gui_add_widget(Gui* gui, Widget* widget, WidgetLayer layer) { WidgetArray_t* widget_array = NULL; switch(layer) { @@ -54,10 +54,10 @@ void gui_add_widget(GUI* gui, Widget* widget, WidgetLayer layer) { gui_update(gui); } -void gui_update(GUI* gui) { +void gui_update(Gui* gui) { assert(gui); - GUIMessage message; - message.type = GUIMessageTypeRedraw; + GuiMessage message; + message.type = GuiMessageTypeRedraw; gui_event_messsage_send(gui->event, &message); } @@ -72,7 +72,7 @@ Widget* gui_widget_find_enabled(WidgetArray_t array) { return NULL; } -bool gui_redraw_fs(GUI* gui) { +bool gui_redraw_fs(Gui* gui) { canvas_frame_set(gui->canvas, 0, 0, 128, 64); Widget* widget = gui_widget_find_enabled(gui->widgets_fs); if(widget) { @@ -83,25 +83,25 @@ bool gui_redraw_fs(GUI* gui) { } } -void gui_redraw_status_bar(GUI* gui) { +void gui_redraw_status_bar(Gui* gui) { canvas_frame_set(gui->canvas, 0, 0, 128, 64); Widget* widget = gui_widget_find_enabled(gui->widgets_status_bar); if(widget) widget_draw(widget, gui->canvas); } -void gui_redraw_normal(GUI* gui) { +void gui_redraw_normal(Gui* gui) { canvas_frame_set(gui->canvas, 0, 9, 128, 55); Widget* widget = gui_widget_find_enabled(gui->widgets); if(widget) widget_draw(widget, gui->canvas); } -void gui_redraw_dialogs(GUI* gui) { +void gui_redraw_dialogs(Gui* gui) { canvas_frame_set(gui->canvas, 10, 20, 118, 44); Widget* widget = gui_widget_find_enabled(gui->widgets_dialog); if(widget) widget_draw(widget, gui->canvas); } -void gui_redraw(GUI* gui) { +void gui_redraw(Gui* gui) { assert(gui); if(!gui_redraw_fs(gui)) { @@ -110,10 +110,11 @@ void gui_redraw(GUI* gui) { } gui_redraw_dialogs(gui); - canvas_commit(gui->canvas); + // canvas_commit(gui->canvas); + // redraw u8g2 } -void gui_input(GUI* gui, InputEvent* input_event) { +void gui_input(Gui* gui, InputEvent* input_event) { assert(gui); Widget* widget = gui_widget_find_enabled(gui->widgets_dialog); @@ -125,8 +126,8 @@ void gui_input(GUI* gui, InputEvent* input_event) { } } -GUI* gui_alloc() { - GUI* gui = furi_alloc(sizeof(GUI)); +Gui* gui_alloc() { + Gui* gui = furi_alloc(sizeof(Gui)); // Initialize widget arrays WidgetArray_init(gui->widgets_status_bar); WidgetArray_init(gui->widgets); @@ -135,15 +136,17 @@ GUI* gui_alloc() { // Event dispatcher gui->event = gui_event_alloc(); - - // Drawing canvas - gui->canvas = canvas_alloc(); + + // Drawing canvas api + + gui->canvas_api = + canvas_api_init(); return gui; } void gui_task(void* p) { - GUI* gui = gui_alloc(); + Gui* gui = gui_alloc(); GuiApi gui_api = { .add_widget = gui_add_widget, @@ -160,10 +163,10 @@ void gui_task(void* p) { // Forever dispatch while(1) { - GUIMessage message = gui_event_message_next(gui->event); - if(message.type == GUIMessageTypeRedraw) { + GuiMessage message = gui_event_message_next(gui->event); + if(message.type == GuiMessageTypeRedraw) { gui_redraw(gui); - } else if(message.type == GUIMessageTypeInput) { + } else if(message.type == GuiMessageTypeInput) { gui_input(gui, &message.input); } } diff --git a/applications/gui/gui.h b/applications/gui/gui.h index b09e3bff2..a65ea53d4 100644 --- a/applications/gui/gui.h +++ b/applications/gui/gui.h @@ -1,6 +1,7 @@ #pragma once #include "widget.h" +#include "canvas.h" typedef enum { WidgetLayerStatusBar, @@ -10,9 +11,9 @@ typedef enum { } WidgetLayer; typedef struct Widget Widget; -typedef struct GUI GUI; +typedef struct Gui Gui; typedef struct { - void (*add_widget)(GUI* gui, Widget* widget, WidgetLayer layer); - GUI* gui; + void (*add_widget)(Gui* gui, Widget* widget, WidgetLayer layer); + Gui* gui; } GuiApi; diff --git a/applications/gui/gui_event.c b/applications/gui/gui_event.c index a2ee801b7..5c04d9a33 100644 --- a/applications/gui/gui_event.c +++ b/applications/gui/gui_event.c @@ -5,7 +5,7 @@ #define GUI_EVENT_MQUEUE_SIZE 8 -struct GUIEvent { +struct GuiEvent { FuriRecordSubscriber* input_event_record; osMessageQueueId_t mqueue; osMutexId_t lock_mutex; @@ -13,7 +13,7 @@ struct GUIEvent { void gui_event_input_events_callback(const void* value, size_t size, void* ctx) { assert(ctx); - GUIEvent* gui_event = ctx; + GuiEvent* gui_event = ctx; GUIMessage message; message.type = GUIMessageTypeInput; @@ -22,8 +22,8 @@ void gui_event_input_events_callback(const void* value, size_t size, void* ctx) osMessageQueuePut(gui_event->mqueue, &message, 0, 0); } -GUIEvent* gui_event_alloc() { - GUIEvent* gui_event = furi_alloc(sizeof(GUIEvent)); +GuiEvent* gui_event_alloc() { + GuiEvent* gui_event = furi_alloc(sizeof(GuiEvent)); // Allocate message que gui_event->mqueue = osMessageQueueNew(GUI_EVENT_MQUEUE_SIZE, sizeof(GUIMessage), NULL); assert(gui_event->mqueue); @@ -40,30 +40,30 @@ GUIEvent* gui_event_alloc() { return gui_event; } -void gui_event_free(GUIEvent* gui_event) { +void gui_event_free(GuiEvent* gui_event) { assert(gui_event); gui_event_unlock(gui_event); assert(osMessageQueueDelete(gui_event->mqueue) == osOK); free(gui_event); } -void gui_event_lock(GUIEvent* gui_event) { +void gui_event_lock(GuiEvent* gui_event) { assert(gui_event); assert(osMutexAcquire(gui_event->lock_mutex, osWaitForever) == osOK); } -void gui_event_unlock(GUIEvent* gui_event) { +void gui_event_unlock(GuiEvent* gui_event) { assert(gui_event); assert(osMutexRelease(gui_event->lock_mutex) == osOK); } -void gui_event_messsage_send(GUIEvent* gui_event, GUIMessage* message) { +void gui_event_messsage_send(GuiEvent* gui_event, GUIMessage* message) { assert(gui_event); assert(message); osMessageQueuePut(gui_event->mqueue, message, 0, 0); } -GUIMessage gui_event_message_next(GUIEvent* gui_event) { +GUIMessage gui_event_message_next(GuiEvent* gui_event) { assert(gui_event); GUIMessage message; gui_event_unlock(gui_event); diff --git a/applications/gui/gui_event.h b/applications/gui/gui_event.h index c3a47e451..730eb8c67 100644 --- a/applications/gui/gui_event.h +++ b/applications/gui/gui_event.h @@ -14,16 +14,16 @@ typedef struct { void* data; } GUIMessage; -typedef struct GUIEvent GUIEvent; +typedef struct GuiEvent GuiEvent; -GUIEvent* gui_event_alloc(); +GuiEvent* gui_event_alloc(); -void gui_event_free(GUIEvent* gui_event); +void gui_event_free(GuiEvent* gui_event); -void gui_event_lock(GUIEvent* gui_event); +void gui_event_lock(GuiEvent* gui_event); -void gui_event_unlock(GUIEvent* gui_event); +void gui_event_unlock(GuiEvent* gui_event); -void gui_event_messsage_send(GUIEvent* gui_event, GUIMessage* message); +void gui_event_messsage_send(GuiEvent* gui_event, GUIMessage* message); -GUIMessage gui_event_message_next(GUIEvent* gui_event); +GUIMessage gui_event_message_next(GuiEvent* gui_event); diff --git a/applications/gui/gui_i.h b/applications/gui/gui_i.h index e12970fc3..6a9bf2a0e 100644 --- a/applications/gui/gui_i.h +++ b/applications/gui/gui_i.h @@ -1,3 +1,3 @@ #pragma once -void gui_update(GUI* gui); +void gui_update(Gui* gui); diff --git a/applications/gui/widget.c b/applications/gui/widget.c index 1b6b6345a..169812624 100644 --- a/applications/gui/widget.c +++ b/applications/gui/widget.c @@ -7,6 +7,15 @@ #include "gui.h" #include "gui_i.h" +struct Widget { + void* gui; + bool is_enabled; + WidgetDrawCallback draw_callback; + void* draw_callback_context; + WidgetInputCallback input_callback; + void* input_callback_context; +} + Widget* widget_alloc(WidgetDrawCallback callback, void* callback_context) { Widget* widget = furi_alloc(sizeof(Widget)); widget->is_enabled = true; @@ -53,12 +62,18 @@ void widget_gui_set(Widget* widget, GUI* gui) { widget->gui = gui; } -void widget_draw(Widget* widget, Canvas* canvas) { +void widget_draw(Widget* widget, ValueMutex* canvas_api_mutex) { assert(widget); - assert(canvas); + assert(canvas_api_mutex); assert(widget->gui); - if(widget->draw_callback) widget->draw_callback(canvas, widget->draw_callback_context); + if(widget->draw_callback) { + CanvasApi* api = acquire_mutex_block(canvas_api_mutex); // TODO: timeout? + if(api != NULL) { + widget->draw_callback(api, widget->draw_callback_context); + } + release_mutex(canvas_api_mutex, api); + } } void widget_input(Widget* widget, InputEvent* event) { diff --git a/applications/gui/widget.h b/applications/gui/widget.h index 340e5310a..83f7d4977 100644 --- a/applications/gui/widget.h +++ b/applications/gui/widget.h @@ -1,20 +1,11 @@ #pragma once #include +#include "canvas.h" -typedef struct GUI GUI; -typedef struct Canvas Canvas; +typedef struct Widget Widget; -typedef struct { - void* gui; - bool is_enabled; - WidgetDrawCallback draw_callback; - void* draw_callback_context; - WidgetInputCallback input_callback; - void* input_callback_context; -} Widget; - -typedef void (*WidgetDrawCallback)(Canvas* canvas, void* context); +typedef void (*WidgetDrawCallback)(CanvasApi* api, void* context); typedef void (*WidgetInputCallback)(InputEvent* event, void* context); Widget* widget_alloc(); diff --git a/applications/gui/widget_i.h b/applications/gui/widget_i.h index 5c1af22da..b0fefa443 100644 --- a/applications/gui/widget_i.h +++ b/applications/gui/widget_i.h @@ -1,6 +1,6 @@ #pragma once -void widget_gui_set(Widget* widget, GUI* gui); +void widget_gui_set(Widget* widget, Gui* gui); void widget_draw(Widget* widget, Canvas* canvas); diff --git a/applications/menu/menu.c b/applications/menu/menu.c index 8cafe6a44..fdef8cadc 100644 --- a/applications/menu/menu.c +++ b/applications/menu/menu.c @@ -6,7 +6,6 @@ #include #include #include -#include #include "menu_event.h" #include "menu_item.h" @@ -37,7 +36,7 @@ Menu* menu_alloc() { widget_input_callback_set(menu->widget, menu_event_input_callback, menu->event); // Open GUI and register fullscreen widget - menu->gui_record = furi_open_deprecated("gui", false, false, NULL, NULL, NULL); + menu->gui_record = furi_open("gui"); assert(menu->gui_record); return menu;