implemented basic desktop
This commit is contained in:
parent
f6c547ad45
commit
48d2fd6c2d
@ -12,11 +12,16 @@ typedef struct _lv_obj_t lv_obj_t;
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
AppTypeService,
|
AppTypeService,
|
||||||
AppTypeSystem,
|
AppTypeSystem,
|
||||||
|
AppTypeDesktop,
|
||||||
AppTypeUser
|
AppTypeUser
|
||||||
} AppType;
|
} AppType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AppStackSizeNormal = 2048
|
AppStackSizeTiny = 512,
|
||||||
|
AppStackSizeSmall = 1024,
|
||||||
|
AppStackSizeNormal = 2048,
|
||||||
|
AppStackSizeLarge = 4096,
|
||||||
|
AppStackSizeHuge = 8192,
|
||||||
} AppStackSize;
|
} AppStackSize;
|
||||||
|
|
||||||
typedef void (*AppOnStart)(void _Nonnull* parameter);
|
typedef void (*AppOnStart)(void _Nonnull* parameter);
|
||||||
|
|||||||
@ -64,16 +64,16 @@ const AppManifest _Nullable* app_manifest_registry_find_by_id(const char* id) {
|
|||||||
return (manifest != NULL) ? *manifest : NULL;
|
return (manifest != NULL) ? *manifest : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_manifest_registry_for_each_of_type(AppType type, AppManifestCallback callback) {
|
void app_manifest_registry_for_each_of_type(AppType type, void* _Nullable context, AppManifestCallback callback) {
|
||||||
APP_REGISTRY_FOR_EACH(manifest, {
|
APP_REGISTRY_FOR_EACH(manifest, {
|
||||||
if (manifest->type == type) {
|
if (manifest->type == type) {
|
||||||
callback(manifest);
|
callback(manifest, context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_manifest_registry_for_each(AppManifestCallback callback) {
|
void app_manifest_registry_for_each(AppManifestCallback callback, void* _Nullable context) {
|
||||||
APP_REGISTRY_FOR_EACH(manifest, {
|
APP_REGISTRY_FOR_EACH(manifest, {
|
||||||
callback(manifest);
|
callback(manifest, context);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,14 +9,14 @@ extern "C" {
|
|||||||
extern const AppManifest* const INTERNAL_APP_MANIFESTS[];
|
extern const AppManifest* const INTERNAL_APP_MANIFESTS[];
|
||||||
extern const size_t INTERNAL_APP_COUNT;
|
extern const size_t INTERNAL_APP_COUNT;
|
||||||
|
|
||||||
typedef void (*AppManifestCallback)(const AppManifest*);
|
typedef void (*AppManifestCallback)(const AppManifest*, void* context);
|
||||||
|
|
||||||
void app_manifest_registry_init();
|
void app_manifest_registry_init();
|
||||||
void app_manifest_registry_add(const AppManifest _Nonnull* manifest);
|
void app_manifest_registry_add(const AppManifest _Nonnull* manifest);
|
||||||
void app_manifest_registry_remove(const AppManifest _Nonnull* manifest);
|
void app_manifest_registry_remove(const AppManifest _Nonnull* manifest);
|
||||||
const AppManifest _Nullable* app_manifest_registry_find_by_id(const char* id);
|
const AppManifest _Nullable* app_manifest_registry_find_by_id(const char* id);
|
||||||
void app_manifest_registry_for_each(AppManifestCallback callback);
|
void app_manifest_registry_for_each(AppManifestCallback callback, void* _Nullable context);
|
||||||
void app_manifest_registry_for_each_of_type(AppType type, AppManifestCallback callback);
|
void app_manifest_registry_for_each_of_type(AppType type, void* _Nullable context, AppManifestCallback callback);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 274 B |
|
Before Width: | Height: | Size: 224 B After Width: | Height: | Size: 224 B |
@ -1,18 +1,59 @@
|
|||||||
#include "desktop.h"
|
#include "desktop.h"
|
||||||
#include "furi_extra_defines.h"
|
#include "lvgl.h"
|
||||||
|
#include "check.h"
|
||||||
|
#include "record.h"
|
||||||
|
#include "apps/services/loader/loader.h"
|
||||||
|
#include "apps/services/gui/gui.h"
|
||||||
|
#include "apps/services/gui/view_port.h"
|
||||||
|
#include "app_manifest_registry.h"
|
||||||
|
|
||||||
static void desktop_start(void* param) {
|
static void on_open_app(lv_event_t* e) {
|
||||||
UNUSED(param);
|
lv_event_code_t code = lv_event_get_code(e);
|
||||||
printf("desktop app init\n");
|
if (code == LV_EVENT_CLICKED) {
|
||||||
|
const AppManifest* manifest = lv_event_get_user_data(e);
|
||||||
|
FURI_RECORD_TRANSACTION(RECORD_LOADER, Loader*, loader, {
|
||||||
|
loader_start_app_nonblocking(loader, manifest->id, NULL);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_app_to_list(const AppManifest* manifest, void* _Nullable parent) {
|
||||||
|
furi_check(parent);
|
||||||
|
lv_obj_t* list = (lv_obj_t*)parent;
|
||||||
|
lv_obj_t* btn = lv_list_add_btn(list, LV_SYMBOL_FILE, manifest->name);
|
||||||
|
lv_obj_add_event_cb(btn, &on_open_app, LV_EVENT_CLICKED, (void*)manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void desktop_show(lv_obj_t* parent, void* context) {
|
||||||
|
lv_obj_t* list = lv_list_create(parent);
|
||||||
|
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
|
||||||
|
lv_obj_center(list);
|
||||||
|
|
||||||
|
lv_list_add_text(list, "System");
|
||||||
|
app_manifest_registry_for_each_of_type(AppTypeSystem, list, add_app_to_list);
|
||||||
|
lv_list_add_text(list, "User");
|
||||||
|
app_manifest_registry_for_each_of_type(AppTypeUser, list, add_app_to_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void desktop_start() {
|
||||||
|
ViewPort* view_port = view_port_alloc();
|
||||||
|
view_port_draw_callback_set(view_port, &desktop_show, NULL);
|
||||||
|
FURI_RECORD_TRANSACTION(RECORD_GUI, Gui*, gui, {
|
||||||
|
gui_add_view_port(gui, view_port, GuiLayerDesktop);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static void desktop_stop() {
|
||||||
|
furi_crash("desktop_stop is not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppManifest desktop_app = {
|
const AppManifest desktop_app = {
|
||||||
.id = "desktop",
|
.id = "desktop",
|
||||||
.name = "Desktop",
|
.name = "Desktop",
|
||||||
.icon = NULL,
|
.icon = NULL,
|
||||||
.type = AppTypeService,
|
.type = AppTypeDesktop,
|
||||||
.on_start = &desktop_start,
|
.on_start = &desktop_start,
|
||||||
.on_stop = NULL,
|
.on_stop = &desktop_stop,
|
||||||
.on_show = NULL,
|
.on_show = NULL,
|
||||||
.stack_size = AppStackSizeNormal
|
.stack_size = AppStackSizeNormal
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,162 +1,17 @@
|
|||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "gui_i.h"
|
#include "gui_i.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "record.h"
|
||||||
#include "esp_lvgl_port.h"
|
#include "esp_lvgl_port.h"
|
||||||
#include "apps/services/gui/widgets/widgets.h"
|
#include "apps/services/gui/widgets/widgets.h"
|
||||||
|
#include "apps/services/loader/loader.h"
|
||||||
|
|
||||||
static void gui_redraw_status_bar(Gui* gui, bool need_attention) {
|
#define TAG "gui"
|
||||||
/*
|
|
||||||
ViewPortArray_it_t it;
|
|
||||||
uint8_t left_used = 0;
|
|
||||||
uint8_t right_used = 0;
|
|
||||||
uint8_t width;
|
|
||||||
|
|
||||||
canvas_frame_set(
|
static lv_obj_t* screen_with_top_bar(lv_obj_t* parent) {
|
||||||
gui->lvgl_parent, GUI_STATUS_BAR_X, GUI_STATUS_BAR_Y, GUI_DISPLAY_WIDTH, GUI_STATUS_BAR_HEIGHT);
|
lv_obj_set_style_bg_blacken(parent);
|
||||||
|
|
||||||
// for support black theme - paint white area and
|
lv_obj_t* vertical_container = lv_obj_create(parent);
|
||||||
// draw icon with transparent white color
|
|
||||||
|
|
||||||
canvas_set_color(gui->canvas, ColorWhite);
|
|
||||||
canvas_draw_box(gui->canvas, 1, 1, 9, 7);
|
|
||||||
canvas_draw_box(gui->canvas, 7, 3, 58, 6);
|
|
||||||
canvas_draw_box(gui->canvas, 61, 1, 32, 7);
|
|
||||||
canvas_draw_box(gui->canvas, 89, 3, 38, 6);
|
|
||||||
canvas_set_color(gui->canvas, ColorBlack);
|
|
||||||
canvas_set_bitmap_mode(gui->canvas, 1);
|
|
||||||
canvas_draw_icon(gui->canvas, 0, 0, &I_Background_128x11);
|
|
||||||
canvas_set_bitmap_mode(gui->canvas, 0);
|
|
||||||
|
|
||||||
// Right side
|
|
||||||
uint8_t x = GUI_DISPLAY_WIDTH - 1;
|
|
||||||
ViewPortArray_it(it, gui->layers[GuiLayerStatusBarRight]);
|
|
||||||
while(!ViewPortArray_end_p(it) && right_used < GUI_STATUS_BAR_WIDTH) {
|
|
||||||
ViewPort* view_port = *ViewPortArray_ref(it);
|
|
||||||
if(view_port_is_enabled(view_port)) {
|
|
||||||
width = view_port_get_width(view_port);
|
|
||||||
if(!width) width = 8;
|
|
||||||
// Recalculate next position
|
|
||||||
right_used += (width + 2);
|
|
||||||
x -= (width + 2);
|
|
||||||
// Prepare work area background
|
|
||||||
canvas_frame_set(
|
|
||||||
gui->canvas,
|
|
||||||
x - 1,
|
|
||||||
GUI_STATUS_BAR_Y + 1,
|
|
||||||
width + 2,
|
|
||||||
GUI_STATUS_BAR_WORKAREA_HEIGHT + 2);
|
|
||||||
canvas_set_color(gui->canvas, ColorWhite);
|
|
||||||
canvas_draw_box(
|
|
||||||
gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas));
|
|
||||||
canvas_set_color(gui->canvas, ColorBlack);
|
|
||||||
// ViewPort draw
|
|
||||||
canvas_frame_set(
|
|
||||||
gui->canvas, x, GUI_STATUS_BAR_Y + 2, width, GUI_STATUS_BAR_WORKAREA_HEIGHT);
|
|
||||||
view_port_draw(view_port, gui->canvas);
|
|
||||||
}
|
|
||||||
ViewPortArray_next(it);
|
|
||||||
}
|
|
||||||
// Draw frame around icons on the right
|
|
||||||
if(right_used) {
|
|
||||||
canvas_frame_set(
|
|
||||||
gui->canvas,
|
|
||||||
GUI_DISPLAY_WIDTH - 3 - right_used,
|
|
||||||
GUI_STATUS_BAR_Y,
|
|
||||||
right_used + 3,
|
|
||||||
GUI_STATUS_BAR_HEIGHT);
|
|
||||||
canvas_set_color(gui->canvas, ColorBlack);
|
|
||||||
canvas_draw_rframe(
|
|
||||||
gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas), 1);
|
|
||||||
canvas_draw_line(
|
|
||||||
gui->canvas,
|
|
||||||
canvas_width(gui->canvas) - 2,
|
|
||||||
1,
|
|
||||||
canvas_width(gui->canvas) - 2,
|
|
||||||
canvas_height(gui->canvas) - 2);
|
|
||||||
canvas_draw_line(
|
|
||||||
gui->canvas,
|
|
||||||
1,
|
|
||||||
canvas_height(gui->canvas) - 2,
|
|
||||||
canvas_width(gui->canvas) - 2,
|
|
||||||
canvas_height(gui->canvas) - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left side
|
|
||||||
x = 2;
|
|
||||||
ViewPortArray_it(it, gui->layers[GuiLayerStatusBarLeft]);
|
|
||||||
while(!ViewPortArray_end_p(it) && (right_used + left_used) < GUI_STATUS_BAR_WIDTH) {
|
|
||||||
ViewPort* view_port = *ViewPortArray_ref(it);
|
|
||||||
if(view_port_is_enabled(view_port)) {
|
|
||||||
width = view_port_get_width(view_port);
|
|
||||||
if(!width) width = 8;
|
|
||||||
// Prepare work area background
|
|
||||||
canvas_frame_set(
|
|
||||||
gui->canvas,
|
|
||||||
x - 1,
|
|
||||||
GUI_STATUS_BAR_Y + 1,
|
|
||||||
width + 2,
|
|
||||||
GUI_STATUS_BAR_WORKAREA_HEIGHT + 2);
|
|
||||||
canvas_set_color(gui->canvas, ColorWhite);
|
|
||||||
canvas_draw_box(
|
|
||||||
gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas));
|
|
||||||
canvas_set_color(gui->canvas, ColorBlack);
|
|
||||||
// ViewPort draw
|
|
||||||
canvas_frame_set(
|
|
||||||
gui->canvas, x, GUI_STATUS_BAR_Y + 2, width, GUI_STATUS_BAR_WORKAREA_HEIGHT);
|
|
||||||
view_port_draw(view_port, gui->canvas);
|
|
||||||
// Recalculate next position
|
|
||||||
left_used += (width + 2);
|
|
||||||
x += (width + 2);
|
|
||||||
}
|
|
||||||
ViewPortArray_next(it);
|
|
||||||
}
|
|
||||||
// Extra notification
|
|
||||||
if(need_attention) {
|
|
||||||
width = icon_get_width(&I_Hidden_window_9x8);
|
|
||||||
// Prepare work area background
|
|
||||||
canvas_frame_set(
|
|
||||||
gui->canvas,
|
|
||||||
x - 1,
|
|
||||||
GUI_STATUS_BAR_Y + 1,
|
|
||||||
width + 2,
|
|
||||||
GUI_STATUS_BAR_WORKAREA_HEIGHT + 2);
|
|
||||||
canvas_set_color(gui->canvas, ColorWhite);
|
|
||||||
canvas_draw_box(gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas));
|
|
||||||
canvas_set_color(gui->canvas, ColorBlack);
|
|
||||||
// Draw Icon
|
|
||||||
canvas_frame_set(
|
|
||||||
gui->canvas, x, GUI_STATUS_BAR_Y + 2, width, GUI_STATUS_BAR_WORKAREA_HEIGHT);
|
|
||||||
canvas_draw_icon(gui->canvas, 0, 0, &I_Hidden_window_9x8);
|
|
||||||
// Recalculate next position
|
|
||||||
left_used += (width + 2);
|
|
||||||
x += (width + 2);
|
|
||||||
}
|
|
||||||
// Draw frame around icons on the left
|
|
||||||
if(left_used) {
|
|
||||||
canvas_frame_set(gui->canvas, 0, 0, left_used + 3, GUI_STATUS_BAR_HEIGHT);
|
|
||||||
canvas_draw_rframe(
|
|
||||||
gui->canvas, 0, 0, canvas_width(gui->canvas), canvas_height(gui->canvas), 1);
|
|
||||||
canvas_draw_line(
|
|
||||||
gui->canvas,
|
|
||||||
canvas_width(gui->canvas) - 2,
|
|
||||||
1,
|
|
||||||
canvas_width(gui->canvas) - 2,
|
|
||||||
canvas_height(gui->canvas) - 2);
|
|
||||||
canvas_draw_line(
|
|
||||||
gui->canvas,
|
|
||||||
1,
|
|
||||||
canvas_height(gui->canvas) - 2,
|
|
||||||
canvas_width(gui->canvas) - 2,
|
|
||||||
canvas_height(gui->canvas) - 2);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool gui_redraw_window(Gui* gui) {
|
|
||||||
ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerWindow]);
|
|
||||||
if (view_port) {
|
|
||||||
lv_obj_set_style_bg_blacken(gui->lvgl_parent);
|
|
||||||
|
|
||||||
lv_obj_t* vertical_container = lv_obj_create(gui->lvgl_parent);
|
|
||||||
lv_obj_set_size(vertical_container, LV_PCT(100), LV_PCT(100));
|
lv_obj_set_size(vertical_container, LV_PCT(100), LV_PCT(100));
|
||||||
lv_obj_set_flex_flow(vertical_container, LV_FLEX_FLOW_COLUMN);
|
lv_obj_set_flex_flow(vertical_container, LV_FLEX_FLOW_COLUMN);
|
||||||
lv_obj_set_style_no_padding(vertical_container);
|
lv_obj_set_style_no_padding(vertical_container);
|
||||||
@ -164,13 +19,51 @@ static bool gui_redraw_window(Gui* gui) {
|
|||||||
|
|
||||||
top_bar(vertical_container);
|
top_bar(vertical_container);
|
||||||
|
|
||||||
lv_obj_t* window_parent = lv_obj_create(vertical_container);
|
lv_obj_t* child_container = lv_obj_create(vertical_container);
|
||||||
lv_obj_set_width(window_parent, LV_PCT(100));
|
lv_obj_set_width(child_container, LV_PCT(100));
|
||||||
lv_obj_set_flex_grow(window_parent, 1);
|
lv_obj_set_flex_grow(child_container, 1);
|
||||||
lv_obj_set_style_no_padding(vertical_container);
|
lv_obj_set_style_no_padding(vertical_container);
|
||||||
lv_obj_set_style_bg_blacken(vertical_container);
|
lv_obj_set_style_bg_blacken(vertical_container);
|
||||||
|
|
||||||
view_port_draw(view_port, window_parent);
|
return child_container;
|
||||||
|
}
|
||||||
|
|
||||||
|
static lv_obj_t* screen_with_top_bar_and_toolbar(lv_obj_t* parent) {
|
||||||
|
lv_obj_set_style_bg_blacken(parent);
|
||||||
|
|
||||||
|
lv_obj_t* vertical_container = lv_obj_create(parent);
|
||||||
|
lv_obj_set_size(vertical_container, LV_PCT(100), LV_PCT(100));
|
||||||
|
lv_obj_set_flex_flow(vertical_container, LV_FLEX_FLOW_COLUMN);
|
||||||
|
lv_obj_set_style_no_padding(vertical_container);
|
||||||
|
lv_obj_set_style_bg_blacken(vertical_container);
|
||||||
|
|
||||||
|
top_bar(vertical_container);
|
||||||
|
|
||||||
|
FURI_RECORD_TRANSACTION(RECORD_LOADER, Loader*, loader, {
|
||||||
|
const AppManifest* manifest = loader_get_current_app(loader);
|
||||||
|
if (manifest != NULL) {
|
||||||
|
toolbar(vertical_container, TOP_BAR_HEIGHT, manifest);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
lv_obj_t* spacer = lv_obj_create(vertical_container);
|
||||||
|
lv_obj_set_size(spacer, 2, 2);
|
||||||
|
lv_obj_set_style_bg_blacken(spacer);
|
||||||
|
|
||||||
|
lv_obj_t* child_container = lv_obj_create(vertical_container);
|
||||||
|
lv_obj_set_width(child_container, LV_PCT(100));
|
||||||
|
lv_obj_set_flex_grow(child_container, 1);
|
||||||
|
lv_obj_set_style_no_padding(vertical_container);
|
||||||
|
lv_obj_set_style_bg_blacken(vertical_container);
|
||||||
|
|
||||||
|
return child_container;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gui_redraw_window(Gui* gui) {
|
||||||
|
ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerWindow]);
|
||||||
|
if (view_port) {
|
||||||
|
lv_obj_t* container = screen_with_top_bar_and_toolbar(gui->lvgl_parent);
|
||||||
|
view_port_draw(view_port, container);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -178,14 +71,14 @@ static bool gui_redraw_window(Gui* gui) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool gui_redraw_desktop(Gui* gui) {
|
static bool gui_redraw_desktop(Gui* gui) {
|
||||||
/*
|
|
||||||
canvas_frame_set(gui->lvgl_parent, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT);
|
|
||||||
ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerDesktop]);
|
ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerDesktop]);
|
||||||
if(view_port) {
|
if (view_port) {
|
||||||
view_port_draw(view_port, gui->lvgl_parent);
|
lv_obj_t* container = screen_with_top_bar(gui->lvgl_parent);
|
||||||
|
view_port_draw(view_port, container);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "no desktop layer found");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -207,12 +100,10 @@ void gui_redraw(Gui* gui) {
|
|||||||
furi_check(lvgl_port_lock(100));
|
furi_check(lvgl_port_lock(100));
|
||||||
lv_obj_clean(gui->lvgl_parent);
|
lv_obj_clean(gui->lvgl_parent);
|
||||||
|
|
||||||
gui_redraw_desktop(gui);
|
|
||||||
if (!gui_redraw_fs(gui)) {
|
if (!gui_redraw_fs(gui)) {
|
||||||
if (!gui_redraw_window(gui)) {
|
if (!gui_redraw_window(gui)) {
|
||||||
gui_redraw_desktop(gui);
|
gui_redraw_desktop(gui);
|
||||||
}
|
}
|
||||||
gui_redraw_status_bar(gui, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lvgl_port_unlock();
|
lvgl_port_unlock();
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
|
#include "apps/services/gui/widgets/widgets.h"
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "gui_i.h"
|
#include "gui_i.h"
|
||||||
#include "view_port_i.h"
|
#include "view_port_i.h"
|
||||||
#include "esp_lvgl_port.h"
|
|
||||||
|
|
||||||
#define TAG "viewport"
|
#define TAG "viewport"
|
||||||
|
|
||||||
@ -90,6 +91,7 @@ void view_port_draw(ViewPort* view_port, lv_obj_t* parent) {
|
|||||||
|
|
||||||
if (view_port->draw_callback) {
|
if (view_port->draw_callback) {
|
||||||
lv_obj_clean(parent);
|
lv_obj_clean(parent);
|
||||||
|
lv_obj_set_style_no_padding(parent);
|
||||||
view_port->draw_callback(parent, view_port->draw_callback_context);
|
view_port->draw_callback(parent, view_port->draw_callback_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
40
components/nanobake/src/apps/services/gui/widgets/toolbar.c
Normal file
40
components/nanobake/src/apps/services/gui/widgets/toolbar.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include "toolbar.h"
|
||||||
|
#include "record.h"
|
||||||
|
#include "apps/services/gui/widgets/widgets.h"
|
||||||
|
#include "apps/services/loader/loader.h"
|
||||||
|
|
||||||
|
static void app_toolbar_close(lv_event_t* event) {
|
||||||
|
FURI_RECORD_TRANSACTION(RECORD_LOADER, Loader*, loader, {
|
||||||
|
loader_stop_app(loader);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
void toolbar(lv_obj_t* parent, lv_coord_t offset_y, const AppManifest* manifest) {
|
||||||
|
lv_obj_t* toolbar = lv_obj_create(parent);
|
||||||
|
lv_obj_set_width(toolbar, LV_PCT(100));
|
||||||
|
lv_obj_set_height(toolbar, TOOLBAR_HEIGHT);
|
||||||
|
lv_obj_set_pos(toolbar, 0, offset_y);
|
||||||
|
lv_obj_set_style_no_padding(toolbar);
|
||||||
|
lv_obj_center(toolbar);
|
||||||
|
lv_obj_set_flex_flow(toolbar, LV_FLEX_FLOW_ROW);
|
||||||
|
|
||||||
|
lv_obj_t* close_button = lv_btn_create(toolbar);
|
||||||
|
lv_obj_set_size(close_button, TOOLBAR_HEIGHT - 4, TOOLBAR_HEIGHT - 4);
|
||||||
|
lv_obj_set_style_no_padding(close_button);
|
||||||
|
lv_obj_add_event_cb(close_button, &app_toolbar_close,LV_EVENT_CLICKED, NULL);
|
||||||
|
lv_obj_t* close_button_image = lv_img_create(close_button);
|
||||||
|
lv_img_set_src(close_button_image, LV_SYMBOL_CLOSE);
|
||||||
|
lv_obj_align(close_button_image, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
|
||||||
|
lv_obj_t* label_container = lv_obj_create(toolbar);
|
||||||
|
lv_obj_set_style_no_padding(label_container);
|
||||||
|
lv_obj_set_height(label_container, LV_PCT(100));
|
||||||
|
lv_obj_set_flex_grow(label_container, 1);
|
||||||
|
|
||||||
|
lv_obj_t* label = lv_label_create(label_container);
|
||||||
|
lv_label_set_text(label, manifest->name);
|
||||||
|
lv_obj_set_style_text_font(label, &lv_font_montserrat_18, 0);
|
||||||
|
lv_obj_set_size(label, LV_PCT(100), TOOLBAR_FONT_HEIGHT);
|
||||||
|
lv_obj_set_pos(label, 0, (TOOLBAR_HEIGHT - TOOLBAR_FONT_HEIGHT - 10) / 2);
|
||||||
|
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
|
}
|
||||||
17
components/nanobake/src/apps/services/gui/widgets/toolbar.h
Normal file
17
components/nanobake/src/apps/services/gui/widgets/toolbar.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lvgl.h"
|
||||||
|
#include "app_manifest.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TOOLBAR_HEIGHT 40
|
||||||
|
#define TOOLBAR_FONT_HEIGHT 18
|
||||||
|
|
||||||
|
void toolbar(lv_obj_t* parent, lv_coord_t offset_y, const AppManifest* manifest);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -22,5 +22,5 @@ void top_bar(lv_obj_t* parent) {
|
|||||||
lv_obj_set_style_bg_blacken(wifi);
|
lv_obj_set_style_bg_blacken(wifi);
|
||||||
lv_obj_set_style_img_recolor(wifi, lv_color_white(), 0);
|
lv_obj_set_style_img_recolor(wifi, lv_color_white(), 0);
|
||||||
lv_obj_set_style_img_recolor_opa(wifi, 255, 0);
|
lv_obj_set_style_img_recolor_opa(wifi, 255, 0);
|
||||||
lv_img_set_src(wifi, "A:/assets/wifi-off.png");
|
lv_img_set_src(wifi, "A:/assets/ic_small_wifi_off.png");
|
||||||
}
|
}
|
||||||
@ -2,7 +2,15 @@
|
|||||||
|
|
||||||
#include "lvgl.h"
|
#include "lvgl.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TOP_BAR_ICON_SIZE 18
|
#define TOP_BAR_ICON_SIZE 18
|
||||||
#define TOP_BAR_HEIGHT (TOP_BAR_ICON_SIZE + 2)
|
#define TOP_BAR_HEIGHT (TOP_BAR_ICON_SIZE + 2)
|
||||||
|
|
||||||
void top_bar(lv_obj_t* parent);
|
void top_bar(lv_obj_t* parent);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,6 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "top_bar.h"
|
#include "top_bar.h"
|
||||||
|
#include "toolbar.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
void lv_obj_set_style_bg_blacken(lv_obj_t* obj);
|
void lv_obj_set_style_bg_blacken(lv_obj_t* obj);
|
||||||
void lv_obj_set_style_no_padding(lv_obj_t* obj);
|
void lv_obj_set_style_no_padding(lv_obj_t* obj);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@ -51,6 +51,15 @@ void loader_stop_app(Loader* loader) {
|
|||||||
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AppManifest* _Nullable loader_get_current_app(Loader* loader) {
|
||||||
|
App* app = loader->app_data.app;
|
||||||
|
if (app != NULL) {
|
||||||
|
return app->manifest;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FuriPubSub* loader_get_pubsub(Loader* loader) {
|
FuriPubSub* loader_get_pubsub(Loader* loader) {
|
||||||
furi_assert(loader);
|
furi_assert(loader);
|
||||||
// it's safe to return pubsub without locking
|
// it's safe to return pubsub without locking
|
||||||
@ -123,6 +132,10 @@ static void loader_start_app_with_manifest(
|
|||||||
const AppManifest* _Nonnull manifest,
|
const AppManifest* _Nonnull manifest,
|
||||||
const char* args
|
const char* args
|
||||||
) {
|
) {
|
||||||
|
if (manifest->type != AppTypeUser && manifest->type != AppTypeSystem) {
|
||||||
|
furi_crash("app type not supported by loader");
|
||||||
|
}
|
||||||
|
|
||||||
App* _Nonnull app = furi_app_alloc(manifest);
|
App* _Nonnull app = furi_app_alloc(manifest);
|
||||||
loader->app_data.app = app;
|
loader->app_data.app = app;
|
||||||
loader->app_data.args = (void*)args;
|
loader->app_data.args = (void*)args;
|
||||||
@ -136,18 +149,9 @@ static void loader_start_app_with_manifest(
|
|||||||
loader->app_data.view_port = view_port;
|
loader->app_data.view_port = view_port;
|
||||||
view_port_draw_callback_set(view_port, manifest->on_show, NULL);
|
view_port_draw_callback_set(view_port, manifest->on_show, NULL);
|
||||||
|
|
||||||
switch (manifest->type) {
|
|
||||||
case AppTypeService:
|
|
||||||
furi_crash("service apps cannot have an on_show implementation");
|
|
||||||
case AppTypeSystem:
|
|
||||||
case AppTypeUser:
|
|
||||||
FURI_RECORD_TRANSACTION(RECORD_GUI, Gui*, gui, {
|
FURI_RECORD_TRANSACTION(RECORD_GUI, Gui*, gui, {
|
||||||
gui_add_view_port(gui, view_port, GuiLayerWindow);
|
gui_add_view_port(gui, view_port, GuiLayerWindow);
|
||||||
})
|
})
|
||||||
break;
|
|
||||||
default:
|
|
||||||
furi_crash("viewport not implemented for app type");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
loader->app_data.view_port = NULL;
|
loader->app_data.view_port = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#include "furi_core.h"
|
#include "furi_core.h"
|
||||||
#include "furi_string.h"
|
#include "furi_string.h"
|
||||||
#include "pubsub.h"
|
#include "pubsub.h"
|
||||||
|
#include "app_manifest.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -47,6 +48,7 @@ void loader_start_app_nonblocking(Loader* loader, const char* id, const char* ar
|
|||||||
|
|
||||||
void loader_stop_app(Loader* loader);
|
void loader_stop_app(Loader* loader);
|
||||||
|
|
||||||
|
const AppManifest* _Nullable loader_get_current_app(Loader* loader);
|
||||||
/**
|
/**
|
||||||
* @brief Start application with GUI error message
|
* @brief Start application with GUI error message
|
||||||
* @param[in] instance loader instance
|
* @param[in] instance loader instance
|
||||||
|
|||||||
@ -8,23 +8,27 @@
|
|||||||
#define TAG "nanobake"
|
#define TAG "nanobake"
|
||||||
|
|
||||||
// System services
|
// System services
|
||||||
extern const AppManifest desktop_app;
|
|
||||||
extern const AppManifest gui_app;
|
extern const AppManifest gui_app;
|
||||||
extern const AppManifest loader_app;
|
extern const AppManifest loader_app;
|
||||||
|
|
||||||
|
// Desktop
|
||||||
|
extern const AppManifest desktop_app;
|
||||||
|
|
||||||
// System apps
|
// System apps
|
||||||
extern const AppManifest system_info_app;
|
extern const AppManifest system_info_app;
|
||||||
|
|
||||||
void start_service(const AppManifest* _Nonnull manifest) {
|
void start_service(const AppManifest* _Nonnull manifest, void* _Nullable context) {
|
||||||
// TODO: keep track of running services
|
UNUSED(context);
|
||||||
FURI_LOG_I(TAG, "Starting service %s", manifest->name);
|
FURI_LOG_I(TAG, "Starting service %s", manifest->name);
|
||||||
|
furi_check(manifest->on_start, "service must define on_start");
|
||||||
manifest->on_start(NULL);
|
manifest->on_start(NULL);
|
||||||
|
// TODO: keep track of running services
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_apps(Config* _Nonnull config) {
|
static void register_apps(Config* _Nonnull config) {
|
||||||
FURI_LOG_I(TAG, "Registering core apps");
|
FURI_LOG_I(TAG, "Registering core apps");
|
||||||
app_manifest_registry_add(&desktop_app);
|
|
||||||
app_manifest_registry_add(&gui_app);
|
app_manifest_registry_add(&gui_app);
|
||||||
|
app_manifest_registry_add(&desktop_app);
|
||||||
app_manifest_registry_add(&loader_app);
|
app_manifest_registry_add(&loader_app);
|
||||||
app_manifest_registry_add(&system_info_app);
|
app_manifest_registry_add(&system_info_app);
|
||||||
|
|
||||||
@ -36,7 +40,13 @@ static void register_apps(Config* _Nonnull config) {
|
|||||||
|
|
||||||
static void start_services() {
|
static void start_services() {
|
||||||
FURI_LOG_I(TAG, "Starting services");
|
FURI_LOG_I(TAG, "Starting services");
|
||||||
app_manifest_registry_for_each_of_type(AppTypeService, start_service);
|
app_manifest_registry_for_each_of_type(AppTypeService, NULL, start_service);
|
||||||
|
FURI_LOG_I(TAG, "Startup complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_desktop() {
|
||||||
|
FURI_LOG_I(TAG, "Starting desktop");
|
||||||
|
desktop_app.on_start(NULL);
|
||||||
FURI_LOG_I(TAG, "Startup complete");
|
FURI_LOG_I(TAG, "Startup complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,4 +61,5 @@ __attribute__((unused)) extern void nanobake_start(Config* _Nonnull config) {
|
|||||||
register_apps(config);
|
register_apps(config);
|
||||||
|
|
||||||
start_services();
|
start_services();
|
||||||
|
start_desktop();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,6 @@
|
|||||||
#include "apps/services/gui/gui.h"
|
#include "apps/services/gui/gui.h"
|
||||||
#include "apps/services/loader/loader.h"
|
#include "apps/services/loader/loader.h"
|
||||||
|
|
||||||
static void on_button_click(lv_event_t _Nonnull* event) {
|
|
||||||
UNUSED(event);
|
|
||||||
|
|
||||||
FURI_RECORD_TRANSACTION(RECORD_LOADER, Loader*, loader, {
|
|
||||||
loader_start_app_nonblocking(loader, "systeminfo", NULL);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
static void app_show(lv_obj_t* parent, void* context) {
|
static void app_show(lv_obj_t* parent, void* context) {
|
||||||
UNUSED(context);
|
UNUSED(context);
|
||||||
|
|
||||||
@ -19,13 +11,7 @@ static void app_show(lv_obj_t* parent, void* context) {
|
|||||||
lv_obj_set_width(label, 200);
|
lv_obj_set_width(label, 200);
|
||||||
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
|
||||||
lv_label_set_text(label, "Hello, world!");
|
lv_label_set_text(label, "Hello, world!");
|
||||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, -30);
|
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
|
||||||
lv_obj_t* btn = lv_btn_create(parent);
|
|
||||||
label = lv_label_create(btn);
|
|
||||||
lv_label_set_text_static(label, "System Info");
|
|
||||||
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 30);
|
|
||||||
lv_obj_add_event_cb(btn, on_button_click, LV_EVENT_CLICKED, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppManifest hello_world_app = {
|
const AppManifest hello_world_app = {
|
||||||
|
|||||||
@ -20,11 +20,11 @@ __attribute__((unused)) void app_main(void) {
|
|||||||
|
|
||||||
nanobake_start(&config);
|
nanobake_start(&config);
|
||||||
|
|
||||||
FURI_RECORD_TRANSACTION(RECORD_LOADER, Loader*, loader, {
|
// FURI_RECORD_TRANSACTION(RECORD_LOADER, Loader*, loader, {
|
||||||
FuriString* error_message = furi_string_alloc();
|
// FuriString* error_message = furi_string_alloc();
|
||||||
if (loader_start_app(loader, hello_world_app.id, NULL, error_message) != LoaderStatusOk) {
|
// if (loader_start_app(loader, hello_world_app.id, NULL, error_message) != LoaderStatusOk) {
|
||||||
FURI_LOG_E(hello_world_app.id, "%s\r\n", furi_string_get_cstr(error_message));
|
// FURI_LOG_E(hello_world_app.id, "%s\r\n", furi_string_get_cstr(error_message));
|
||||||
}
|
// }
|
||||||
furi_string_free(error_message);
|
// furi_string_free(error_message);
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,13 @@
|
|||||||
CONFIG_IDF_TARGET="esp32"
|
CONFIG_IDF_TARGET="esp32"
|
||||||
CONFIG_LV_COLOR_16_SWAP=y
|
CONFIG_LV_COLOR_16_SWAP=y
|
||||||
CONFIG_LV_USE_USER_DATA=y
|
CONFIG_LV_USE_USER_DATA=y
|
||||||
|
CONFIG_LV_USE_FS_STDIO=y
|
||||||
|
CONFIG_LV_FS_STDIO_LETTER=65
|
||||||
|
CONFIG_LV_FS_STDIO_PATH=""
|
||||||
|
CONFIG_LV_FS_STDIO_CACHE_SIZE=4096
|
||||||
|
CONFIG_LV_USE_PNG=y
|
||||||
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2
|
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user