mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-01 02:11:57 +00:00
refactor(ui-lvgl): centerRow and pillButton helpers; document the shared text-entry popup and bubble row
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VeBrxKyHHxWsmttVkUdBrj
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -238,6 +238,8 @@ filled while selected), `drawDisclosure` (▸ / ▾ on an accordion section),
|
||||
`drawPageDots`, `drawLoadingDots` (the waiting animation), `drawSignalBars`
|
||||
(SNR as four bars).
|
||||
|
||||
`MessagesScreen`'s history lists draw each message through one `drawHeadedBubble()` (sender, a `BubbleMark` -- delivery glyph or hop count -- and age over the body; `expand` wraps the body, otherwise the selected row marquees): a new list of chat-like rows passes it the row's pieces instead of laying out its own bubble.
|
||||
|
||||
`FullscreenMsgView::wrapLines()` is a standalone pixel-accurate word-wrapper
|
||||
(O(n), variable-width-font aware) reusable by any multi-line layout; it writes
|
||||
into the shared `s_wrap_trans` / `s_wrap_lines` scratch (single-threaded render,
|
||||
|
||||
@@ -291,17 +291,6 @@ static lv_obj_t* adminPopupButton(lv_obj_t* parent, const char* text, uint8_t ac
|
||||
return b;
|
||||
}
|
||||
|
||||
static lv_obj_t* adminRowBox(lv_obj_t* parent) {
|
||||
lv_obj_t* r = lv_obj_create(parent);
|
||||
styleSurface(r, theme::BG);
|
||||
lv_obj_remove_flag(r, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_size(r, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_flex_flow(r, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(r, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_style_pad_column(r, theme::GAP, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
// A typed value arrived: its editor.
|
||||
void UITask::adminValuePopup() {
|
||||
using namespace adminview;
|
||||
@@ -317,7 +306,7 @@ void UITask::adminValuePopup() {
|
||||
lv_obj_t* panel = navPopupPanel(f->label, false);
|
||||
s_val_lbl = s_choice = nullptr;
|
||||
if (f->kind == admin::K_ONOFF) {
|
||||
lv_obj_t* r = adminRowBox(panel);
|
||||
lv_obj_t* r = centerRow(panel);
|
||||
label(r, "Off", THEME_FONT_BODY, theme::TEXT_MUTED);
|
||||
lv_obj_t* sw = lv_switch_create(r);
|
||||
lv_obj_set_size(sw, 56, 28);
|
||||
@@ -325,7 +314,7 @@ void UITask::adminValuePopup() {
|
||||
lv_obj_add_event_cb(sw, onAdminValue, LV_EVENT_VALUE_CHANGED, (void*)(uintptr_t)V_TOGGLE);
|
||||
label(r, "On", THEME_FONT_BODY, theme::TEXT_MUTED);
|
||||
} else if (f->kind == admin::K_NUMBER) {
|
||||
lv_obj_t* r = adminRowBox(panel);
|
||||
lv_obj_t* r = centerRow(panel);
|
||||
adminPopupButton(r, LV_SYMBOL_MINUS, V_MINUS, false);
|
||||
s_val_lbl = label(r, "", THEME_FONT_LARGE, theme::TEXT);
|
||||
lv_obj_set_width(s_val_lbl, 80);
|
||||
@@ -342,7 +331,7 @@ void UITask::adminValuePopup() {
|
||||
if (f->isRadio()) {
|
||||
noteLabel(panel, "A mismatch cuts the node off.");
|
||||
}
|
||||
lv_obj_t* r = adminRowBox(panel);
|
||||
lv_obj_t* r = centerRow(panel);
|
||||
adminPopupButton(r, LV_SYMBOL_OK " Save", V_SAVE, true);
|
||||
}
|
||||
|
||||
@@ -388,7 +377,7 @@ void UITask::adminReplyPopup(const char* text) {
|
||||
lv_obj_set_scrollbar_mode(box, LV_SCROLLBAR_MODE_ACTIVE);
|
||||
}
|
||||
noteLabel(box, text[0] ? text : "(empty)", THEME_FONT_BODY, theme::TEXT);
|
||||
lv_obj_t* r = adminRowBox(panel);
|
||||
lv_obj_t* r = centerRow(panel);
|
||||
adminPopupButton(r, "OK", adminview::V_CLOSE, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -248,17 +248,6 @@ static lv_obj_t* wheel(lv_obj_t* parent, uint8_t n, int sel, lv_event_cb_t cb, u
|
||||
|
||||
static lv_obj_t* colon(lv_obj_t* parent) { return label(parent, ":", THEME_FONT_LARGE, theme::TEXT_MUTED); }
|
||||
|
||||
static lv_obj_t* row(lv_obj_t* parent) {
|
||||
lv_obj_t* r = lv_obj_create(parent);
|
||||
styleSurface(r, theme::BG);
|
||||
lv_obj_remove_flag(r, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_size(r, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_flex_flow(r, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(r, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_style_pad_column(r, theme::GAP, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace clockview
|
||||
|
||||
static void onOpenClock(lv_event_t* e) { (void)e; s_ui->showClock(); }
|
||||
@@ -304,7 +293,7 @@ void UITask::buildClock() {
|
||||
s_big = s_go_lbl = s_alarm_sw = s_cal = nullptr;
|
||||
|
||||
// Tabs
|
||||
lv_obj_t* tabs = row(body);
|
||||
lv_obj_t* tabs = centerRow(body);
|
||||
static const char* const NAMES[TAB_COUNT] = { "Alarm", "Timer", "Stopwatch", "Calendar" };
|
||||
for (int t = 0; t < TAB_COUNT; t++) {
|
||||
lv_obj_t* b = lv_button_create(tabs);
|
||||
@@ -318,7 +307,7 @@ void UITask::buildClock() {
|
||||
}
|
||||
|
||||
if (s_tab == TAB_ALARM) {
|
||||
lv_obj_t* r = row(body);
|
||||
lv_obj_t* r = centerRow(body);
|
||||
wheel(r, 24, _prefs->alarm_hour % 24, onAlarmWheel, 0);
|
||||
colon(r);
|
||||
wheel(r, 60, _prefs->alarm_min % 60, onAlarmWheel, 1);
|
||||
@@ -384,7 +373,7 @@ void UITask::buildClock() {
|
||||
lv_obj_set_style_text_align(s_big, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_pad_ver(s_big, 18, 0);
|
||||
} else {
|
||||
lv_obj_t* r = row(body);
|
||||
lv_obj_t* r = centerRow(body);
|
||||
wheel(r, 24, s_timer_h, onTimerWheel, 0);
|
||||
colon(r);
|
||||
wheel(r, 60, s_timer_m, onTimerWheel, 1);
|
||||
@@ -398,7 +387,7 @@ void UITask::buildClock() {
|
||||
lv_obj_set_style_pad_ver(s_big, 18, 0);
|
||||
}
|
||||
|
||||
lv_obj_t* acts = row(body);
|
||||
lv_obj_t* acts = centerRow(body);
|
||||
lv_obj_t* go = lv_button_create(acts);
|
||||
lv_obj_set_size(go, 150, 40);
|
||||
lv_obj_set_style_shadow_width(go, 0, 0);
|
||||
|
||||
@@ -573,6 +573,34 @@ static lv_obj_t* flexBox(lv_obj_t* parent, lv_flex_flow_t flow) {
|
||||
return b;
|
||||
}
|
||||
|
||||
// A full-width row of centred items that grows with them (button rows in
|
||||
// popups, the clock's tabs and actions).
|
||||
static lv_obj_t* centerRow(lv_obj_t* parent) {
|
||||
lv_obj_t* r = lv_obj_create(parent);
|
||||
styleSurface(r, theme::BG);
|
||||
lv_obj_remove_flag(r, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_size(r, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_flex_flow(r, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(r, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_style_pad_column(r, theme::GAP, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
// A small pill button with a label, right-aligned in its parent row.
|
||||
static lv_obj_t* pillButton(lv_obj_t* row, const char* text, uint32_t bg, lv_event_cb_t cb, uintptr_t user) {
|
||||
lv_obj_t* b = lv_button_create(row);
|
||||
lv_obj_set_size(b, LV_SIZE_CONTENT, 24);
|
||||
lv_obj_set_style_pad_hor(b, 10, 0);
|
||||
lv_obj_set_style_pad_ver(b, 0, 0);
|
||||
lv_obj_set_style_radius(b, LV_RADIUS_CIRCLE, 0);
|
||||
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||
lv_obj_set_style_bg_color(b, lv_color_hex(bg), 0);
|
||||
lv_obj_align(b, LV_ALIGN_RIGHT_MID, -2, 0);
|
||||
lv_obj_add_event_cb(b, cb, LV_EVENT_CLICKED, (void*)user);
|
||||
lv_obj_center(label(b, text, THEME_FONT_SMALL, theme::TEXT));
|
||||
return b;
|
||||
}
|
||||
|
||||
// ── Settings kit ──
|
||||
// Every settings page is built from the same few pieces: group() -- a section
|
||||
// title and the card its rows sit on, hairlines between them -- and rows on
|
||||
@@ -3152,16 +3180,7 @@ static void chatSection(lv_obj_t* parent, const char* text, int fold, int unread
|
||||
lv_obj_align_to(n, t, LV_ALIGN_OUT_RIGHT_MID, 8, 0);
|
||||
}
|
||||
if (filter < 0 || folded) return;
|
||||
lv_obj_t* b = lv_button_create(row);
|
||||
lv_obj_set_size(b, LV_SIZE_CONTENT, 24);
|
||||
lv_obj_set_style_pad_hor(b, 10, 0);
|
||||
lv_obj_set_style_pad_ver(b, 0, 0);
|
||||
lv_obj_set_style_radius(b, LV_RADIUS_CIRCLE, 0);
|
||||
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||
lv_obj_set_style_bg_color(b, lv_color_hex(fav_only ? theme::ACCENT_DIM : theme::SURFACE), 0);
|
||||
lv_obj_align(b, LV_ALIGN_RIGHT_MID, -2, 0);
|
||||
lv_obj_add_event_cb(b, onChatFilter, LV_EVENT_CLICKED, (void*)(uintptr_t)filter);
|
||||
lv_obj_center(label(b, fav_only ? UI_SYMBOL_STAR " Fav" : "All", THEME_FONT_SMALL, theme::TEXT));
|
||||
pillButton(row, fav_only ? UI_SYMBOL_STAR " Fav" : "All", fav_only ? theme::ACCENT_DIM : theme::SURFACE, onChatFilter, filter);
|
||||
}
|
||||
|
||||
// Section title with an "All" / "★ Fav" pill on the right that flips the
|
||||
@@ -3172,16 +3191,7 @@ static void sectionWithFilter(lv_obj_t* parent, const char* text, bool fav_only,
|
||||
lv_obj_remove_flag(row, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_size(row, LV_PCT(100), 26);
|
||||
lv_obj_align(label(row, text, THEME_FONT_SMALL, theme::TEXT_MUTED), LV_ALIGN_BOTTOM_LEFT, 0, -2);
|
||||
lv_obj_t* b = lv_button_create(row);
|
||||
lv_obj_set_size(b, LV_SIZE_CONTENT, 24);
|
||||
lv_obj_set_style_pad_hor(b, 10, 0);
|
||||
lv_obj_set_style_pad_ver(b, 0, 0);
|
||||
lv_obj_set_style_radius(b, LV_RADIUS_CIRCLE, 0);
|
||||
lv_obj_set_style_shadow_width(b, 0, 0);
|
||||
lv_obj_set_style_bg_color(b, lv_color_hex(fav_only ? theme::ACCENT_DIM : theme::SURFACE), 0);
|
||||
lv_obj_align(b, LV_ALIGN_RIGHT_MID, -2, 0);
|
||||
lv_obj_add_event_cb(b, onChatFilter, LV_EVENT_CLICKED, (void*)(uintptr_t)which);
|
||||
lv_obj_center(label(b, fav_only ? UI_SYMBOL_STAR " Fav" : "All", THEME_FONT_SMALL, theme::TEXT));
|
||||
pillButton(row, fav_only ? UI_SYMBOL_STAR " Fav" : "All", fav_only ? theme::ACCENT_DIM : theme::SURFACE, onChatFilter, which);
|
||||
}
|
||||
|
||||
void UITask::showChats() {
|
||||
|
||||
Reference in New Issue
Block a user