implemented gui and view_port

using flipper source (adapted)
disabled key input for now
disabled non-fullscreen drawing for now
This commit is contained in:
Ken Van Hoeylandt
2023-12-27 23:53:19 +01:00
parent 48d875a944
commit f0cfd3c34d
17 changed files with 993 additions and 87 deletions
@@ -3,83 +3,231 @@
#include "record.h"
#include "check.h"
static NbScreenId screen_counter = 0;
#define TAG "Gui"
NbGuiHandle gui_alloc() {
struct NbGui* gui = malloc(sizeof(struct NbGui));
ScreenDict_init(gui->screens);
gui->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
return 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;
}
void gui_free(NbGuiHandle gui) {
ScreenDict_clear(gui->screens);
furi_mutex_free(gui->mutex);
free(gui);
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_lock(NbGuiHandle gui) {
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(NbGuiHandle gui) {
void gui_unlock(NbGui* gui) {
furi_assert(gui);
furi_check(furi_mutex_release(gui->mutex) == FuriStatusOk);
}
NbScreenId gui_screen_create(NbGuiHandle gui, InitScreen callback) {
NbScreenId id = screen_counter++;
NbScreen screen = {
.id = id,
.parent = NULL,
.callback = callback
};
void gui_add_view_port(NbGui* gui, ViewPort* view_port, GuiLayer layer) {
furi_assert(gui);
furi_assert(view_port);
furi_check(layer < GuiLayerMAX);
ScreenDict_set_at(gui->screens, id, screen);
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);
// TODO: notify desktop of change
// TODO: have desktop update views
lv_obj_t* parent = lv_scr_act();
gui_screen_set_parent(gui, id, parent);
// TODO: call from desktop
screen.callback(gui_screen_get_parent(gui, id), id);
return id;
// Request redraw
gui_update(gui);
}
lv_obj_t* gui_screen_get_parent(NbGuiHandle gui, NbScreenId id) {
NbScreen* screen = ScreenDict_get(gui->screens, id);
furi_check(screen != NULL);
return screen->parent;
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_screen_set_parent(NbGuiHandle gui, NbScreenId id, lv_obj_t* parent) {
NbScreen* screen = ScreenDict_get(gui->screens, id);
furi_check(screen != NULL);
screen->parent = parent;
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_screen_free(NbGuiHandle gui, NbScreenId id) {
NbScreen* screen = ScreenDict_get(gui->screens, id);
furi_check(screen != NULL);
void gui_view_port_send_to_back(NbGui* gui, ViewPort* view_port) {
furi_assert(gui);
furi_assert(view_port);
// TODO: notify? use callback? (done from desktop service)
lv_obj_clean(screen->parent);
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);
ScreenDict_erase(gui->screens, id);
// Request redraw
gui_update(gui);
}
static int32_t prv_gui_main(void* param) {
UNUSED(param);
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();
struct NbGui* gui = gui_alloc();
furi_record_create(RECORD_GUI, gui);
printf("gui app init\n");
return 0;
}
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",