mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-17 02:45:05 +00:00
Notes revamped, icon fixes, Tab5 fixes (#682)
This commit is contained in:
parent
7413888cdf
commit
d64eac64f0
@ -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
|
||||
|
||||
Binary file not shown.
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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[];
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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]);
|
||||
|
||||
@ -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
|
||||
// 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);
|
||||
break;
|
||||
case 1: // Save
|
||||
if (!ctx->filePath.empty()) {
|
||||
lvgl_lock();
|
||||
}
|
||||
|
||||
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);
|
||||
lvgl_unlock();
|
||||
saveFile(ctx, ctx->filePath);
|
||||
}
|
||||
break;
|
||||
case 2: // Save as...
|
||||
lvgl_lock();
|
||||
|
||||
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);
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user