mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-10-09 03:06:39 +00:00
fix(ui-lvgl): popups no longer shrink when their list is pulled past its end
LVGL 9.2.2 measures a SIZE_CONTENT box from its children as scrolled, so an elastic pull past the end of a capped popup list shrank it by the overshoot, again on every pull. lvgl_patches.py fixes calc_content_height in the downloaded library (a build middleware for PlatformIO, called directly by the sim's build_wasm.sh). The five popups that each built the same panel now share popupOpen() (fit to content / full height / under the status bar). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -710,20 +710,7 @@ void UITask::mapDownloadPopup() {
|
||||
if (_dl_zmax < _map_z) _dl_zmax = _map_z + 3;
|
||||
if (_dl_zmax > src_max) _dl_zmax = src_max; // the server has nothing finer
|
||||
|
||||
_dl_overlay = dimOverlay(screen());
|
||||
|
||||
lv_obj_t* panel = lv_obj_create(_dl_overlay);
|
||||
anim::popup(_dl_overlay);
|
||||
lv_obj_set_size(panel, lv_display_get_horizontal_resolution(NULL) - 16, LV_SIZE_CONTENT);
|
||||
lv_obj_align(panel, LV_ALIGN_CENTER, 0, theme::STATUS_H / 2);
|
||||
lv_obj_set_style_bg_color(panel, lv_color_hex(theme::BG), 0);
|
||||
lv_obj_set_style_border_color(panel, lv_color_hex(theme::ACCENT), 0);
|
||||
lv_obj_set_style_border_width(panel, 1, 0);
|
||||
lv_obj_set_style_radius(panel, theme::RADIUS, 0);
|
||||
lv_obj_set_style_pad_all(panel, theme::PAD, 0);
|
||||
lv_obj_set_style_pad_row(panel, 4, 0);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_max_height(panel, lv_display_get_vertical_resolution(NULL) - theme::STATUS_H - 12, 0); // scrolls past that
|
||||
lv_obj_t* panel = popupOpen(screen(), POP_FIT, _dl_overlay);
|
||||
|
||||
lv_obj_t* hdr = lv_obj_create(panel);
|
||||
styleSurface(hdr, theme::BG);
|
||||
|
||||
@@ -476,27 +476,8 @@ void UITask::navToNode(const uint8_t* key, int32_t lat, int32_t lon, const char*
|
||||
|
||||
lv_obj_t* UITask::navPopupPanel(const char* title, bool full) {
|
||||
navClosePopup();
|
||||
_nav_overlay = dimOverlay(screen());
|
||||
|
||||
lv_obj_t* panel = lv_obj_create(_nav_overlay);
|
||||
anim::popup(_nav_overlay);
|
||||
int w = lv_display_get_horizontal_resolution(NULL) - 16;
|
||||
if (full) {
|
||||
lv_obj_set_size(panel, w, lv_display_get_vertical_resolution(NULL) - theme::STATUS_H - 12);
|
||||
lv_obj_set_pos(panel, 8, theme::STATUS_H + 6);
|
||||
} else { // as tall as its content, scrolling past the screen's height
|
||||
lv_obj_set_size(panel, w, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_max_height(panel, lv_display_get_vertical_resolution(NULL) - theme::STATUS_H - 12, 0);
|
||||
lv_obj_align(panel, LV_ALIGN_CENTER, 0, theme::STATUS_H / 2);
|
||||
}
|
||||
lv_obj_set_style_bg_color(panel, lv_color_hex(theme::BG), 0);
|
||||
lv_obj_set_style_border_color(panel, lv_color_hex(theme::ACCENT), 0);
|
||||
lv_obj_set_style_border_width(panel, 1, 0);
|
||||
lv_obj_set_style_radius(panel, theme::RADIUS, 0);
|
||||
lv_obj_set_style_pad_all(panel, theme::PAD, 0);
|
||||
lv_obj_t* panel = popupOpen(screen(), full ? POP_FULL : POP_FIT, _nav_overlay);
|
||||
lv_obj_set_style_pad_row(panel, 6, 0);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
|
||||
if (full) lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE); // its own list scrolls
|
||||
|
||||
lv_obj_t* hdr = lv_obj_create(panel);
|
||||
styleSurface(hdr, theme::BG);
|
||||
|
||||
@@ -141,19 +141,8 @@ void UITask::radioFreqPopup(bool repeater) {
|
||||
using namespace radioview;
|
||||
if (s_overlay) return;
|
||||
s_freq_rpt = repeater;
|
||||
s_overlay = dimOverlay(screen());
|
||||
lv_obj_t* panel = lv_obj_create(s_overlay);
|
||||
anim::popup(s_overlay);
|
||||
lv_obj_set_size(panel, lv_display_get_horizontal_resolution(NULL) - 16, LV_SIZE_CONTENT);
|
||||
lv_obj_align(panel, LV_ALIGN_TOP_MID, 0, theme::STATUS_H + 4);
|
||||
lv_obj_set_style_bg_color(panel, lv_color_hex(theme::BG), 0);
|
||||
lv_obj_set_style_border_color(panel, lv_color_hex(theme::ACCENT), 0);
|
||||
lv_obj_set_style_border_width(panel, 1, 0);
|
||||
lv_obj_set_style_radius(panel, theme::RADIUS, 0);
|
||||
lv_obj_set_style_pad_all(panel, theme::PAD, 0);
|
||||
lv_obj_t* panel = popupOpen(screen(), POP_TOP, s_overlay);
|
||||
lv_obj_set_style_pad_row(panel, 6, 0);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
||||
float lo, hi;
|
||||
radio_driver.getFreqBounds(lo, hi);
|
||||
char t[48];
|
||||
|
||||
@@ -150,6 +150,41 @@ static lv_obj_t* dimOverlay(lv_obj_t* parent) {
|
||||
return o;
|
||||
}
|
||||
|
||||
// A popup: the dimmed layer (into `overlay`, to close it by) and its panel --
|
||||
// the page colour, the accent hairline, a flex column -- rising into view.
|
||||
// POP_FIT: as tall as its content, centred below the status bar, scrolling
|
||||
// past that height. POP_FULL: all of that height; its own list scrolls.
|
||||
// POP_TOP: as tall as its content, under the status bar, clear of a keyboard.
|
||||
enum PopFit : uint8_t { POP_FIT, POP_FULL, POP_TOP };
|
||||
static lv_obj_t* popupOpen(lv_obj_t* parent, PopFit fit, lv_obj_t*& overlay, int32_t inset = 8) {
|
||||
overlay = dimOverlay(parent);
|
||||
lv_obj_t* panel = lv_obj_create(overlay);
|
||||
int32_t w = lv_display_get_horizontal_resolution(NULL), h = lv_display_get_vertical_resolution(NULL);
|
||||
lv_obj_set_width(panel, w - 2 * inset);
|
||||
if (fit == POP_FULL) {
|
||||
lv_obj_set_height(panel, h - theme::STATUS_H - 12);
|
||||
lv_obj_set_pos(panel, inset, theme::STATUS_H + 6);
|
||||
} else if (fit == POP_TOP) {
|
||||
lv_obj_set_height(panel, LV_SIZE_CONTENT);
|
||||
lv_obj_align(panel, LV_ALIGN_TOP_MID, 0, theme::STATUS_H + 4);
|
||||
} else {
|
||||
lv_obj_set_height(panel, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_max_height(panel, h - theme::STATUS_H - 12, 0);
|
||||
lv_obj_align(panel, LV_ALIGN_CENTER, 0, theme::STATUS_H / 2);
|
||||
lv_obj_set_scrollbar_mode(panel, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
}
|
||||
if (fit != POP_FIT) lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_style_bg_color(panel, lv_color_hex(theme::BG), 0);
|
||||
lv_obj_set_style_border_color(panel, lv_color_hex(theme::ACCENT), 0);
|
||||
lv_obj_set_style_border_width(panel, 1, 0);
|
||||
lv_obj_set_style_radius(panel, theme::RADIUS, 0);
|
||||
lv_obj_set_style_pad_all(panel, theme::PAD, 0);
|
||||
lv_obj_set_style_pad_row(panel, 4, 0);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
|
||||
anim::popup(overlay);
|
||||
return panel;
|
||||
}
|
||||
|
||||
// ── Info cards ──
|
||||
// Label / value rows on a card (Diagnostics, GPS, node detail, About): the
|
||||
// label small and muted on the left, the value on the right -- wrapping,
|
||||
@@ -429,23 +464,11 @@ static void pickerOpen(lv_obj_t* c) {
|
||||
Choice* ch = choiceOf(c);
|
||||
pickerClose();
|
||||
s_pick_target = c;
|
||||
s_pick_overlay = dimOverlay(lv_layer_top());
|
||||
lv_obj_t* panel = popupOpen(lv_layer_top(), POP_FIT, s_pick_overlay, 24);
|
||||
lv_obj_add_event_cb(s_pick_overlay, [](lv_event_t* e) { // a tap beside the list: nothing changes
|
||||
if (lv_event_get_target(e) == lv_event_get_current_target(e)) pickerClose();
|
||||
}, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_t* panel = lv_obj_create(s_pick_overlay);
|
||||
styleSurface(panel, theme::BG);
|
||||
lv_obj_set_width(panel, lv_display_get_horizontal_resolution(NULL) - 48);
|
||||
lv_obj_set_height(panel, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_max_height(panel, lv_display_get_vertical_resolution(NULL) - theme::STATUS_H - 16, 0);
|
||||
lv_obj_align(panel, LV_ALIGN_CENTER, 0, theme::STATUS_H / 2);
|
||||
lv_obj_set_style_radius(panel, theme::RADIUS, 0);
|
||||
lv_obj_set_style_border_color(panel, lv_color_hex(theme::ACCENT), 0);
|
||||
lv_obj_set_style_border_width(panel, 1, 0);
|
||||
lv_obj_set_style_pad_all(panel, 6, 0);
|
||||
lv_obj_set_style_pad_row(panel, 4, 0);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_scrollbar_mode(panel, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
lv_obj_t* t = label(panel, ch->title, THEME_FONT_SMALL, theme::TEXT_MUTED);
|
||||
lv_obj_set_style_pad_hor(t, 4, 0);
|
||||
lv_obj_t* card = group(panel, nullptr);
|
||||
@@ -459,7 +482,6 @@ static void pickerOpen(lv_obj_t* c) {
|
||||
if (cur) { label(r, LV_SYMBOL_OK, THEME_FONT_BODY, theme::ACCENT); sel_row = r; }
|
||||
lv_obj_add_event_cb(r, onPickOption, LV_EVENT_CLICKED, (void*)(uintptr_t)i);
|
||||
}
|
||||
anim::popup(s_pick_overlay);
|
||||
if (sel_row) { lv_obj_update_layout(panel); lv_obj_scroll_to_view_recursive(sel_row, LV_ANIM_OFF); }
|
||||
}
|
||||
|
||||
@@ -1812,21 +1834,7 @@ void UITask::startNearbyScan() {
|
||||
// Dimmed full-screen overlay (swallows taps) holding a panel with the results.
|
||||
// A child of the current screen, so it goes away with it.
|
||||
void UITask::showScanPopup() {
|
||||
_scan_overlay = dimOverlay(screen());
|
||||
|
||||
lv_obj_t* panel = lv_obj_create(_scan_overlay);
|
||||
anim::popup(_scan_overlay);
|
||||
lv_obj_set_size(panel, lv_display_get_horizontal_resolution(NULL) - 16,
|
||||
lv_display_get_vertical_resolution(NULL) - theme::STATUS_H - 12);
|
||||
lv_obj_set_pos(panel, 8, theme::STATUS_H + 6);
|
||||
lv_obj_set_style_bg_color(panel, lv_color_hex(theme::BG), 0);
|
||||
lv_obj_set_style_border_color(panel, lv_color_hex(theme::ACCENT), 0);
|
||||
lv_obj_set_style_border_width(panel, 1, 0);
|
||||
lv_obj_set_style_radius(panel, theme::RADIUS, 0);
|
||||
lv_obj_set_style_pad_all(panel, theme::PAD, 0);
|
||||
lv_obj_set_style_pad_row(panel, 4, 0);
|
||||
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_t* panel = popupOpen(screen(), POP_FULL, _scan_overlay);
|
||||
|
||||
lv_obj_t* hdr = lv_obj_create(panel);
|
||||
styleSurface(hdr, theme::BG);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# Fixes to LVGL 9.2.2 (lib_deps) that ui-lvgl needs, applied in place to the
|
||||
# downloaded library -- idempotent, so every build can run it.
|
||||
#
|
||||
# PlatformIO: extra_scripts = pre:examples/companion_radio/ui-lvgl/lvgl_patches.py
|
||||
# (patches as LVGL is compiled, i.e. after lib_deps are fetched)
|
||||
# The sim: python3 examples/companion_radio/ui-lvgl/lvgl_patches.py <lvgl dir>
|
||||
#
|
||||
# Content height counted as scrolled (lv_obj_pos.c, calc_content_height): a
|
||||
# SIZE_CONTENT box capped by max_height measures its children where the scroll
|
||||
# has moved them, so an elastic pull past its end shrinks it by the overshoot,
|
||||
# again on every pull (popups with a list). The function zeroes scroll.y for
|
||||
# the count, but the children's coords already carry it; it's added back.
|
||||
import os
|
||||
import sys
|
||||
|
||||
PATCHES = [
|
||||
("src/core/lv_obj_pos.c", [
|
||||
(" /*Normal top aligns. */\n"
|
||||
" child_res_tmp = child->coords.y2 - obj->coords.y1 + 1;\n",
|
||||
" /*Normal top aligns. */\n"
|
||||
" child_res_tmp = child->coords.y2 - obj->coords.y1 + 1 + scroll_y_tmp;\n"),
|
||||
(" else {\n"
|
||||
" child_res_tmp = child->coords.y2 - obj->coords.y1 + 1;\n"
|
||||
" }\n",
|
||||
" else {\n"
|
||||
" child_res_tmp = child->coords.y2 - obj->coords.y1 + 1 + scroll_y_tmp;\n"
|
||||
" }\n"),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
def apply(lvgl_dir):
|
||||
for rel, subs in PATCHES:
|
||||
path = os.path.join(lvgl_dir, rel)
|
||||
with open(path) as f:
|
||||
src = f.read()
|
||||
out = src
|
||||
for old, new in subs:
|
||||
if new in out:
|
||||
continue
|
||||
if out.count(old) != 1:
|
||||
raise RuntimeError("lvgl_patches: %s changed upstream, re-check the patch" % rel)
|
||||
out = out.replace(old, new)
|
||||
if out != src:
|
||||
with open(path, "w") as f:
|
||||
f.write(out)
|
||||
print("lvgl_patches: patched %s" % rel)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
apply(sys.argv[1])
|
||||
else:
|
||||
Import("env") # noqa: F821 (SCons)
|
||||
|
||||
def _patch(env, node):
|
||||
path = node.srcnode().get_abspath()
|
||||
apply(path[: path.rindex(os.sep + "src" + os.sep)])
|
||||
return node
|
||||
|
||||
env.AddBuildMiddleware(_patch, "*/lvgl/src/core/lv_obj_pos.c") # noqa: F821
|
||||
Reference in New Issue
Block a user