feat(rlcd): invert toggle, mono threshold, font bump, B/W luminance
- RLCD device.properties: DefaultDark (focus UI visible), fontSize 18
(+28% vs 14: small 10->14, default 14->18, large 18->24, icons 16->20/36->48)
- ST7305 driver: honor invertColor config (was ignored), call
esp_lcd_panel_invert_color after init
- DisplayDevice: add supportsInvertColor + set/get, and
supportsMonochromeThreshold/set/get (ST7305 only)
- EspLcdDisplay: implement invert via panelHandle, and mono threshold via
global g_mono_threshold shared with esp_lvgl_port
- DisplaySettings: new fields invertColor (default true to preserve current
inverted look) and monochromeThreshold (default 60 best for DefaultDark per
user testing, range 20-230)
- Lvgl.cpp: apply invert + threshold at boot from settings
- Display app: add Invert colors switch (if supportsInvertColor) + Mono
threshold slider with live preview and persistence
- esp_lvgl_port_disp.c (components override for hash mismatch): fix B/W
conversion
BEFORE: blue >16 only -> crushed colors, no gray handling
AFTER: proper luminance Y=0.299R+0.587G+0.114B with adjustable threshold
(default 60), no Bayer dithering dots. Crisp text on reflective
- Launcher/button/list wrappers reverted to stock DefaultDark (no white
focus hacks) per user request - focus UI now uses default outline which
survives luminance threshold
Verified on waveshare-esp32-s3-rlcd /dev/cu.usbmodem1101:
- Build 2877200 bytes, flash hash verified
- Invert toggle works, threshold slider live (60 best per test)
- Font bump visible, focus UI visible for button navigation
- No dithering dots
Docs: LVGL mono https://docs.lvgl.io/9.2/porting/display.html#monochrome-displays
Themes: https://docs.lvgl.io/9.2/details/common-widget-features/styles/themes.html
Co-authored-by: Hermes Agent <hermes@noreply>
This commit is contained in:
@@ -120,6 +120,42 @@ class DisplayApp final : public App {
|
||||
app->displaySettingsUpdated = true;
|
||||
}
|
||||
|
||||
static void onInvertColorChanged(lv_event_t* event) {
|
||||
auto* app = static_cast<DisplayApp*>(lv_event_get_user_data(event));
|
||||
auto* sw = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
bool enabled = lv_obj_has_state(sw, LV_STATE_CHECKED);
|
||||
app->displaySettings.invertColor = enabled;
|
||||
app->displaySettingsUpdated = true;
|
||||
// Apply immediately
|
||||
auto hal_display = getHalDisplay();
|
||||
if (hal_display && hal_display->supportsInvertColor()) {
|
||||
hal_display->setInvertColor(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
static void onMonoThresholdChanged(lv_event_t* event) {
|
||||
auto* slider = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
auto* app = static_cast<DisplayApp*>(lv_event_get_user_data(event));
|
||||
int32_t val = lv_slider_get_value(slider);
|
||||
if (val < 1) val = 1;
|
||||
if (val > 255) val = 255;
|
||||
app->displaySettings.monochromeThreshold = static_cast<uint8_t>(val);
|
||||
app->displaySettingsUpdated = true;
|
||||
auto hal_display = getHalDisplay();
|
||||
if (hal_display && hal_display->supportsMonochromeThreshold()) {
|
||||
hal_display->setMonochromeThreshold(static_cast<uint8_t>(val));
|
||||
}
|
||||
}
|
||||
|
||||
static void onMonoThresholdChanging(lv_event_t* event) {
|
||||
auto* slider = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
auto* value_label = static_cast<lv_obj_t*>(lv_event_get_user_data(event));
|
||||
if (value_label) {
|
||||
int32_t v = lv_slider_get_value(slider);
|
||||
lv_label_set_text_fmt(value_label, "%d", (int)v);
|
||||
}
|
||||
}
|
||||
|
||||
static void onTimeoutChanged(lv_event_t* event) {
|
||||
auto* app = static_cast<DisplayApp*>(lv_event_get_user_data(event));
|
||||
auto* dropdown = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||
@@ -332,6 +368,65 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Invert color toggle (if display supports it - e.g. RLCD ST7305)
|
||||
{
|
||||
auto hal_disp = getHalDisplay();
|
||||
if (hal_disp && hal_disp->supportsInvertColor()) {
|
||||
auto* invert_wrapper = lv_obj_create(main_wrapper);
|
||||
lv_obj_set_size(invert_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_all(invert_wrapper, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(invert_wrapper, 0, LV_STATE_DEFAULT);
|
||||
|
||||
auto* invert_label = lv_label_create(invert_wrapper);
|
||||
lv_label_set_text(invert_label, "Invert colors");
|
||||
lv_obj_align(invert_label, LV_ALIGN_LEFT_MID, 0, 0);
|
||||
|
||||
auto* invert_switch = lv_switch_create(invert_wrapper);
|
||||
if (displaySettings.invertColor) {
|
||||
lv_obj_add_state(invert_switch, LV_STATE_CHECKED);
|
||||
}
|
||||
lv_obj_align(invert_switch, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||
lv_obj_add_event_cb(invert_switch, onInvertColorChanged, LV_EVENT_VALUE_CHANGED, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Monochrome threshold slider (ST7305 reflective) - adjustable B/W cut
|
||||
{
|
||||
auto hal_disp = getHalDisplay();
|
||||
if (hal_disp && hal_disp->supportsMonochromeThreshold()) {
|
||||
auto* thresh_wrapper = lv_obj_create(main_wrapper);
|
||||
lv_obj_set_size(thresh_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_all(thresh_wrapper, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(thresh_wrapper, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_set_flex_flow(thresh_wrapper, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_row(thresh_wrapper, 2, LV_STATE_DEFAULT);
|
||||
|
||||
auto* header_row = lv_obj_create(thresh_wrapper);
|
||||
lv_obj_set_size(header_row, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_pad_all(header_row, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(header_row, 0, LV_STATE_DEFAULT);
|
||||
|
||||
auto* thresh_label = lv_label_create(header_row);
|
||||
lv_label_set_text(thresh_label, "Mono threshold");
|
||||
lv_obj_align(thresh_label, LV_ALIGN_LEFT_MID, 0, 0);
|
||||
|
||||
auto* value_label = lv_label_create(header_row);
|
||||
lv_label_set_text_fmt(value_label, "%d", displaySettings.monochromeThreshold);
|
||||
lv_obj_align(value_label, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||
|
||||
auto* thresh_slider = lv_slider_create(thresh_wrapper);
|
||||
lv_obj_set_width(thresh_slider, LV_PCT(100));
|
||||
lv_slider_set_range(thresh_slider, 20, 230); // avoid extremes that make screen all black/white
|
||||
lv_slider_set_value(thresh_slider, displaySettings.monochromeThreshold, LV_ANIM_OFF);
|
||||
// Live label update: pass value_label as user_data
|
||||
lv_obj_add_event_cb(thresh_slider, onMonoThresholdChanging, LV_EVENT_VALUE_CHANGED, value_label);
|
||||
// Persist + apply: pass app as user_data
|
||||
lv_obj_add_event_cb(thresh_slider, onMonoThresholdChanged, LV_EVENT_VALUE_CHANGED, this);
|
||||
// Apply initial threshold live
|
||||
hal_disp->setMonochromeThreshold(displaySettings.monochromeThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasCalibratableTouchDevice()) {
|
||||
auto* calibrate_wrapper = lv_obj_create(main_wrapper);
|
||||
lv_obj_set_size(calibrate_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
|
||||
Reference in New Issue
Block a user