diff options
| author | blasty <blasty@local> | 2026-08-07 23:24:12 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-08-07 23:24:12 +0200 |
| commit | 5ccbc09ce7d43d226683589e8141f9e216f2f176 (patch) | |
| tree | 86e83b19c322b1effd4fce42ade3c9f3fbb9cb1e /tests | |
| parent | Ctrl+F: search the whole database, by text or by bytes (diff) | |
| download | ida-tui-5ccbc09ce7d43d226683589e8141f9e216f2f176.tar.gz ida-tui-5ccbc09ce7d43d226683589e8141f9e216f2f176.tar.xz ida-tui-5ccbc09ce7d43d226683589e8141f9e216f2f176.zip | |
Centre modals with a rule about modals, not a list of them
SearchPalette opened pinned to the top of the screen: the CSS named the
screens that centre (`SymbolPalette, StringsPalette, ProjectPalette, …`)
and a new dialog is not on a list nobody remembers to edit. The comment
sitting above that rule — "every #pal-box palette centres, not just the
symbol one" — was the *first* time this happened.
`ModalScreen { align: center middle; }` matches subclasses, so every
dialog inherits it and the next one is centred for free; the eight
per-screen rules that only repeated it are gone. Textual's own Ctrl+P
CommandPalette is a ModalScreen too and wants its stock top alignment, so
it opts out in one visible line rather than by omission.
The `modal_centering` scenario checks both halves: that centring is
expressed as a rule, and that it actually reaches a dialog's laid-out
region (above/below and left/right within a cell).
894 passed, 0 failed.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_scenarios.py | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py index 6d95564..37ec017 100644 --- a/tests/test_scenarios.py +++ b/tests/test_scenarios.py @@ -1094,6 +1094,51 @@ async def s_structs(c: Ctx): c.check("Esc closes the struct editor", not isinstance(app.screen, StructEditor)) +@scenario("modal_centering") +async def s_modal_centering(c: Ctx): + """Every dialog we define is centred, without anyone maintaining a list. + + The CSS used to name the screens that centre, so a new palette shipped + pinned to the top of the screen (twice). The rule is on ModalScreen now; + this fails if a modal ever opts out by accident, which the naked eye only + catches when the dialog is already in front of a user. + """ + from textual.screen import ModalScreen + + import idatui.app as A + + ours = sorted( + (n for n, v in vars(A).items() + if isinstance(v, type) and issubclass(v, ModalScreen) + and v is not ModalScreen and v.__module__ == A.__name__), + key=str) + c.check("found the app's modal screens", len(ours) >= 8, f"{ours}") + styles = A.IdaTui.CSS + c.check("centring is a rule about modals, not a list of them", + "ModalScreen { align: center middle; }" in styles, + "the ModalScreen rule is gone") + # And prove it REACHES a dialog, rather than just being present in the text. + await c.press("ctrl+f") + opened = await c.wait(lambda: isinstance(c.app.screen, A.SearchPalette), 10) + if not opened: + c.check("the search palette opened", False, + f"screen={type(c.app.screen).__name__}") + return + scr = c.app.screen + await c.wait(lambda: scr.query_one("#pal-box").region.height > 0, 5) + box = scr.query_one("#pal-box").region + above, below = box.y, c.app.size.height - (box.y + box.height) + c.check("the search palette is vertically centred", + box.height > 0 and abs(above - below) <= 1, + f"box={box} screen={c.app.size} above={above} below={below}") + left = box.x + right = c.app.size.width - (box.x + box.width) + c.check("and horizontally centred", abs(left - right) <= 1, + f"left={left} right={right}") + await c.press("escape") + await c.wait(lambda: not isinstance(c.app.screen, A.SearchPalette), 5) + + @scenario("db_search") async def s_db_search(c: Ctx): """Ctrl+F: search the whole database, by disassembly text or by bytes.""" |
