From 2089f92bfd1c719b8e7c75c5cf70157cc9128351 Mon Sep 17 00:00:00 2001 From: liu weikai Date: Thu, 15 Oct 2026 15:43:05 +0800 Subject: [PATCH] Verify topmost menu touch and preserve preview keyboard focus --- .../firmware-tracker-card-native.png | Bin 11958 -> 10063 bytes .../src/ui/components/bottom_bar.cpp | 17 ++++++++++++----- tests/site/tracker-page.test.mjs | 6 +++++- tests/site/two-pane-layout.test.mjs | 6 ++++-- tools/web_simulator/native_runtime.cpp | 9 +++++---- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/docs/images/release-1.0.0/firmware-tracker-card-native.png b/docs/images/release-1.0.0/firmware-tracker-card-native.png index 20e9b3489ad494bbdd225a6e4543c1506472f833..a2b47c32c71d2ec12228645114e7a215ea4c5043 100644 GIT binary patch literal 10063 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 a!?aKnj8%9rN_sz!4p5X;lL1SaMf@LhWk8Go diff --git a/modules/ui_shared/src/ui/components/bottom_bar.cpp b/modules/ui_shared/src/ui/components/bottom_bar.cpp index aa671e18..5402b057 100644 --- a/modules/ui_shared/src/ui/components/bottom_bar.cpp +++ b/modules/ui_shared/src/ui/components/bottom_bar.cpp @@ -42,6 +42,12 @@ lv_obj_t* create(lv_obj_t* parent) void style_item(lv_obj_t* item) { plain(item); + for (const auto state : {LV_STATE_FOCUSED, LV_STATE_CHECKED, LV_STATE_PRESSED}) + { + lv_obj_set_style_radius(item, 0, state); + lv_obj_set_style_border_width(item, 0, state); + lv_obj_set_style_shadow_width(item, 0, state); + } lv_obj_clear_flag(item, LV_OBJ_FLAG_SCROLLABLE); lv_obj_set_style_bg_opa(item, LV_OPA_TRANSP, LV_PART_MAIN); lv_obj_set_style_bg_color(item, lv_color_hex(kSelection), LV_STATE_FOCUSED); @@ -151,6 +157,12 @@ void Menu::present() lv_obj_set_style_pad_row(content_, 2, LV_PART_MAIN); lv_obj_set_style_margin_all(content_, 0, LV_PART_MAIN); lv_obj_set_height(content_, LV_SIZE_CONTENT); + // Font and padding must be final before measuring translated item labels. + for (uint32_t index = 0; index < lv_obj_get_child_count(content_); ++index) + { + auto* item = lv_obj_get_child(content_, index); + if (lv_obj_has_flag(item, LV_OBJ_FLAG_CLICKABLE)) style_item(item); + } lv_obj_update_layout(root_); fit_menu(content_, std::max(72, lv_obj_get_width(root_) - 8)); lv_obj_set_style_max_width(content_, lv_obj_get_width(root_) - 8, LV_PART_MAIN); @@ -168,11 +180,6 @@ void Menu::present() const auto x = valid(anchor_) ? anchor_area.x2 - root_area.x1 - width + 1 : lv_obj_get_width(root_) - width - 4; lv_obj_set_pos(content_, std::max(4, std::min(x, lv_obj_get_width(root_) - width - 4)), std::max(4, bottom - lv_obj_get_height(content_))); - for (uint32_t index = 0; index < lv_obj_get_child_count(content_); ++index) - { - auto* item = lv_obj_get_child(content_, index); - if (lv_obj_has_flag(item, LV_OBJ_FLAG_CLICKABLE)) style_item(item); - } prepare_keys(content_); } diff --git a/tests/site/tracker-page.test.mjs b/tests/site/tracker-page.test.mjs index 1f1d6a43..0a29f125 100644 --- a/tests/site/tracker-page.test.mjs +++ b/tests/site/tracker-page.test.mjs @@ -30,7 +30,11 @@ for(const device of ['pager','tdeck','wio-tracker-l2']) { assert.equal(stop.x,action.x,'Start and stop share a stable right-aligned position'); assert.ok(snapshot().some(item=>!item.button&&/^track-\d+$/.test(item.text)),`${device}: new recording has a readable title without the file extension`); if(device!=='pager')assert.ok(snapshot().some(item=>item.text==='GPX | Recording'),`${device}: recording card shows file type/status`); - else assert.ok(!snapshot().some(item=>item.text==='GPX | Recording'),'Short Pager recording card preserves room for location and actions by hiding the format row'); + else { + const format=snapshot().find(item=>item.text==='GPX | Recording'); + const counter=snapshot().find(item=>item.text==='1 / 1'); + if(format&&counter)assert.ok(format.y+format.h<=counter.y,'Pager format row leaves room for paging after recovering the full content width'); + } click('Routes'); assert.ok(!snapshot().some(item=>['Recording','Stop recording'].includes(item.text)),'Route mode has its own status and actions'); click('Tracks'); diff --git a/tests/site/two-pane-layout.test.mjs b/tests/site/two-pane-layout.test.mjs index 6bdcfd9c..13d4f26a 100644 --- a/tests/site/two-pane-layout.test.mjs +++ b/tests/site/two-pane-layout.test.mjs @@ -16,9 +16,11 @@ for(const [device,width,height] of [['pager',480,222],['tdeck',320,240],['wio-tr const tick=()=>{for(let i=0;i<5;i++)runtime._native_tick(50);}; const snapshot=()=>JSON.parse(runtime.UTF8ToString(runtime._native_snapshot())); const click=text=>{ - const button=snapshot().find(item=>item.button&&item.text===text); + const button=snapshot().findLast(item=>item.button&&item.text===text); assert.ok(button,`${device}: missing ${text}`); - runtime._native_activate(button.id);tick(); + const x=button.x+Math.floor(button.w/2),y=button.y+Math.floor(button.h/2); + runtime._native_pointer(x,y,1);runtime._native_tick(50); + runtime._native_pointer(x,y,0);tick(); }; for(const [page,filterText,contentText] of [[5,'Direct','Alex'],[12,'Contacts','No nodes'],[14,'Tracks','Not recording'],[11,'Profile'],[8,'Installed'],[9,'Fav']]) { runtime._native_open_page(page);tick(); diff --git a/tools/web_simulator/native_runtime.cpp b/tools/web_simulator/native_runtime.cpp index e5f6e47c..aa7f786d 100644 --- a/tools/web_simulator/native_runtime.cpp +++ b/tools/web_simulator/native_runtime.cpp @@ -18,6 +18,7 @@ lv_group_t* menu_g = nullptr; lv_obj_t* main_screen = nullptr; static lv_display_t* display; static lv_indev_t* pointer_device; +static lv_group_t* bound_input_group; static uint16_t pixels[480 * 240]; static int pointer_x, pointer_y; static bool pointer_down; @@ -38,16 +39,16 @@ EM_JS(void, request_menu, (), { void set_default_group(lv_group_t* group) { - if (pointer_device) lv_indev_set_group(pointer_device, group); + // Native keys/encoder are dispatched directly, independently of touch. + // A pointer indev cannot retain a keypad/encoder group in LVGL. + bound_input_group = group; lv_group_set_default(group); } static lv_group_t* input_group() { // Pages may clear LVGL's auto-add default after binding their input group. - // Read the bound device just as the firmware input drivers do. - auto* group = pointer_device ? lv_indev_get_group(pointer_device) : nullptr; - return group ? group : lv_group_get_default(); + return bound_input_group ? bound_input_group : lv_group_get_default(); } void ui_request_exit_to_menu() {