mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-01 10:21:59 +00:00
fix(l2): quick panel stalled and tore when pulled; GPS sky plot cut off
The panel froze and dimmed the screen as the finger started: a snapshot of the whole screen (slow on the map) and a full-screen flush, so it stalled, jumped and tore top to bottom. Now it slides opaque over the live screen (a clear layer under it still takes the tap that closes it), built at start. Its slide is timed by its own frames, at most 30 ms a frame: a slow frame ended the 160 ms lv_anim and the panel just appeared. The sky plot on GPS > Sky was a fixed 168 px, taller than what is left under the title bar and tabs: now it takes that height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,7 +34,7 @@ static lv_obj_t *s_quality = nullptr, *s_pos = nullptr, *s_grid = nullptr, *s_al
|
||||
*s_speed = nullptr, *s_course = nullptr, *s_hdop = nullptr, *s_vdop = nullptr,
|
||||
*s_pdop = nullptr, *s_cn0 = nullptr, *s_best = nullptr, *s_nmea = nullptr, *s_rx = nullptr;
|
||||
static lv_obj_t *s_d_fix = nullptr, *s_d_ttff = nullptr, *s_d_search = nullptr, *s_d_utc = nullptr;
|
||||
static const int SKY = 168;
|
||||
static const int SKY = 168; // the plot at most; less when the screen under the tabs is shorter
|
||||
static const int BAR_PITCH = 26, BAR_W = 16, BARS_H = 120, AXIS_W = 22;
|
||||
|
||||
// Snapshot the screen draws from, sorted: used first, then by signal.
|
||||
@@ -108,7 +108,7 @@ static void onGpsSkyDraw(lv_event_t* e) {
|
||||
lv_area_t a;
|
||||
lv_obj_get_coords(o, &a);
|
||||
int32_t cx = (a.x1 + a.x2) / 2, cy = (a.y1 + a.y2) / 2;
|
||||
int32_t r = SKY / 2 - 10;
|
||||
int32_t r = lv_area_get_height(&a) / 2 - 10;
|
||||
|
||||
lv_draw_arc_dsc_t arc;
|
||||
lv_draw_arc_dsc_init(&arc);
|
||||
@@ -275,7 +275,12 @@ void UITask::buildGps() {
|
||||
styleSurface(s_sky, theme::BG);
|
||||
lv_obj_remove_flag(s_sky, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_remove_flag(s_sky, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_set_size(s_sky, SKY, SKY);
|
||||
{ // as tall as is left under the tabs
|
||||
layoutNow(body);
|
||||
int32_t h = lv_obj_get_content_height(body) - theme::TAB_H - lv_obj_get_style_pad_row(body, LV_PART_MAIN);
|
||||
if (h > SKY) h = SKY;
|
||||
lv_obj_set_size(s_sky, h, h);
|
||||
}
|
||||
lv_obj_add_event_cb(s_sky, onGpsSkyDraw, LV_EVENT_DRAW_MAIN_END, NULL);
|
||||
|
||||
lv_obj_t* col = lv_obj_create(top);
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
// GPS, sound, the trail, live share -- the advert, the lock, and the
|
||||
// brightness under them. Holding a tile opens its settings. The tiles are two
|
||||
// pages of four, swiped sideways. Swiped up, a tap under it or on the status
|
||||
// bar, the side button or another screen puts it away. The screen under it
|
||||
// is frozen and dimmed in one snapshot (freeze::early, as under a popup), so
|
||||
// the slide redraws an image and the panel -- a live screen under it, or a
|
||||
// dim blended over that, was redrawn every frame -- and nothing under it
|
||||
// takes a touch. ui-new has the same things as Home pages (Radio, Bluetooth,
|
||||
// Advert, GPS).
|
||||
// bar, the side button or another screen puts it away. Nothing under it
|
||||
// takes a touch (a clear layer catches it). The screen under it isn't dimmed
|
||||
// or frozen: the panel is opaque, so sliding down it covers the screen
|
||||
// without redrawing it, where a frozen, dimmed copy took a snapshot of the
|
||||
// whole screen as the finger started (the panel stalled, then jumped) and
|
||||
// sent all of it to the panel at once (it tore, top to bottom). Built at
|
||||
// start, so the first pull doesn't stall either. ui-new has the same things
|
||||
// as Home pages (Radio, Bluetooth, Advert, GPS).
|
||||
//
|
||||
// Single-TU fragment: included by ui-lvgl/UITask.cpp after QuickScreen.h.
|
||||
|
||||
@@ -19,7 +21,7 @@ enum : uint8_t { T_BT, T_WIFI, T_GPS, T_SOUND, T_ADVERT, T_TRAIL, T_SHARE, T_LOC
|
||||
static const int PER_PAGE = 4;
|
||||
|
||||
static lv_obj_t* s_panel = nullptr;
|
||||
static lv_obj_t* s_catch = nullptr; // under it, while it's out: a tap there closes it
|
||||
static lv_obj_t* s_catch = nullptr; // under it, while it's out: a tap there closes it (clear)
|
||||
static lv_obj_t* s_pages = nullptr;
|
||||
static lv_obj_t* s_dot[2];
|
||||
static uint8_t s_look[T_COUNT]; // what tileSet() last drew (0: nothing yet)
|
||||
@@ -38,18 +40,48 @@ static void place(int32_t ty) {
|
||||
if (ty < -s_h) ty = -s_h;
|
||||
lv_obj_set_style_translate_y(s_panel, ty, 0);
|
||||
}
|
||||
static void placeCb(void* o, int32_t v) { (void)o; place(v); }
|
||||
static void hidden(lv_anim_t* a) {
|
||||
(void)a;
|
||||
lv_obj_add_flag(s_panel, LV_OBJ_FLAG_HIDDEN);
|
||||
if (s_catch) { lv_obj_delete(s_catch); s_catch = nullptr; } // the frozen screen goes with it
|
||||
if (s_catch) { lv_obj_delete(s_catch); s_catch = nullptr; }
|
||||
s_sb_panel = false; // back under the title bar, if the screen has one
|
||||
s_ui->statusBarSync();
|
||||
}
|
||||
// The slide, timed by its own frames: a frame that took long (the map
|
||||
// redrawing under it) moves it at most STEP_MS on, where an lv_anim, timed
|
||||
// by the clock alone, was over by then and the panel just appeared.
|
||||
static const uint32_t STEP_MS = 30;
|
||||
static lv_timer_t* s_mover = nullptr;
|
||||
static int32_t s_from = 0, s_to = 0;
|
||||
static uint32_t s_t = 0, s_dur = 1, s_last = 0;
|
||||
static bool s_away = false;
|
||||
static void moverStop() {
|
||||
if (s_mover) { lv_timer_delete(s_mover); s_mover = nullptr; }
|
||||
}
|
||||
static void moverTick(lv_timer_t* t) {
|
||||
(void)t;
|
||||
uint32_t dt = lv_tick_elaps(s_last);
|
||||
s_last = lv_tick_get();
|
||||
s_t += dt < STEP_MS ? dt : STEP_MS;
|
||||
if (s_t >= s_dur) {
|
||||
moverStop();
|
||||
place(s_to);
|
||||
if (s_away) hidden(nullptr);
|
||||
return;
|
||||
}
|
||||
const int32_t k = 1024 - (int32_t)((s_dur - s_t) * 1024 / s_dur); // 0..1024, then eased out
|
||||
const int32_t e = 1024 - (1024 - k) * (1024 - k) / 1024 * (1024 - k) / 1024;
|
||||
place(s_from + (s_to - s_from) * e / 1024);
|
||||
}
|
||||
static void slide(int32_t to, bool away) {
|
||||
lv_anim_delete(s_panel, NULL);
|
||||
anim::run(s_panel, placeCb, lv_obj_get_style_translate_y(s_panel, LV_PART_MAIN), to,
|
||||
away ? anim::OUT_MS : anim::POP_MS, away ? hidden : nullptr);
|
||||
moverStop();
|
||||
s_from = lv_obj_get_style_translate_y(s_panel, LV_PART_MAIN);
|
||||
s_to = to;
|
||||
s_away = away;
|
||||
s_t = 0;
|
||||
s_dur = away ? anim::OUT_MS : anim::POP_MS;
|
||||
s_last = lv_tick_get();
|
||||
s_mover = lv_timer_create(moverTick, LV_DEF_REFR_PERIOD / 2, NULL);
|
||||
}
|
||||
|
||||
static void onTile(lv_event_t* e) {
|
||||
@@ -142,7 +174,7 @@ static void onStatusBarTouch(lv_event_t* e) {
|
||||
}
|
||||
}
|
||||
|
||||
// Built the first time it's pulled, on the top layer between the screen and
|
||||
// Built at start (UITask::begin), hidden, on the top layer between the screen and
|
||||
// the toast and status bar (which stay over it).
|
||||
void UITask::quickPanelBuild() {
|
||||
using namespace qpanel;
|
||||
@@ -245,19 +277,16 @@ bool UITask::quickPanelBegin() {
|
||||
if (_nav_overlay) navClosePopup();
|
||||
pickerClose();
|
||||
quickPanelRefresh();
|
||||
lv_anim_delete(s_panel, NULL);
|
||||
if (!s_catch) { // a still copy of the screen, dimmed, under it: a tap or swipe there closes it
|
||||
moverStop();
|
||||
if (!s_catch) { // a clear layer under it: a tap or swipe there closes it
|
||||
s_catch = lv_obj_create(lv_layer_top());
|
||||
lv_obj_remove_style_all(s_catch);
|
||||
lv_obj_set_size(s_catch, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_bg_color(s_catch, lv_color_hex(0x000000), 0);
|
||||
lv_obj_add_flag(s_catch, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_remove_flag(s_catch, LV_OBJ_FLAG_GESTURE_BUBBLE);
|
||||
lv_obj_add_event_cb(s_catch, onCatch, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_add_event_cb(s_catch, onPanelGesture, LV_EVENT_GESTURE, NULL);
|
||||
lv_obj_move_to_index(s_catch, lv_obj_get_index(s_panel));
|
||||
lv_obj_add_event_cb(s_catch, freeze::ownerDeleted, LV_EVENT_DELETE, NULL);
|
||||
freeze::early(s_catch, LV_OPA_50); // no memory, or a popup's still frozen: the screen stays as it is
|
||||
}
|
||||
lv_obj_remove_flag(s_panel, LV_OBJ_FLAG_HIDDEN);
|
||||
s_sb_panel = true; // the full status bar over it, a title bar or not
|
||||
@@ -275,7 +304,7 @@ void UITask::quickPanelClose(bool animate) {
|
||||
if (!s_panel || (!s_open && lv_obj_has_flag(s_panel, LV_OBJ_FLAG_HIDDEN))) return;
|
||||
s_open = s_drag = false;
|
||||
if (animate) { slide(-s_h, true); return; }
|
||||
lv_anim_delete(s_panel, NULL);
|
||||
moverStop();
|
||||
hidden(nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,7 @@ void UITask::begin(DisplayDriver* display_drv, SensorManager* sensors, NodePrefs
|
||||
lv_display_add_event_cb(lv_display_get_default(), [](lv_event_t*) { rowsFitPending(); }, LV_EVENT_REFR_START, NULL);
|
||||
|
||||
buildStatusBar();
|
||||
quickPanelBuild(); // QuickPanel.h: ready before the first pull
|
||||
applyDisplayPrefs(); // a slider percentage overrides the level main.cpp set
|
||||
{ char c[24]; lvport::crashSummary(c, sizeof(c)); } // the dump in flash read now (~45 ms), not on the first Diagnostics
|
||||
showHome();
|
||||
|
||||
Reference in New Issue
Block a user