mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-17 02:45:05 +00:00
e-paper UX improvements (#672)
- On monochrome displays, buttons have no default-state border while retaining borders in other states. - App grid tiles retain the theme’s focus outlines and icon colors on monochrome displays. - Tile labels have a consistent height and continue to use dot truncation. - On non-monochrome displays, existing button, tile outline, icon color, and focus behavior remains unchanged.
This commit is contained in:
parent
2b6b4b5167
commit
0d451e8863
@ -1,4 +1,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#define LV_USE_PRIVATE_API 1 // For the lv_theme_t declaration
|
||||||
|
|
||||||
#include <lvgl/devices/display.h>
|
#include <lvgl/devices/display.h>
|
||||||
|
|
||||||
#include <lvgl/ppa.h>
|
#include <lvgl/ppa.h>
|
||||||
@ -18,6 +20,38 @@
|
|||||||
|
|
||||||
constexpr auto* TAG = "lvgl_display";
|
constexpr auto* TAG = "lvgl_display";
|
||||||
|
|
||||||
|
#if LV_USE_THEME_MONO
|
||||||
|
|
||||||
|
static lv_style_t mono_button_style;
|
||||||
|
static bool mono_button_style_initialized = false;
|
||||||
|
static lv_theme_t mono_theme_extension;
|
||||||
|
|
||||||
|
static void mono_theme_extension_apply(lv_theme_t*, lv_obj_t* obj) {
|
||||||
|
if (lv_obj_check_type(obj, &lv_button_class)) {
|
||||||
|
lv_obj_add_style(obj, &mono_button_style, LV_PART_MAIN | LV_STATE_DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The mono theme draws a border around every button. This removes it in the default state, keeping the pressed border and focus outline.
|
||||||
|
static void lvgl_display_extend_mono_theme(lv_display_t* disp) {
|
||||||
|
if (!mono_button_style_initialized) {
|
||||||
|
lv_style_init(&mono_button_style);
|
||||||
|
lv_style_set_border_width(&mono_button_style, 0);
|
||||||
|
mono_button_style_initialized = true;
|
||||||
|
}
|
||||||
|
// LVGL prefers the default and simple themes when they are also enabled, so only the mono theme itself is extended
|
||||||
|
lv_theme_t* mono_theme = lv_display_get_theme(disp);
|
||||||
|
if (mono_theme == nullptr || mono_theme != lv_theme_mono_get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mono_theme_extension = *mono_theme;
|
||||||
|
lv_theme_set_parent(&mono_theme_extension, mono_theme);
|
||||||
|
lv_theme_set_apply_cb(&mono_theme_extension, mono_theme_extension_apply);
|
||||||
|
lv_display_set_theme(disp, &mono_theme_extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
struct LvglDisplayCtx {
|
struct LvglDisplayCtx {
|
||||||
void* buf1;
|
void* buf1;
|
||||||
void* buf2;
|
void* buf2;
|
||||||
@ -470,6 +504,10 @@ error_t lvgl_display_add(struct Device* device, const struct LvglDisplayConfig*
|
|||||||
return ERROR_OUT_OF_MEMORY;
|
return ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LV_USE_THEME_MONO
|
||||||
|
lvgl_display_extend_mono_theme(disp);
|
||||||
|
#endif
|
||||||
|
|
||||||
ctx->render_mode = render_mode;
|
ctx->render_mode = render_mode;
|
||||||
lv_display_set_color_format(disp, lv_color_format);
|
lv_display_set_color_format(disp, lv_color_format);
|
||||||
lv_display_set_buffers(disp, ctx->buf1, ctx->buf2, buf_size_bytes, render_mode);
|
lv_display_set_buffers(disp, ctx->buf1, ctx->buf2, buf_size_bytes, render_mode);
|
||||||
|
|||||||
@ -52,6 +52,11 @@ lv_color_t getIconColor(bool focused, bool highlighted) {
|
|||||||
return highlighted ? lv_color_hex(ICON_COLOR_HIGHLIGHTED) : lv_color_white();
|
return highlighted ? lv_color_hex(ICON_COLOR_HIGHLIGHTED) : lv_color_white();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accent colours can't be rendered in 1bpp, so tiles use theme colours and the theme's focus outline instead
|
||||||
|
bool isMonochrome(lv_obj_t* obj) {
|
||||||
|
return lv_display_get_color_format(lv_obj_get_display(obj)) == LV_COLOR_FORMAT_I1;
|
||||||
|
}
|
||||||
|
|
||||||
const AppGridItem* getTileItem(lv_event_t* e) {
|
const AppGridItem* getTileItem(lv_event_t* e) {
|
||||||
return static_cast<const AppGridItem*>(lv_obj_get_user_data(lv_event_get_target_obj(e)));
|
return static_cast<const AppGridItem*>(lv_obj_get_user_data(lv_event_get_target_obj(e)));
|
||||||
}
|
}
|
||||||
@ -156,6 +161,7 @@ void AppGrid::populate() {
|
|||||||
lv_obj_set_flag(lv_obj_get_parent(nextButton), LV_OBJ_FLAG_HIDDEN, page_count <= 1);
|
lv_obj_set_flag(lv_obj_get_parent(nextButton), LV_OBJ_FLAG_HIDDEN, page_count <= 1);
|
||||||
|
|
||||||
lv_obj_t* focusedTile = nullptr;
|
lv_obj_t* focusedTile = nullptr;
|
||||||
|
const bool monochrome = isMonochrome(grid);
|
||||||
const uint32_t first = page * layout.pageSize;
|
const uint32_t first = page * layout.pageSize;
|
||||||
const uint32_t last = std::min(item_count, first + layout.pageSize);
|
const uint32_t last = std::min(item_count, first + layout.pageSize);
|
||||||
for (uint32_t i = first; i < last; i++) {
|
for (uint32_t i = first; i < last; i++) {
|
||||||
@ -167,8 +173,10 @@ void AppGrid::populate() {
|
|||||||
lv_obj_set_style_pad_row(tile, layout.pad / 2, LV_STATE_DEFAULT);
|
lv_obj_set_style_pad_row(tile, layout.pad / 2, LV_STATE_DEFAULT);
|
||||||
lv_obj_set_style_shadow_width(tile, 0, LV_STATE_DEFAULT);
|
lv_obj_set_style_shadow_width(tile, 0, LV_STATE_DEFAULT);
|
||||||
lv_obj_set_style_bg_opa(tile, LV_OPA_TRANSP, LV_STATE_DEFAULT);
|
lv_obj_set_style_bg_opa(tile, LV_OPA_TRANSP, LV_STATE_DEFAULT);
|
||||||
lv_obj_set_style_outline_width(tile, 0, LV_STATE_FOCUSED);
|
if (!monochrome) {
|
||||||
lv_obj_set_style_outline_width(tile, 0, LV_STATE_FOCUS_KEY);
|
lv_obj_set_style_outline_width(tile, 0, LV_STATE_FOCUSED);
|
||||||
|
lv_obj_set_style_outline_width(tile, 0, LV_STATE_FOCUS_KEY);
|
||||||
|
}
|
||||||
lv_obj_set_flex_flow(tile, LV_FLEX_FLOW_COLUMN);
|
lv_obj_set_flex_flow(tile, LV_FLEX_FLOW_COLUMN);
|
||||||
lv_obj_set_flex_align(tile, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
lv_obj_set_flex_align(tile, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
lv_obj_set_user_data(tile, const_cast<AppGridItem*>(&item));
|
lv_obj_set_user_data(tile, const_cast<AppGridItem*>(&item));
|
||||||
@ -177,13 +185,16 @@ void AppGrid::populate() {
|
|||||||
lv_obj_set_style_text_font(icon, lvgl_get_shared_icon_font_2x(), LV_STATE_DEFAULT);
|
lv_obj_set_style_text_font(icon, lvgl_get_shared_icon_font_2x(), LV_STATE_DEFAULT);
|
||||||
lv_obj_set_style_text_align(icon, LV_TEXT_ALIGN_CENTER, LV_STATE_DEFAULT);
|
lv_obj_set_style_text_align(icon, LV_TEXT_ALIGN_CENTER, LV_STATE_DEFAULT);
|
||||||
lv_obj_set_size(icon, layout.iconSize, layout.iconSize);
|
lv_obj_set_size(icon, layout.iconSize, layout.iconSize);
|
||||||
lv_obj_set_style_text_color(icon, getIconColor(false, item.highlighted), LV_STATE_DEFAULT);
|
if (!monochrome) {
|
||||||
|
lv_obj_set_style_text_color(icon, getIconColor(false, item.highlighted), LV_STATE_DEFAULT);
|
||||||
|
}
|
||||||
lv_label_set_text(icon, item.icon);
|
lv_label_set_text(icon, item.icon);
|
||||||
|
|
||||||
lv_obj_t* label = lv_label_create(tile);
|
lv_obj_t* label = lv_label_create(tile);
|
||||||
lv_obj_set_style_text_font(label, lvgl_get_text_font(FONT_SIZE_SMALL), LV_STATE_DEFAULT);
|
lv_obj_set_style_text_font(label, lvgl_get_text_font(FONT_SIZE_SMALL), LV_STATE_DEFAULT);
|
||||||
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, LV_STATE_DEFAULT);
|
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, LV_STATE_DEFAULT);
|
||||||
lv_obj_set_width(label, LV_PCT(100));
|
// Dots mode needs a fixed height, otherwise the label wraps instead of truncating
|
||||||
|
lv_obj_set_size(label, LV_PCT(100), lv_font_get_line_height(lvgl_get_text_font(FONT_SIZE_SMALL)));
|
||||||
lv_label_set_long_mode(label, LV_LABEL_LONG_MODE_DOTS);
|
lv_label_set_long_mode(label, LV_LABEL_LONG_MODE_DOTS);
|
||||||
lv_label_set_text(label, item.manifest.name);
|
lv_label_set_text(label, item.manifest.name);
|
||||||
|
|
||||||
@ -194,8 +205,10 @@ void AppGrid::populate() {
|
|||||||
if (callbacks.onKey != nullptr) {
|
if (callbacks.onKey != nullptr) {
|
||||||
lv_obj_add_event_cb(tile, onTileKey, LV_EVENT_KEY, this);
|
lv_obj_add_event_cb(tile, onTileKey, LV_EVENT_KEY, this);
|
||||||
}
|
}
|
||||||
lv_obj_add_event_cb(tile, onTileFocusChanged, LV_EVENT_FOCUSED, nullptr);
|
if (!monochrome) {
|
||||||
lv_obj_add_event_cb(tile, onTileFocusChanged, LV_EVENT_DEFOCUSED, nullptr);
|
lv_obj_add_event_cb(tile, onTileFocusChanged, LV_EVENT_FOCUSED, nullptr);
|
||||||
|
lv_obj_add_event_cb(tile, onTileFocusChanged, LV_EVENT_DEFOCUSED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (!focusedAppId.empty() && focusedAppId == item.manifest.id) {
|
if (!focusedAppId.empty() && focusedAppId == item.manifest.id) {
|
||||||
focusedTile = tile;
|
focusedTile = tile;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user