diff --git a/src/textual/widgets/_radio_set.py b/src/textual/widgets/_radio_set.py index 8599c178c7..a05f1966d2 100644 --- a/src/textual/widgets/_radio_set.py +++ b/src/textual/widgets/_radio_set.py @@ -2,8 +2,11 @@ from __future__ import annotations +from typing import ClassVar + import rich.repr +from ..binding import Binding, BindingType from ..containers import Container from ..events import Mount from ..message import Message @@ -35,6 +38,21 @@ class RadioSet(Container): } """ + BINDINGS: ClassVar[list[BindingType]] = [ + Binding("down,right", "next_button", "", show=False), + Binding("shift+tab", "breakout_previous", "", show=False), + Binding("tab", "breakout_next", "", show=False), + Binding("up,left", "previous_button", "", show=False), + ] + """ + | Key(s) | Description | + | :- | :- | + | left, up | Select the previous radio button in the set. | + | right, down | Select the next radio button in the set. | + | shift+tab | Move focus to the previous focusable widget relative to the set. | + | tab | Move focus to the next focusable widget relative to the set. | + """ + @rich.repr.auto class Changed(Message, bubble=True): """Posted when the pressed button in the set changes. @@ -155,3 +173,37 @@ def pressed_index(self) -> int: if self._pressed_button is not None else -1 ) + + def action_previous_button(self) -> None: + """Navigate to the previous button in the set. + + Note that this will wrap around to the end if at the start. + """ + if self.children: + if self.screen.focused == self.children[0]: + self.screen.set_focus(self.children[-1]) + else: + self.screen.focus_previous() + + def action_next_button(self) -> None: + """Navigate to the next button in the set. + + Note that this will wrap around to the start if at the end. + """ + if self.children: + if self.screen.focused == self.children[-1]: + self.screen.set_focus(self.children[0]) + else: + self.screen.focus_next() + + def action_breakout_previous(self) -> None: + """Break out of the radio set to the previous widget in the focus chain.""" + if self.children: + self.screen.set_focus(self.children[0]) + self.screen.focus_previous() + + def action_breakout_next(self) -> None: + """Break out of the radio set to the next widget in the focus chain.""" + if self.children: + self.screen.set_focus(self.children[-1]) + self.screen.focus_next()