Change RadioSet so it's less a container of widgets and more a widget

Initially we went with a RadioSet being a simple container of RadioButtons,
with the user navigating the RadioButtons like you would any other set of
widgets. This was fine but it became pretty clear pretty quickly that having
to tab through a non-trivial collection of buttons in a set to get to the
next widget wasn't ideal.

This commit, satisfying #2368, takes over the navigation of the buttons
within the container, makes the container itself a focusable widget, and
sets up some new bindings to allow a more natural and efficient interaction
with the set.
This commit is contained in:
Dave Pearson
2023-04-25 15:00:44 +01:00
parent a6a373161f
commit c45f9358ee
6 changed files with 214 additions and 169 deletions

View File

@@ -57,13 +57,10 @@ async def test_radioset_inner_navigation():
async with RadioSetApp().run_test() as pilot:
assert pilot.app.screen.focused is None
await pilot.press("tab")
assert (
pilot.app.screen.focused == pilot.app.query_one("#from_buttons").children[0]
)
for key, landing in (("down", 1), ("up", 0), ("right", 1), ("left", 0)):
await pilot.press(key)
await pilot.press(key, "enter")
assert (
pilot.app.screen.focused
pilot.app.query_one("#from_buttons", RadioSet).pressed_button
== pilot.app.query_one("#from_buttons").children[landing]
)
@@ -73,11 +70,11 @@ async def test_radioset_breakout_navigation():
async with RadioSetApp().run_test() as pilot:
assert pilot.app.screen.focused is None
await pilot.press("tab")
assert pilot.app.screen.focused.parent is pilot.app.query_one("#from_buttons")
assert pilot.app.screen.focused is pilot.app.query_one("#from_buttons")
await pilot.press("tab")
assert pilot.app.screen.focused.parent is pilot.app.query_one("#from_strings")
assert pilot.app.screen.focused is pilot.app.query_one("#from_strings")
await pilot.press("shift+tab")
assert pilot.app.screen.focused.parent is pilot.app.query_one("#from_buttons")
assert pilot.app.screen.focused is pilot.app.query_one("#from_buttons")
class BadRadioSetApp(App[None]):