diff --git a/Devices/waveshare-esp32-s3-rlcd/device.properties b/Devices/waveshare-esp32-s3-rlcd/device.properties index bd460cbb..65c8ca7f 100644 --- a/Devices/waveshare-esp32-s3-rlcd/device.properties +++ b/Devices/waveshare-esp32-s3-rlcd/device.properties @@ -22,5 +22,5 @@ display.dpi=120 lvgl.colorDepth=16 lvgl.uiDensity=compact -lvgl.fontSize=18 +lvgl.fontSize=20 lvgl.theme=DefaultDark diff --git a/Modules/lvgl-module/include/tactility/lvgl_fonts.h b/Modules/lvgl-module/include/tactility/lvgl_fonts.h index 2420235b..9cdbcdcc 100644 --- a/Modules/lvgl-module/include/tactility/lvgl_fonts.h +++ b/Modules/lvgl-module/include/tactility/lvgl_fonts.h @@ -1,31 +1,25 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once - #include #include - #ifdef __cplusplus extern "C" { #endif - enum LvglFontSize { FONT_SIZE_SMALL, FONT_SIZE_DEFAULT, FONT_SIZE_LARGE, }; - const lv_font_t* lvgl_get_shared_icon_font(); uint32_t lvgl_get_shared_icon_font_height(); - const lv_font_t* lvgl_get_text_font(enum LvglFontSize font_size); uint32_t lvgl_get_text_font_height(enum LvglFontSize font_size); - const lv_font_t* lvgl_get_launcher_icon_font(); uint32_t lvgl_get_launcher_icon_font_height(); - const lv_font_t* lvgl_get_statusbar_icon_font(); uint32_t lvgl_get_statusbar_icon_font_height(); - +void lvgl_set_runtime_font_size(uint8_t font_size); +uint8_t lvgl_get_runtime_font_size(); #ifdef __cplusplus } #endif diff --git a/Modules/lvgl-module/source/lvgl_fonts.c b/Modules/lvgl-module/source/lvgl_fonts.c index aab97211..b164d648 100644 --- a/Modules/lvgl-module/source/lvgl_fonts.c +++ b/Modules/lvgl-module/source/lvgl_fonts.c @@ -4,7 +4,6 @@ #include // The preprocessor definitions that are used below are defined in the CMakeLists.txt from this module. - extern const lv_font_t TT_LVGL_TEXT_FONT_SMALL_SYMBOL; extern const lv_font_t TT_LVGL_TEXT_FONT_DEFAULT_SYMBOL; extern const lv_font_t TT_LVGL_TEXT_FONT_LARGE_SYMBOL; @@ -13,7 +12,84 @@ extern const lv_font_t TT_LVGL_LAUNCHER_FONT_ICON_SYMBOL; extern const lv_font_t TT_LVGL_STATUSBAR_FONT_ICON_SYMBOL; extern const lv_font_t TT_LVGL_SHARED_FONT_ICON_SYMBOL; +// All compiled-in Montserrat fonts for runtime switching (extern from lvgl lib) +#ifdef CONFIG_LV_FONT_MONTSERRAT_14 +extern const lv_font_t lv_font_montserrat_14; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_16 +extern const lv_font_t lv_font_montserrat_16; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_18 +extern const lv_font_t lv_font_montserrat_18; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_20 +extern const lv_font_t lv_font_montserrat_20; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_24 +extern const lv_font_t lv_font_montserrat_24; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_26 +extern const lv_font_t lv_font_montserrat_26; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_28 +extern const lv_font_t lv_font_montserrat_28; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_30 +extern const lv_font_t lv_font_montserrat_30; +#endif + +// Runtime font size override - 0 = use compile-time default, otherwise explicit point size +static uint8_t g_runtime_font_size = 0; + +void lvgl_set_runtime_font_size(uint8_t font_size) { + g_runtime_font_size = font_size; +} + +uint8_t lvgl_get_runtime_font_size() { + return g_runtime_font_size; +} + +static const lv_font_t* get_font_for_size(uint8_t size) { + // Map requested size to closest available compiled font + if (size == 0) return NULL; // use compile-time +#ifdef CONFIG_LV_FONT_MONTSERRAT_14 + if (size <= 14) return &lv_font_montserrat_14; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_16 + if (size <= 16) return &lv_font_montserrat_16; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_18 + if (size <= 18) return &lv_font_montserrat_18; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_20 + if (size <= 20) return &lv_font_montserrat_20; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_24 + if (size <= 24) return &lv_font_montserrat_24; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_26 + if (size <= 26) return &lv_font_montserrat_26; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_28 + if (size <= 28) return &lv_font_montserrat_28; +#endif +#ifdef CONFIG_LV_FONT_MONTSERRAT_30 + return &lv_font_montserrat_30; +#else + return NULL; +#endif +} + uint32_t lvgl_get_text_font_height(enum LvglFontSize font_size) { + if (g_runtime_font_size != 0) { + // Scale heights: small = runtime-4, default = runtime, large = runtime+6 + switch (font_size) { + case FONT_SIZE_SMALL: return g_runtime_font_size > 4 ? g_runtime_font_size - 4 : g_runtime_font_size; + case FONT_SIZE_DEFAULT: return g_runtime_font_size; + case FONT_SIZE_LARGE: return g_runtime_font_size + 6; + default: check(false); + } + } switch (font_size) { case FONT_SIZE_SMALL: return TT_LVGL_TEXT_FONT_SMALL_SIZE; case FONT_SIZE_DEFAULT: return TT_LVGL_TEXT_FONT_DEFAULT_SIZE; @@ -21,23 +97,30 @@ uint32_t lvgl_get_text_font_height(enum LvglFontSize font_size) { default: check(false); } } + const lv_font_t* lvgl_get_text_font(enum LvglFontSize font_size) { + if (g_runtime_font_size != 0) { + uint8_t target_size; + switch (font_size) { + case FONT_SIZE_SMALL: target_size = g_runtime_font_size > 4 ? g_runtime_font_size - 4 : g_runtime_font_size; break; + case FONT_SIZE_DEFAULT: target_size = g_runtime_font_size; break; + case FONT_SIZE_LARGE: target_size = g_runtime_font_size + 6; break; + default: check(false); return &TT_LVGL_TEXT_FONT_DEFAULT_SYMBOL; + } + const lv_font_t* f = get_font_for_size(target_size); + if (f != NULL) return f; + } switch (font_size) { case FONT_SIZE_SMALL: return &TT_LVGL_TEXT_FONT_SMALL_SYMBOL; case FONT_SIZE_DEFAULT: return &TT_LVGL_TEXT_FONT_DEFAULT_SYMBOL; case FONT_SIZE_LARGE: return &TT_LVGL_TEXT_FONT_LARGE_SYMBOL; - default: check(false); + default: check(false); return &TT_LVGL_TEXT_FONT_DEFAULT_SYMBOL; } } uint32_t lvgl_get_shared_icon_font_height() { return TT_LVGL_SHARED_FONT_ICON_SIZE; } - const lv_font_t* lvgl_get_shared_icon_font() { return &TT_LVGL_SHARED_FONT_ICON_SYMBOL; } - uint32_t lvgl_get_launcher_icon_font_height() { return TT_LVGL_LAUNCHER_FONT_ICON_SIZE; } - const lv_font_t* lvgl_get_launcher_icon_font() { return &TT_LVGL_LAUNCHER_FONT_ICON_SYMBOL; } - uint32_t lvgl_get_statusbar_icon_font_height() { return TT_LVGL_STATUSBAR_FONT_ICON_SIZE; } - const lv_font_t* lvgl_get_statusbar_icon_font() { return &TT_LVGL_STATUSBAR_FONT_ICON_SYMBOL; } diff --git a/Tactility/Include/Tactility/settings/DisplaySettings.h b/Tactility/Include/Tactility/settings/DisplaySettings.h index 9d879683..a5cff52c 100644 --- a/Tactility/Include/Tactility/settings/DisplaySettings.h +++ b/Tactility/Include/Tactility/settings/DisplaySettings.h @@ -26,6 +26,7 @@ struct DisplaySettings { bool disableScreensaverWhenCharging = false; bool invertColor = false; uint8_t monochromeThreshold = 60; + uint8_t fontSize = 0; // 0 = use compile-time default, otherwise 14/16/18/20/24/28 }; lv_display_rotation_t toLvglDisplayRotation(Orientation orientation); bool load(DisplaySettings& settings); diff --git a/Tactility/Source/app/display/Display.cpp b/Tactility/Source/app/display/Display.cpp index 58c3416a..3c66a589 100644 --- a/Tactility/Source/app/display/Display.cpp +++ b/Tactility/Source/app/display/Display.cpp @@ -1,11 +1,11 @@ #include #include +#include #ifdef ESP_PLATFORM #include #endif - #include #include #include @@ -156,6 +156,21 @@ class DisplayApp final : public App { } } + static void onFontSizeChanged(lv_event_t* event) { + auto* app = static_cast(lv_event_get_user_data(event)); + auto* dropdown = static_cast(lv_event_get_target(event)); + uint32_t idx = lv_dropdown_get_selected(dropdown); + // Map dropdown index to font size: 0=default (compile-time), 1=14, 2=16, 3=18, 4=20, 5=24, 6=28 + static const uint8_t font_sizes[] = {0, 14, 16, 18, 20, 24, 28}; + if (idx < sizeof(font_sizes)/sizeof(font_sizes[0])) { + uint8_t new_size = font_sizes[idx]; + app->displaySettings.fontSize = new_size; + app->displaySettingsUpdated = true; + // Apply immediately for next screens - current screen keeps old fonts until reopen + lvgl_set_runtime_font_size(new_size); + } + } + static void onTimeoutChanged(lv_event_t* event) { auto* app = static_cast(lv_event_get_user_data(event)); auto* dropdown = static_cast(lv_event_get_target(event)); @@ -427,6 +442,35 @@ public: } } + // Runtime font size selector + { + auto* font_wrapper = lv_obj_create(main_wrapper); + lv_obj_set_size(font_wrapper, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_style_pad_all(font_wrapper, 0, LV_STATE_DEFAULT); + lv_obj_set_style_border_width(font_wrapper, 0, LV_STATE_DEFAULT); + + auto* font_label = lv_label_create(font_wrapper); + lv_label_set_text(font_label, "Font size"); + lv_obj_align(font_label, LV_ALIGN_LEFT_MID, 0, 0); + + auto* font_dropdown = lv_dropdown_create(font_wrapper); + lv_dropdown_set_options(font_dropdown, "Default\n14 Small\n16\n18\n20\n24 Next\n28 Large"); + lv_obj_align(font_dropdown, LV_ALIGN_RIGHT_MID, 0, 0); + lv_obj_add_event_cb(font_dropdown, onFontSizeChanged, LV_EVENT_VALUE_CHANGED, this); + + // Map current fontSize to dropdown index + uint8_t fs = displaySettings.fontSize; + uint32_t idx = 0; + if (fs == 14) idx = 1; + else if (fs == 16) idx = 2; + else if (fs == 18) idx = 3; + else if (fs == 20) idx = 4; + else if (fs == 24) idx = 5; + else if (fs == 28) idx = 6; + else idx = 0; // 0 = compile-time default (currently 20) + lv_dropdown_set_selected(font_dropdown, idx); + } + if (hasCalibratableTouchDevice()) { auto* calibrate_wrapper = lv_obj_create(main_wrapper); lv_obj_set_size(calibrate_wrapper, LV_PCT(100), LV_SIZE_CONTENT); diff --git a/Tactility/Source/lvgl/Lvgl.cpp b/Tactility/Source/lvgl/Lvgl.cpp index 72453417..edd62861 100644 --- a/Tactility/Source/lvgl/Lvgl.cpp +++ b/Tactility/Source/lvgl/Lvgl.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -44,6 +45,11 @@ void attachDevices() { if (rotation != lv_display_get_rotation(lvgl_display)) { lv_display_set_rotation(lvgl_display, rotation); } + // Apply runtime font size (0 = compile-time default) + if (settings.fontSize != 0) { + lvgl_set_runtime_font_size(settings.fontSize); + LOGGER.info("Runtime font size set to {}", settings.fontSize); + } // Apply invert setting if display supports it if (display->supportsInvertColor()) { display->setInvertColor(settings.invertColor); diff --git a/Tactility/Source/settings/DisplaySettings.cpp b/Tactility/Source/settings/DisplaySettings.cpp index 7c371a44..db1817c9 100644 --- a/Tactility/Source/settings/DisplaySettings.cpp +++ b/Tactility/Source/settings/DisplaySettings.cpp @@ -25,6 +25,7 @@ constexpr auto* SETTINGS_KEY_SCREENSAVER_TYPE = "screensaverType"; constexpr auto* SETTINGS_KEY_DISABLE_WHEN_CHARGING = "disableScreensaverWhenCharging"; constexpr auto* SETTINGS_KEY_INVERT_COLOR = "invertColor"; constexpr auto* SETTINGS_KEY_MONO_THRESHOLD = "monochromeThreshold"; +constexpr auto* SETTINGS_KEY_FONT_SIZE = "fontSize"; static Orientation getDefaultOrientation() { auto* display = lv_display_get_default(); @@ -187,6 +188,14 @@ bool load(DisplaySettings& settings) { if (mono_thresh > 255) mono_thresh = 255; } + int font_size = 0; + auto font_entry = map.find(SETTINGS_KEY_FONT_SIZE); + if (font_entry != map.end()) { + font_size = atoi(font_entry->second.c_str()); + if (font_size < 0) font_size = 0; + if (font_size > 36) font_size = 36; + } + settings.orientation = orientation; settings.gammaCurve = gamma_curve; settings.backlightDuty = backlight_duty; @@ -196,6 +205,7 @@ bool load(DisplaySettings& settings) { settings.disableScreensaverWhenCharging = disable_when_charging; settings.invertColor = invert_color; settings.monochromeThreshold = static_cast(mono_thresh); + settings.fontSize = static_cast(font_size); return true; } @@ -210,7 +220,8 @@ DisplaySettings getDefault() { .screensaverType = ScreensaverType::BouncingBalls, .disableScreensaverWhenCharging = false, .invertColor = true, - .monochromeThreshold = 60 + .monochromeThreshold = 60, + .fontSize = 0 }; } @@ -233,6 +244,7 @@ bool save(const DisplaySettings& settings) { map[SETTINGS_KEY_DISABLE_WHEN_CHARGING] = settings.disableScreensaverWhenCharging ? "1" : "0"; map[SETTINGS_KEY_INVERT_COLOR] = settings.invertColor ? "1" : "0"; map[SETTINGS_KEY_MONO_THRESHOLD] = std::to_string(settings.monochromeThreshold); + map[SETTINGS_KEY_FONT_SIZE] = std::to_string(settings.fontSize); auto settings_path = getSettingsFilePath(); if (!file::findOrCreateParentDirectory(settings_path, 0755)) { return false; diff --git a/device.py b/device.py index df1698d3..f2f5e9fe 100644 --- a/device.py +++ b/device.py @@ -304,6 +304,25 @@ def write_lvgl_variables(output_file, device_properties: dict): output_file.write("CONFIG_TT_LVGL_STATUSBAR_ICON_SIZE=20\n") output_file.write("CONFIG_TT_LVGL_LAUNCHER_ICON_SIZE=48\n") output_file.write("CONFIG_TT_LVGL_SHARED_ICON_SIZE=20\n") + elif font_height <= 20: + # Exact +~14% over 18 bucket for RLCD - requested "increase another 15%" + output_file.write("CONFIG_LV_FONT_MONTSERRAT_16=y\n") + output_file.write("CONFIG_LV_FONT_MONTSERRAT_20=y\n") + output_file.write("CONFIG_LV_FONT_MONTSERRAT_26=y\n") + output_file.write("CONFIG_LV_FONT_DEFAULT_MONTSERRAT_20=y\n") + output_file.write("CONFIG_TT_LVGL_FONT_SIZE_SMALL=16\n") + output_file.write("CONFIG_TT_LVGL_FONT_SIZE_DEFAULT=20\n") + output_file.write("CONFIG_TT_LVGL_FONT_SIZE_LARGE=26\n") + output_file.write("CONFIG_TT_LVGL_STATUSBAR_ICON_SIZE=20\n") + output_file.write("CONFIG_TT_LVGL_LAUNCHER_ICON_SIZE=48\n") + output_file.write("CONFIG_TT_LVGL_SHARED_ICON_SIZE=20\n") + # For runtime font size setting on RLCD - include all sizes for switching + # This adds ~150KB to binary but allows runtime font choice 14/18/20/24/28 + output_file.write("CONFIG_LV_FONT_MONTSERRAT_14=y\n") + output_file.write("CONFIG_LV_FONT_MONTSERRAT_18=y\n") + output_file.write("CONFIG_LV_FONT_MONTSERRAT_24=y\n") + output_file.write("CONFIG_LV_FONT_MONTSERRAT_28=y\n") + output_file.write("CONFIG_LV_FONT_MONTSERRAT_30=y\n") elif font_height <= 24: output_file.write("CONFIG_LV_FONT_MONTSERRAT_18=y\n") output_file.write("CONFIG_LV_FONT_MONTSERRAT_24=y\n")