mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-01 10:21:59 +00:00
fix: GPS search clock stops with the receiver; L2 cursor survives accented keys; lighter, scrolling quick panel
- GPS: stop() resets the sky state so the 'Searching' timer does not run while the receiver is off; the status page shows it only when GPS is on. - L2 keyboard: put the FOCUSED state back after typing a key or picking a variant, so the cursor is drawn again after characters like a-ogonek. - Quick panel: drop the full-screen dim (a blend per frame), so the screen below stays interactive; tiles are one sideways-scrolling, snapping row; the brightness slider no longer animates and only updates the backlight when the value changes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VeBrxKyHHxWsmttVkUdBrj
This commit is contained in:
@@ -151,6 +151,13 @@ static void releaseShift(lv_obj_t* kbd) {
|
||||
static char s_var_txt[12][8];
|
||||
static const char* s_var_map[13];
|
||||
|
||||
// The cursor is only drawn while the field is FOCUSED, and the popup (a touch
|
||||
// on another object) can take that state away: put it back after a pick.
|
||||
static void keepCursor(lv_obj_t* ta) {
|
||||
lv_obj_add_state(ta, LV_STATE_FOCUSED);
|
||||
lv_obj_invalidate(ta);
|
||||
}
|
||||
|
||||
static void closePopup() {
|
||||
if (s_popup) { lv_obj_delete_async(s_popup); s_popup = nullptr; }
|
||||
}
|
||||
@@ -160,7 +167,10 @@ static void onPopupPick(lv_event_t* e) {
|
||||
uint32_t id = lv_buttonmatrix_get_selected_button(m);
|
||||
if (id == LV_BUTTONMATRIX_BUTTON_NONE || !s_popup_kbd) return;
|
||||
lv_obj_t* ta = lv_keyboard_get_textarea(s_popup_kbd);
|
||||
if (ta) lv_textarea_add_text(ta, lv_buttonmatrix_get_button_text(m, id));
|
||||
if (ta) {
|
||||
lv_textarea_add_text(ta, lv_buttonmatrix_get_button_text(m, id));
|
||||
keepCursor(ta);
|
||||
}
|
||||
releaseShift(s_popup_kbd);
|
||||
closePopup();
|
||||
}
|
||||
@@ -248,6 +258,7 @@ static void onEvent(lv_event_t* e) {
|
||||
return;
|
||||
}
|
||||
lv_keyboard_def_event_cb(e); // type the character / backspace / OK
|
||||
if (lv_obj_t* ta = lv_keyboard_get_textarea(kbd)) keepCursor(ta);
|
||||
if (strcmp(t, KB_BS) != 0) releaseShift(kbd);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
// The quick panel, as a phone's: pulled down from the status bar (or a tap
|
||||
// on it), over any screen. Tiles that switch at a tap -- Bluetooth, WiFi,
|
||||
// GPS, sound, the trail, live share -- the advert, the lock, and the
|
||||
// brightness under them. Holding a tile opens its settings. Swiped up, a tap
|
||||
// under it, the side button or another screen puts it away. ui-new has the
|
||||
// brightness under them. Holding a tile opens its settings. The tiles are one
|
||||
// row that scrolls sideways. Swiped up, a tap on the status bar, the side
|
||||
// button or another screen puts it away; the screen under it stays live (no
|
||||
// dimming layer: blending a full-screen fill into every frame of the slide
|
||||
// was what made it stutter). 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.
|
||||
@@ -11,9 +14,8 @@
|
||||
namespace qpanel {
|
||||
|
||||
enum : uint8_t { T_BT, T_WIFI, T_GPS, T_SOUND, T_ADVERT, T_TRAIL, T_SHARE, T_LOCK, T_COUNT };
|
||||
static const int COLS = 4;
|
||||
static const int VISIBLE = 4; // tiles in view; the rest scroll in (a half tile peeks)
|
||||
|
||||
static lv_obj_t* s_dim = nullptr; // the screen under it, darkened; a tap there closes
|
||||
static lv_obj_t* s_panel = nullptr;
|
||||
static lv_obj_t* s_tile[T_COUNT];
|
||||
static lv_obj_t* s_icon[T_COUNT];
|
||||
@@ -24,18 +26,16 @@ static bool s_open = false; // down, or on its way down
|
||||
static bool s_drag = false; // following a finger from the status bar
|
||||
static int32_t s_y0 = 0;
|
||||
|
||||
// Its place: 0 down, -s_h away under the status bar; the dim with it.
|
||||
// Its place: 0 down, -s_h away under the status bar.
|
||||
static void place(int32_t ty) {
|
||||
if (ty > 0) ty = 0;
|
||||
if (ty < -s_h) ty = -s_h;
|
||||
lv_obj_set_style_translate_y(s_panel, ty, 0);
|
||||
lv_obj_set_style_bg_opa(s_dim, (lv_opa_t)(LV_OPA_50 * (s_h + ty) / s_h), 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);
|
||||
lv_obj_add_flag(s_dim, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
static void slide(int32_t to, bool away) {
|
||||
lv_anim_delete(s_panel, NULL);
|
||||
@@ -47,19 +47,23 @@ static void onTile(lv_event_t* e) {
|
||||
if (!s_open) return; // a swipe up that began on it: the panel is going
|
||||
s_ui->quickPanelTile((int)(uintptr_t)lv_event_get_user_data(e), lv_event_get_code(e) == LV_EVENT_LONG_PRESSED);
|
||||
}
|
||||
static void onDim(lv_event_t* e) { (void)e; s_ui->quickPanelClose(true); }
|
||||
static void onPanelGesture(lv_event_t* e) {
|
||||
(void)e;
|
||||
if (lv_indev_get_gesture_dir(lv_indev_active()) == LV_DIR_TOP) s_ui->quickPanelClose(true);
|
||||
}
|
||||
static void onBrightness(lv_event_t* e) {
|
||||
lv_obj_t* sl = (lv_obj_t*)lv_event_get_target(e);
|
||||
s_ui->setBrightnessPct((uint8_t)lv_slider_get_value(sl), lv_event_get_code(e) == LV_EVENT_RELEASED);
|
||||
static int32_t s_last = -1; // the backlight follows the knob, not every event
|
||||
const int32_t v = lv_slider_get_value(sl);
|
||||
const bool done = lv_event_get_code(e) == LV_EVENT_RELEASED;
|
||||
if (v == s_last && !done) return;
|
||||
s_last = v;
|
||||
s_ui->setBrightnessPct((uint8_t)v, done);
|
||||
}
|
||||
|
||||
static lv_obj_t* tile(lv_obj_t* parent, int t, int w) {
|
||||
lv_obj_t* b = lv_button_create(parent);
|
||||
lv_obj_set_size(b, w, 52);
|
||||
lv_obj_set_size(b, w, 56);
|
||||
lv_obj_set_style_pad_all(b, 2, 0);
|
||||
lv_obj_set_style_radius(b, theme::RADIUS, 0);
|
||||
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||
@@ -70,6 +74,7 @@ static lv_obj_t* tile(lv_obj_t* parent, int t, int w) {
|
||||
s_cap[t] = label(b, "", THEME_FONT_SMALL, theme::TEXT);
|
||||
lv_label_set_long_mode(s_cap[t], LV_LABEL_LONG_DOT);
|
||||
lv_obj_set_style_text_align(s_cap[t], LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_anim_duration(s_cap[t], 0, 0);
|
||||
lv_obj_set_width(s_cap[t], w - 4);
|
||||
lv_obj_align(s_cap[t], LV_ALIGN_BOTTOM_MID, 0, -4);
|
||||
return b;
|
||||
@@ -119,13 +124,6 @@ static void onStatusBarTouch(lv_event_t* e) {
|
||||
// the toast and status bar (which stay over it).
|
||||
void UITask::quickPanelBuild() {
|
||||
using namespace qpanel;
|
||||
s_dim = lv_obj_create(lv_layer_top());
|
||||
lv_obj_remove_style_all(s_dim);
|
||||
lv_obj_set_size(s_dim, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_bg_color(s_dim, lv_color_hex(0x000000), 0);
|
||||
lv_obj_add_flag(s_dim, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_add_event_cb(s_dim, onDim, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
const int32_t w = lv_display_get_horizontal_resolution(NULL);
|
||||
s_panel = lv_obj_create(lv_layer_top());
|
||||
styleOpaque(s_panel, theme::BG);
|
||||
@@ -145,11 +143,19 @@ void UITask::quickPanelBuild() {
|
||||
lv_obj_remove_flag(s_panel, LV_OBJ_FLAG_GESTURE_BUBBLE); // a swipe on it (or a tile) is its own
|
||||
lv_obj_add_event_cb(s_panel, onPanelGesture, LV_EVENT_GESTURE, NULL);
|
||||
|
||||
lv_obj_t* grid = flexBox(s_panel, LV_FLEX_FLOW_ROW_WRAP);
|
||||
lv_obj_set_width(grid, LV_PCT(100));
|
||||
// One row, scrolling sideways in whole tiles: three and a half in view
|
||||
// is what tells it scrolls. Text and icons get room, and a flick stops
|
||||
// on a tile instead of drifting.
|
||||
lv_obj_t* grid = flexBox(s_panel, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_size(grid, w - 2 * theme::PAD, 56);
|
||||
lv_obj_add_flag(grid, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_scroll_dir(grid, LV_DIR_HOR);
|
||||
lv_obj_set_scroll_snap_x(grid, LV_SCROLL_SNAP_START);
|
||||
lv_obj_set_scrollbar_mode(grid, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_obj_remove_flag(grid, LV_OBJ_FLAG_SCROLL_ELASTIC);
|
||||
lv_obj_add_flag(grid, LV_OBJ_FLAG_SCROLL_ONE);
|
||||
lv_obj_set_style_pad_column(grid, theme::GAP, 0);
|
||||
lv_obj_set_style_pad_row(grid, theme::GAP, 0);
|
||||
const int tw = (w - 2 * theme::PAD - (COLS - 1) * theme::GAP) / COLS;
|
||||
const int tw = (w - 2 * theme::PAD - VISIBLE * theme::GAP) / (VISIBLE - 1) - 6; // ~3.5 tiles in view
|
||||
for (int t = 0; t < T_COUNT; t++) s_tile[t] = tile(grid, t, tw);
|
||||
|
||||
lv_obj_t* row = flexBox(s_panel, LV_FLEX_FLOW_ROW);
|
||||
@@ -164,6 +170,9 @@ void UITask::quickPanelBuild() {
|
||||
lv_obj_set_flex_grow(s_slider, 1);
|
||||
lv_obj_set_style_margin_right(s_slider, 8, 0);
|
||||
lv_obj_set_ext_click_area(s_slider, 14);
|
||||
lv_obj_set_style_anim_duration(s_slider, 0, 0); // the knob is where the finger is, not on its way
|
||||
lv_obj_set_style_shadow_width(s_slider, 0, LV_PART_KNOB);
|
||||
lv_obj_remove_flag(s_slider, LV_OBJ_FLAG_SCROLL_CHAIN);
|
||||
lv_obj_remove_flag(s_slider, LV_OBJ_FLAG_GESTURE_BUBBLE); // a drag along it isn't a swipe up
|
||||
lv_obj_set_style_bg_color(s_slider, lv_color_hex(theme::mix(theme::ACCENT, theme::SURFACE, 20)), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(s_slider, LV_OPA_COVER, LV_PART_MAIN);
|
||||
@@ -177,7 +186,6 @@ void UITask::quickPanelBuild() {
|
||||
lv_obj_set_style_bg_color(grip, lv_color_hex(theme::SURFACE_2), 0);
|
||||
lv_obj_set_style_bg_opa(grip, LV_OPA_COVER, 0);
|
||||
|
||||
lv_obj_add_flag(s_dim, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(s_panel, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_move_foreground(_toast);
|
||||
lv_obj_move_foreground(s_status_bar);
|
||||
@@ -192,7 +200,6 @@ bool UITask::quickPanelBegin() {
|
||||
pickerClose();
|
||||
quickPanelRefresh();
|
||||
lv_anim_delete(s_panel, NULL);
|
||||
lv_obj_remove_flag(s_dim, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_remove_flag(s_panel, LV_OBJ_FLAG_HIDDEN);
|
||||
layoutNow(s_panel);
|
||||
s_h = lv_obj_get_height(s_panel) + theme::STATUS_H;
|
||||
|
||||
@@ -185,7 +185,7 @@ private:
|
||||
if (g->hdop > 0 && g->hdop < 99) snprintf(a, sizeof(a), "%.1f", g->hdop); else strcpy(a, "-");
|
||||
row(d, f, rsv, "HDOP", a);
|
||||
if (g->ttff_ms) snprintf(a, sizeof(a), "%lu s", (unsigned long)(g->ttff_ms / 1000));
|
||||
else if (g->start_ms) {
|
||||
else if (on && g->start_ms) {
|
||||
const unsigned long s = (millis() - g->start_ms) / 1000;
|
||||
if (!Features::IS_EINK) snprintf(a, sizeof(a), "%lu s", s);
|
||||
else if (s < 60) strcpy(a, "<1 min"); // seconds would refresh the panel every second
|
||||
|
||||
@@ -104,6 +104,9 @@ public :
|
||||
}
|
||||
|
||||
void stop() override {
|
||||
#ifdef GPS_SKYVIEW
|
||||
_sky.reset(); // a receiver that is off is not searching: stop the TTFF clock
|
||||
#endif
|
||||
if (_pin_en != -1) {
|
||||
digitalWrite(_pin_en, !GPS_EN_ACTIVE);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user