From 44b840dfffa46573ef789fe54accc24020825614 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Martineau Date: Wed, 30 Sep 2026 21:10:32 -0400 Subject: [PATCH] A Cardputer dialog runs from the header to the lane, two rows taller The row of air a floating box keeps above and below is a platform setting now, like its side gutters. At 24 rows it is what makes a box read as floating; at the Cardputer's 14 it was a fifth of what a dialog could show, and the gutters already say it floats, so its dialogs get ten rows between their borders instead of eight. Co-Authored-By: Claude Opus 5.5 (1M context) --- meshterm/platforms.py | 10 ++++++++++ meshterm/ui/tui/frame.py | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/meshterm/platforms.py b/meshterm/platforms.py index c829957..dd3482c 100644 --- a/meshterm/platforms.py +++ b/meshterm/platforms.py @@ -64,6 +64,12 @@ class Platform: twelfth of the whole display, and it costs content: a packet card's reception row folds ``rssi`` onto a line of its own for want of two cells (JP, on-device, 2026-08-10). Two columns a side still reads as floating and buys them back. + dialog_row_margin: Rows a floating dialog leaves to the frame around it — the header + above and the footer below, which a dialog never covers, plus any blank row + between them and the box. One row of air above and below is what lets a box read + as floating on a 24-row terminal (4 in all); on the Cardputer's 14 rows those two + rows are a fifth of what a dialog could show, and its side gutters already say + it floats, so the box runs from the header to the lane (2). header_atoms: Which segments compose the persistent header, in the vocabulary ``"version"``, ``"device"``, ``"badges"``, ``"pulse"``, ``"battery"``. Wired into :func:`~meshterm.ui.menu._header` in P4; unconsumed until then. @@ -138,6 +144,7 @@ class Platform: frame_border: bool menu_icons: bool dialog_margin: int + dialog_row_margin: int header_atoms: tuple[str, ...] lane_deck: str width_reclaim: bool @@ -165,6 +172,7 @@ REGULAR = Platform( frame_border=True, menu_icons=True, dialog_margin=6, + dialog_row_margin=4, header_atoms=("version", "device", "badges", "pulse", "battery"), lane_deck="", width_reclaim=True, @@ -190,6 +198,7 @@ PICOCALC = Platform( frame_border=False, menu_icons=False, dialog_margin=4, + dialog_row_margin=4, # JP's call (2026-08-01, post-P7 review): the handheld's header brands the app — # "MeshTerm vX" — rather than naming the device/port (on a soldered radio the port # never changes), and the activity pulse takes whatever room remains. @@ -227,6 +236,7 @@ CARDPUTER = Platform( frame_border=False, menu_icons=False, dialog_margin=4, + dialog_row_margin=2, header_atoms=("version", "badges", "pulse", "battery"), lane_deck="cardputer", width_reclaim=False, diff --git a/meshterm/ui/tui/frame.py b/meshterm/ui/tui/frame.py index a4afcda..2145223 100644 --- a/meshterm/ui/tui/frame.py +++ b/meshterm/ui/tui/frame.py @@ -634,8 +634,11 @@ def _dialog_layout(screen: Screen, cols: int, rows: int) -> tuple[int, int, int, cap = min(cols - get_platform().dialog_margin, 100) natural = getattr(screen, "dialog_width", None) max_w = cap if natural is None else max(24, min(cap, screen.ratchet_width(natural))) - # Rows the box may spend between its borders — on body lines and breathing room alike. - budget = max(3, rows - 6) + # Rows the box may spend between its borders — on body lines and breathing room alike: + # the frame less the two borders and the rows it leaves to the frame around it (the + # header, the footer, and on a tall enough frame a row of air each side — see + # Platform.dialog_row_margin). + budget = max(3, rows - 2 - get_platform().dialog_row_margin) # Record the budget as the provisional viewport before the body renders, so a # dialog that windows a list inside itself (the path composer) can size to what # it may spend; the slice records the real, body-sized viewport afterwards.