#include "gui_i.h" #include "core_defines.h" #include "record.h" #include "check.h" #define TAG "gui" // Forward declarations from gui_draw.c bool gui_redraw_fs(NbGui* gui); void gui_redraw(NbGui* gui); ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) { // Iterating backward ViewPortArray_it_t it; ViewPortArray_it_last(it, array); while(!ViewPortArray_end_p(it)) { ViewPort* view_port = *ViewPortArray_ref(it); if(view_port_is_enabled(view_port)) { return view_port; } ViewPortArray_previous(it); } return NULL; } size_t gui_active_view_port_count(NbGui* gui, GuiLayer layer) { furi_assert(gui); furi_check(layer < GuiLayerMAX); size_t ret = 0; gui_lock(gui); ViewPortArray_it_t it; ViewPortArray_it_last(it, gui->layers[layer]); while(!ViewPortArray_end_p(it)) { ViewPort* view_port = *ViewPortArray_ref(it); if(view_port_is_enabled(view_port)) { ret++; } ViewPortArray_previous(it); } gui_unlock(gui); return ret; } void gui_update(NbGui* gui) { ESP_LOGI(TAG, "gui_update"); furi_assert(gui); furi_thread_flags_set(gui->thread_id, GUI_THREAD_FLAG_DRAW); } void gui_lock(NbGui* gui) { furi_assert(gui); furi_check(furi_mutex_acquire(gui->mutex, FuriWaitForever) == FuriStatusOk); } void gui_unlock(NbGui* gui) { furi_assert(gui); furi_check(furi_mutex_release(gui->mutex) == FuriStatusOk); } void gui_add_view_port(NbGui* gui, ViewPort* view_port, GuiLayer layer) { furi_assert(gui); furi_assert(view_port); furi_check(layer < GuiLayerMAX); gui_lock(gui); // Verify that view port is not yet added ViewPortArray_it_t it; for(size_t i = 0; i < GuiLayerMAX; i++) { ViewPortArray_it(it, gui->layers[i]); while(!ViewPortArray_end_p(it)) { furi_assert(*ViewPortArray_ref(it) != view_port); ViewPortArray_next(it); } } // Add view port and link with gui ViewPortArray_push_back(gui->layers[layer], view_port); view_port_gui_set(view_port, gui); gui_unlock(gui); // Request redraw gui_update(gui); } void gui_remove_view_port(NbGui* gui, ViewPort* view_port) { furi_assert(gui); furi_assert(view_port); gui_lock(gui); view_port_gui_set(view_port, NULL); ViewPortArray_it_t it; for(size_t i = 0; i < GuiLayerMAX; i++) { ViewPortArray_it(it, gui->layers[i]); while(!ViewPortArray_end_p(it)) { if(*ViewPortArray_ref(it) == view_port) { ViewPortArray_remove(gui->layers[i], it); } else { ViewPortArray_next(it); } } } // if(gui->ongoing_input_view_port == view_port) { // gui->ongoing_input_view_port = NULL; // } gui_unlock(gui); // Request redraw gui_update(gui); } void gui_view_port_send_to_front(NbGui* gui, ViewPort* view_port) { furi_assert(gui); furi_assert(view_port); gui_lock(gui); // Remove GuiLayer layer = GuiLayerMAX; ViewPortArray_it_t it; for(size_t i = 0; i < GuiLayerMAX; i++) { ViewPortArray_it(it, gui->layers[i]); while(!ViewPortArray_end_p(it)) { if(*ViewPortArray_ref(it) == view_port) { ViewPortArray_remove(gui->layers[i], it); furi_assert(layer == GuiLayerMAX); layer = i; } else { ViewPortArray_next(it); } } } furi_assert(layer != GuiLayerMAX); // Return to the top ViewPortArray_push_back(gui->layers[layer], view_port); gui_unlock(gui); // Request redraw gui_update(gui); } void gui_view_port_send_to_back(NbGui* gui, ViewPort* view_port) { furi_assert(gui); furi_assert(view_port); gui_lock(gui); // Remove GuiLayer layer = GuiLayerMAX; ViewPortArray_it_t it; for(size_t i = 0; i < GuiLayerMAX; i++) { ViewPortArray_it(it, gui->layers[i]); while(!ViewPortArray_end_p(it)) { if(*ViewPortArray_ref(it) == view_port) { ViewPortArray_remove(gui->layers[i], it); furi_assert(layer == GuiLayerMAX); layer = i; } else { ViewPortArray_next(it); } } } furi_assert(layer != GuiLayerMAX); // Return to the top ViewPortArray_push_at(gui->layers[layer], 0, view_port); gui_unlock(gui); // Request redraw gui_update(gui); } void gui_set_lockdown(NbGui* gui, bool lockdown) { furi_assert(gui); gui_lock(gui); gui->lockdown = lockdown; gui_unlock(gui); // Request redraw gui_update(gui); } NbGui* gui_alloc() { NbGui* gui = malloc(sizeof(NbGui)); gui->thread_id = furi_thread_get_current_id(); gui->mutex = furi_mutex_alloc(FuriMutexTypeNormal); gui->lvgl_parent = lv_scr_act(); gui->lockdown = false; furi_check(gui->mutex); for(size_t i = 0; i < GuiLayerMAX; i++) { ViewPortArray_init(gui->layers[i]); } /* // Input gui->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); gui->input_events = furi_record_open(RECORD_INPUT_EVENTS); furi_check(gui->input_events); furi_pubsub_subscribe(gui->input_events, gui_input_events_callback, gui); */ return gui; } __attribute((__noreturn__)) int32_t prv_gui_main(void* parameter) { UNUSED(parameter); NbGui* gui = gui_alloc(); furi_record_create(RECORD_GUI, gui); while (1) { uint32_t flags = furi_thread_flags_wait( GUI_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever ); // Process and dispatch input if (flags & GUI_THREAD_FLAG_INPUT) { // // Process till queue become empty // InputEvent input_event; // while(furi_message_queue_get(gui->input_queue, &input_event, 0) == FuriStatusOk) { // gui_input(gui, &input_event); // } } // Process and dispatch draw call if (flags & GUI_THREAD_FLAG_DRAW) { // Clear flags that arrived on input step furi_thread_flags_clear(GUI_THREAD_FLAG_DRAW); gui_redraw(gui); } } } const NbApp gui_app = { .id = "gui", .name = "GUI", .type = SERVICE, .entry_point = &prv_gui_main, .stack_size = NB_TASK_STACK_SIZE_DEFAULT, .priority = NB_TASK_PRIORITY_DEFAULT };