* app loading wip * various improvements irq/isr stuff is now working lvgl locking where needed hello world now uses proper mutex for app unlocking etc? * various improvements * cmsis_esp improvements * implement interrupts
247 lines
6.4 KiB
C
247 lines
6.4 KiB
C
#include "check.h"
|
|
#include "esp_lvgl_port.h"
|
|
#include "furi_extra_defines.h"
|
|
#include "gui_i.h"
|
|
#include "record.h"
|
|
|
|
#define TAG "gui"
|
|
|
|
// Forward declarations from gui_draw.c
|
|
bool gui_redraw_fs(Gui* gui);
|
|
void gui_redraw(Gui* 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(Gui* 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(Gui* gui) {
|
|
ESP_LOGI(TAG, "gui_update");
|
|
furi_assert(gui);
|
|
furi_thread_flags_set(gui->thread_id, GUI_THREAD_FLAG_DRAW);
|
|
}
|
|
|
|
void gui_lock(Gui* gui) {
|
|
furi_assert(gui);
|
|
furi_check(furi_mutex_acquire(gui->mutex, FuriWaitForever) == FuriStatusOk);
|
|
}
|
|
|
|
void gui_unlock(Gui* gui) {
|
|
furi_assert(gui);
|
|
furi_check(furi_mutex_release(gui->mutex) == FuriStatusOk);
|
|
}
|
|
|
|
void gui_add_view_port(Gui* 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(Gui* 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(Gui* 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(Gui* 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(Gui* gui, bool lockdown) {
|
|
furi_assert(gui);
|
|
|
|
gui_lock(gui);
|
|
gui->lockdown = lockdown;
|
|
gui_unlock(gui);
|
|
|
|
// Request redraw
|
|
gui_update(gui);
|
|
}
|
|
|
|
Gui* gui_alloc() {
|
|
Gui* gui = malloc(sizeof(Gui));
|
|
gui->thread_id = furi_thread_get_current_id();
|
|
gui->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
|
|
|
furi_check(lvgl_port_lock(100));
|
|
gui->lvgl_parent = lv_scr_act();
|
|
lvgl_port_unlock();
|
|
|
|
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);
|
|
Gui* 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 AppManifest gui_app = {
|
|
.id = "gui",
|
|
.name = "GUI",
|
|
.icon = NULL,
|
|
.type = AppTypeService,
|
|
.entry_point = &prv_gui_main,
|
|
.stack_size = AppStackSizeNormal
|
|
};
|