Notes revamped, icon fixes, Tab5 fixes (#682)

This commit is contained in:
Ken Van Hoeylandt 2026-10-09 08:49:25 +02:00 committed by GitHub
parent 7413888cdf
commit d64eac64f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 151 additions and 57 deletions

View File

@ -21,25 +21,38 @@ check e668
circle ef4a
close e5cd
cloud f15c
content_copy e14d
content_cut e14e
content_paste e14f
create_new_folder e2cc
delete e92e
deployed_code f720
description e873
devices e326
display_settings eb97
download f090
draft e66d
edit f097
edit_note e745
eject e8fb
electric_bolt ec1c
folder e2c7
folder_open e2c8
forum e8af
gamepad e30f
hard_disk f3da
help e8fd
hub e9f4
image e3f4
info e88e
keyboard_alt f028
keyboard_arrow_up e316
language ea07
lightbulb e90f
lightstrip fff75
link e250
lists e9b9
location_off e0c7
location_on f1db
logo_dev ead6
mail e159
@ -54,11 +67,16 @@ network_wifi_2_bar ebd6
network_wifi_3_bar ebe1
note_add e89c
palette e40a
phone_android f2db
play_arrow e037
power_settings_new f8c7
refresh e5d5
save e161
save_as eb60
sd_card e623
sd_card_alert f057
search ef7a
select_window_2 f4c8
settings e8b8
signal_wifi_0_bar f0b0
signal_wifi_4_bar f065

View File

@ -48,8 +48,8 @@ void tab5_create_devices_v2(Device* i2c0) {
.ldo_voltage_mv = 2500,
.dsi_bus_id = 0,
.num_data_lanes = 2,
.lane_bit_rate_mbps = 965, // ST7123 lane bitrate per M5Stack BSP
.dpi_clock_freq_mhz = 70,
.lane_bit_rate_mbps = 1040, // Deviates from M5Stack BSP to fix flickering
.dpi_clock_freq_mhz = 80,
.hsync_pulse_width = 2,
.hsync_back_porch = 40,
.hsync_front_porch = 40,

View File

@ -49,8 +49,8 @@ void tab5_create_devices_v3(Device* i2c0) {
.ldo_voltage_mv = 2500,
.dsi_bus_id = 0,
.num_data_lanes = 2,
.lane_bit_rate_mbps = 965, // ST7121 lane bitrate per M5Stack BSP (same as ST7123)
.dpi_clock_freq_mhz = 70,
.lane_bit_rate_mbps = 1040, // Deviates from M5Stack BSP to fix flickering
.dpi_clock_freq_mhz = 80,
.hsync_pulse_width = 2,
.hsync_back_porch = 40,
.hsync_front_porch = 40,

View File

@ -194,6 +194,10 @@ shared_symbol_code_point_names = [
"play_arrow",
"eject",
"create_new_folder",
# Notes app
"save",
"save_as",
"folder_open",
]
# Get more from https://fonts.google.com/icons?icon.set=Material+Symbols&icon.style=Rounded

View File

@ -9,7 +9,7 @@ extern "C" {
#endif
/** Changes whenever the icon TTF subset, its codepoints file or the icon name lists change */
#define LVGL_ICON_FONT_VERSION 0xB2450B17u
#define LVGL_ICON_FONT_VERSION 0xD5578751u
// Icon names per icon font, resolved through the .codepoints file next to the TTF
extern const char* const lvgl_icon_shared_names[];

View File

@ -66,3 +66,6 @@
#define LVGL_ICON_SHARED_PLAY_ARROW "\xEE\x80\xB7"
#define LVGL_ICON_SHARED_EJECT "\xEE\xA3\xBB"
#define LVGL_ICON_SHARED_CREATE_NEW_FOLDER "\xEE\x8B\x8C"
#define LVGL_ICON_SHARED_SAVE "\xEE\x85\xA1"
#define LVGL_ICON_SHARED_SAVE_AS "\xEE\xAD\xA0"
#define LVGL_ICON_SHARED_FOLDER_OPEN "\xEE\x8B\x88"

View File

@ -68,6 +68,9 @@ const char* const lvgl_icon_shared_names[] = {
"play_arrow",
"eject",
"create_new_folder",
"save",
"save_as",
"folder_open",
};
const size_t lvgl_icon_shared_name_count = sizeof(lvgl_icon_shared_names) / sizeof(lvgl_icon_shared_names[0]);

View File

@ -15,7 +15,13 @@
#include <lvgl_window_manager/window_manager.h>
#include <lvgl.h>
#include <lvgl/fonts.h>
#include <lvgl/grid_navigation.h>
#include <lvgl/icons/shared.h>
#include <lvgl/insets.h>
#include <lvgl/lvgl.h>
#include <lvgl/widgets/card.h>
#include <lvgl/widgets/icon_button.h>
#include <lvgl/widgets/toolbar.h>
#include <tactility/check.h>
#include <tactility/log.h>
@ -33,7 +39,9 @@ struct Context {
TaskEventGroup* eventGroup = nullptr;
lv_obj_t* uiCurrentFileName = nullptr;
lv_obj_t* uiDropDownMenu = nullptr;
lv_obj_t* uiToolbar = nullptr;
lv_obj_t* uiOverflowButton = nullptr;
lv_obj_t* uiOverlay = nullptr;
lv_obj_t* uiNoteText = nullptr;
std::string filePath;
@ -77,50 +85,100 @@ bool saveFile(Context* ctx, const std::string& path) {
return result;
}
void appNotesEventCb(lv_event_t* e) {
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t* obj = lv_event_get_target_obj(e);
void hideOverlay(Context* ctx) {
if (lv_obj_is_hidden(ctx->uiOverlay)) {
return;
}
lv_obj_set_hidden(ctx->uiOverlay, true);
if (code == LV_EVENT_VALUE_CHANGED) {
if (obj == ctx->uiDropDownMenu) {
switch (lv_dropdown_get_selected(obj)) {
case 0: // New
resetFileContent(ctx);
break;
case 1: // Save
if (!ctx->filePath.empty()) {
lvgl_lock();
ctx->saveBuffer = lv_textarea_get_text(ctx->uiNoteText);
lvgl_unlock();
saveFile(ctx, ctx->filePath);
}
break;
case 2: // Save as...
lvgl_lock();
ctx->saveBuffer = lv_textarea_get_text(ctx->uiNoteText);
lvgl_unlock();
ctx->saveFileLaunchId = fileselection::startForExistingOrNewFile(ctx->appInstanceId, ctx->saveResultStream, ctx->saveResultBuffer, sizeof(ctx->saveResultBuffer), ctx->eventGroup);
LOG_I(TAG, "launched with id %u", ctx->saveFileLaunchId);
break;
case 3: // Load
ctx->loadFileLaunchId = fileselection::startForExistingFile(ctx->appInstanceId, ctx->loadResultStream, ctx->loadResultBuffer, sizeof(ctx->loadResultBuffer), ctx->eventGroup);
LOG_I(TAG, "launched with id %u", ctx->loadFileLaunchId);
break;
}
} else {
auto* cont = lv_event_get_current_target_obj(e);
if (obj == cont) return;
if (lv_obj_get_child(cont, 1)) {
ctx->saveFileLaunchId = fileselection::startForExistingOrNewFile(ctx->appInstanceId, ctx->saveResultStream, ctx->saveResultBuffer, sizeof(ctx->saveResultBuffer), ctx->eventGroup);
LOG_I(TAG, "launched with id %u", ctx->saveFileLaunchId);
} else { //Reset
resetFileContent(ctx);
}
// Keys continue on the button that opened the overlay
lv_group_t* group = lv_group_get_default();
if (group != nullptr && lv_group_get_focused(group) == ctx->uiOverlay) {
lv_group_focus_obj(ctx->uiToolbar);
lv_gridnav_set_focused(ctx->uiToolbar, ctx->uiOverflowButton, LV_ANIM_OFF);
}
}
void onNewPressed(lv_event_t* e) {
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
hideOverlay(ctx);
resetFileContent(ctx);
}
void onSavePressed(lv_event_t* e) {
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
hideOverlay(ctx);
ctx->saveBuffer = lv_textarea_get_text(ctx->uiNoteText);
saveFile(ctx, ctx->filePath);
}
void onSaveAsPressed(lv_event_t* e) {
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
hideOverlay(ctx);
ctx->saveBuffer = lv_textarea_get_text(ctx->uiNoteText);
ctx->saveFileLaunchId = fileselection::startForExistingOrNewFile(ctx->appInstanceId, ctx->saveResultStream, ctx->saveResultBuffer, sizeof(ctx->saveResultBuffer), ctx->eventGroup);
LOG_I(TAG, "launched with id %u", ctx->saveFileLaunchId);
}
void onOpenPressed(lv_event_t* e) {
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
hideOverlay(ctx);
ctx->loadFileLaunchId = fileselection::startForExistingFile(ctx->appInstanceId, ctx->loadResultStream, ctx->loadResultBuffer, sizeof(ctx->loadResultBuffer), ctx->eventGroup);
LOG_I(TAG, "launched with id %u", ctx->loadFileLaunchId);
}
void addOverlayButton(Context* ctx, const char* icon, lv_event_cb_t callback) {
auto* button = lvgl_icon_button_create(ctx->uiOverlay);
auto* label = lv_label_create(button);
lv_obj_set_style_text_font(label, lvgl_get_shared_icon_default_font(), LV_STATE_DEFAULT);
lv_label_set_text(label, icon);
lv_obj_add_event_cb(button, callback, LV_EVENT_SHORT_CLICKED, ctx);
}
void showOverlay(Context* ctx) {
lv_obj_clean(ctx->uiOverlay);
addOverlayButton(ctx, LVGL_ICON_SHARED_NOTE_ADD, onNewPressed);
// Saving needs a file, which "save as" picks
if (!ctx->filePath.empty()) {
addOverlayButton(ctx, LVGL_ICON_SHARED_SAVE, onSavePressed);
}
addOverlayButton(ctx, LVGL_ICON_SHARED_SAVE_AS, onSaveAsPressed);
addOverlayButton(ctx, LVGL_ICON_SHARED_FOLDER_OPEN, onOpenPressed);
lv_obj_set_hidden(ctx->uiOverlay, false);
lv_obj_align_to(ctx->uiOverlay, ctx->uiToolbar, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
lv_group_t* group = lv_group_get_default();
if (group != nullptr) {
lv_group_focus_obj(ctx->uiOverlay);
lv_gridnav_set_focused(ctx->uiOverlay, lv_obj_get_child(ctx->uiOverlay, 0), LV_ANIM_OFF);
// Touch shows no selection, until a key moves the focus
lv_indev_t* indev = lv_indev_active();
if (indev != nullptr && lv_indev_get_type(indev) == LV_INDEV_TYPE_POINTER) {
lvgl_focus_hide_key_selection(group);
}
}
}
void onOverflowPressed(lv_event_t* e) {
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
if (lv_obj_is_hidden(ctx->uiOverlay)) {
showOverlay(ctx);
} else {
hideOverlay(ctx);
}
}
void onOverlayKey(lv_event_t* e) {
if (lv_event_get_key(e) == LV_KEY_ESC) {
hideOverlay(static_cast<Context*>(lv_event_get_user_data(e)));
}
}
void onNoteTextPressed(lv_event_t* e) {
hideOverlay(static_cast<Context*>(lv_event_get_user_data(e)));
}
void createWidgets(lv_obj_t* parent, void* userData) {
auto* ctx = static_cast<Context*>(userData);
@ -128,16 +186,10 @@ void createWidgets(lv_obj_t* parent, void* userData) {
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
lv_obj_t* toolbar = lvgl_toolbar_create(parent, "Notes");
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
ctx->uiDropDownMenu = lv_dropdown_create(toolbar);
lv_dropdown_set_options(ctx->uiDropDownMenu, LV_SYMBOL_FILE " New File\n" LV_SYMBOL_SAVE " Save\n" LV_SYMBOL_SAVE " Save As...\n" LV_SYMBOL_DIRECTORY " Open File");
lv_dropdown_set_text(ctx->uiDropDownMenu, "Menu");
lv_dropdown_set_symbol(ctx->uiDropDownMenu, LV_SYMBOL_DOWN);
lv_dropdown_set_selected_highlight(ctx->uiDropDownMenu, false);
lv_obj_align(ctx->uiDropDownMenu, LV_ALIGN_RIGHT_MID, 0, 0);
lv_obj_add_event_cb(ctx->uiDropDownMenu, appNotesEventCb, LV_EVENT_VALUE_CHANGED, ctx);
ctx->uiToolbar = lvgl_toolbar_create(parent, "Notes");
lv_obj_align(ctx->uiToolbar, LV_ALIGN_TOP_MID, 0, 0);
ctx->uiOverflowButton = lvgl_toolbar_add_text_button_action(ctx->uiToolbar, LVGL_ICON_SHARED_MORE_VERT, onOverflowPressed, ctx);
lv_obj_set_style_text_font(ctx->uiOverflowButton, lvgl_get_shared_icon_default_font(), LV_STATE_DEFAULT);
lv_obj_t* wrapper = lv_obj_create(parent);
lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN);
@ -158,17 +210,18 @@ void createWidgets(lv_obj_t* parent, void* userData) {
lv_obj_set_style_bg_color(ctx->uiNoteText, lv_color_hex(0x262626), LV_PART_MAIN);
}
lv_textarea_set_placeholder_text(ctx->uiNoteText, "Notes...");
lv_obj_add_event_cb(ctx->uiNoteText, onNoteTextPressed, LV_EVENT_PRESSED, ctx);
lv_obj_t* footer = lv_obj_create(wrapper);
lv_obj_set_flex_flow(footer, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(footer, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
// Shows the screen background
lv_obj_set_style_bg_opa(footer, LV_OPA_TRANSP, LV_PART_MAIN);
if (lv_display_get_color_format(lv_obj_get_display(parent)) == LV_COLOR_FORMAT_L8) {
lv_obj_set_style_bg_color(footer, lv_color_hex(0xEEEEEE), LV_PART_MAIN);
lv_obj_set_style_border_width(footer, 1, LV_PART_MAIN);
lv_obj_set_style_border_color(footer, lv_theme_get_color_secondary(footer), LV_PART_MAIN);
lv_obj_set_style_border_side(footer, LV_BORDER_SIDE_TOP, LV_PART_MAIN);
} else {
lv_obj_set_style_bg_color(footer, lv_color_hex(0x262626), LV_PART_MAIN);
lv_obj_set_style_border_width(footer, 0, LV_PART_MAIN);
}
lv_obj_set_width(footer, LV_PCT(100));
@ -183,6 +236,19 @@ void createWidgets(lv_obj_t* parent, void* userData) {
lv_label_set_text(ctx->uiCurrentFileName, "Untitled");
lv_obj_align(ctx->uiCurrentFileName, LV_ALIGN_CENTER, 0, 0);
// Floating over the text area, below the toolbar
ctx->uiOverlay = lvgl_card_create(parent);
lv_obj_set_floating(ctx->uiOverlay, true);
lv_obj_set_size(ctx->uiOverlay, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_flex_flow(ctx->uiOverlay, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(ctx->uiOverlay, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_scrollable(ctx->uiOverlay, false);
lvgl_obj_add_edge_padding(ctx->uiOverlay);
// The arrow keys move between the overlay's buttons as one row
lvgl_grid_navigation_add(ctx->uiOverlay);
lv_obj_add_event_cb(ctx->uiOverlay, onOverlayKey, LV_EVENT_KEY, ctx);
lv_obj_set_hidden(ctx->uiOverlay, true);
if (!ctx->filePath.empty()) {
openFile(ctx, ctx->filePath);
}