bauiv1lib.tabs

UI functionality for creating tab style buttons.

 1# Released under the MIT License. See LICENSE for details.
 2#
 3"""UI functionality for creating tab style buttons."""
 4
 5from __future__ import annotations
 6
 7from dataclasses import dataclass
 8from typing import TYPE_CHECKING, TypeVar, Generic
 9
10import bauiv1 as bui
11
12if TYPE_CHECKING:
13    from typing import Any, Callable
14
15
16@dataclass
17class Tab:
18    """Info for an individual tab in a TabRow"""
19
20    button: bui.Widget
21    position: tuple[float, float]
22    size: tuple[float, float]
23
24
25T = TypeVar('T')
26
27
28class TabRow(Generic[T]):
29    """Encapsulates a row of tab-styled buttons.
30
31    Tabs are indexed by id which is an arbitrary user-provided type.
32    """
33
34    def __init__(
35        self,
36        parent: bui.Widget,
37        tabdefs: list[tuple[T, bui.Lstr]],
38        pos: tuple[float, float],
39        size: tuple[float, float],
40        *,
41        on_select_call: Callable[[T], None] | None = None,
42    ) -> None:
43        if not tabdefs:
44            raise ValueError('At least one tab def is required')
45        self.tabs: dict[T, Tab] = {}
46        tab_pos_v = pos[1]
47        tab_button_width = float(size[0]) / len(tabdefs)
48        tab_spacing = (250.0 - tab_button_width) * 0.06
49        h = pos[0]
50        for tab_id, tab_label in tabdefs:
51            pos = (h + tab_spacing * 0.5, tab_pos_v)
52            size = (tab_button_width - tab_spacing, 50.0)
53            btn = bui.buttonwidget(
54                parent=parent,
55                position=pos,
56                autoselect=True,
57                button_type='tab',
58                size=size,
59                label=tab_label,
60                enable_sound=False,
61                on_activate_call=bui.Call(
62                    self._tick_and_call, on_select_call, tab_id
63                ),
64            )
65            h += tab_button_width
66            self.tabs[tab_id] = Tab(button=btn, position=pos, size=size)
67
68    def update_appearance(self, selected_tab_id: T) -> None:
69        """Update appearances to make the provided tab appear selected."""
70        for tab_id, tab in self.tabs.items():
71            if tab_id == selected_tab_id:
72                bui.buttonwidget(
73                    edit=tab.button,
74                    color=(0.5, 0.4, 0.93),
75                    textcolor=(0.85, 0.75, 0.95),
76                )  # lit
77            else:
78                bui.buttonwidget(
79                    edit=tab.button,
80                    color=(0.52, 0.48, 0.63),
81                    textcolor=(0.65, 0.6, 0.7),
82                )  # unlit
83
84    def _tick_and_call(
85        self, call: Callable[[Any], None] | None, arg: Any
86    ) -> None:
87        bui.getsound('click01').play()
88        if call is not None:
89            call(arg)
@dataclass
class Tab:
17@dataclass
18class Tab:
19    """Info for an individual tab in a TabRow"""
20
21    button: bui.Widget
22    position: tuple[float, float]
23    size: tuple[float, float]

Info for an individual tab in a TabRow

Tab( button: _bauiv1.Widget, position: tuple[float, float], size: tuple[float, float])
button: _bauiv1.Widget
position: tuple[float, float]
size: tuple[float, float]
class TabRow(typing.Generic[~T]):
29class TabRow(Generic[T]):
30    """Encapsulates a row of tab-styled buttons.
31
32    Tabs are indexed by id which is an arbitrary user-provided type.
33    """
34
35    def __init__(
36        self,
37        parent: bui.Widget,
38        tabdefs: list[tuple[T, bui.Lstr]],
39        pos: tuple[float, float],
40        size: tuple[float, float],
41        *,
42        on_select_call: Callable[[T], None] | None = None,
43    ) -> None:
44        if not tabdefs:
45            raise ValueError('At least one tab def is required')
46        self.tabs: dict[T, Tab] = {}
47        tab_pos_v = pos[1]
48        tab_button_width = float(size[0]) / len(tabdefs)
49        tab_spacing = (250.0 - tab_button_width) * 0.06
50        h = pos[0]
51        for tab_id, tab_label in tabdefs:
52            pos = (h + tab_spacing * 0.5, tab_pos_v)
53            size = (tab_button_width - tab_spacing, 50.0)
54            btn = bui.buttonwidget(
55                parent=parent,
56                position=pos,
57                autoselect=True,
58                button_type='tab',
59                size=size,
60                label=tab_label,
61                enable_sound=False,
62                on_activate_call=bui.Call(
63                    self._tick_and_call, on_select_call, tab_id
64                ),
65            )
66            h += tab_button_width
67            self.tabs[tab_id] = Tab(button=btn, position=pos, size=size)
68
69    def update_appearance(self, selected_tab_id: T) -> None:
70        """Update appearances to make the provided tab appear selected."""
71        for tab_id, tab in self.tabs.items():
72            if tab_id == selected_tab_id:
73                bui.buttonwidget(
74                    edit=tab.button,
75                    color=(0.5, 0.4, 0.93),
76                    textcolor=(0.85, 0.75, 0.95),
77                )  # lit
78            else:
79                bui.buttonwidget(
80                    edit=tab.button,
81                    color=(0.52, 0.48, 0.63),
82                    textcolor=(0.65, 0.6, 0.7),
83                )  # unlit
84
85    def _tick_and_call(
86        self, call: Callable[[Any], None] | None, arg: Any
87    ) -> None:
88        bui.getsound('click01').play()
89        if call is not None:
90            call(arg)

Encapsulates a row of tab-styled buttons.

Tabs are indexed by id which is an arbitrary user-provided type.

TabRow( parent: _bauiv1.Widget, tabdefs: list[tuple[~T, babase.Lstr]], pos: tuple[float, float], size: tuple[float, float], *, on_select_call: Optional[Callable[[~T], NoneType]] = None)
35    def __init__(
36        self,
37        parent: bui.Widget,
38        tabdefs: list[tuple[T, bui.Lstr]],
39        pos: tuple[float, float],
40        size: tuple[float, float],
41        *,
42        on_select_call: Callable[[T], None] | None = None,
43    ) -> None:
44        if not tabdefs:
45            raise ValueError('At least one tab def is required')
46        self.tabs: dict[T, Tab] = {}
47        tab_pos_v = pos[1]
48        tab_button_width = float(size[0]) / len(tabdefs)
49        tab_spacing = (250.0 - tab_button_width) * 0.06
50        h = pos[0]
51        for tab_id, tab_label in tabdefs:
52            pos = (h + tab_spacing * 0.5, tab_pos_v)
53            size = (tab_button_width - tab_spacing, 50.0)
54            btn = bui.buttonwidget(
55                parent=parent,
56                position=pos,
57                autoselect=True,
58                button_type='tab',
59                size=size,
60                label=tab_label,
61                enable_sound=False,
62                on_activate_call=bui.Call(
63                    self._tick_and_call, on_select_call, tab_id
64                ),
65            )
66            h += tab_button_width
67            self.tabs[tab_id] = Tab(button=btn, position=pos, size=size)
tabs: dict[~T, Tab]
def update_appearance(self, selected_tab_id: ~T) -> None:
69    def update_appearance(self, selected_tab_id: T) -> None:
70        """Update appearances to make the provided tab appear selected."""
71        for tab_id, tab in self.tabs.items():
72            if tab_id == selected_tab_id:
73                bui.buttonwidget(
74                    edit=tab.button,
75                    color=(0.5, 0.4, 0.93),
76                    textcolor=(0.85, 0.75, 0.95),
77                )  # lit
78            else:
79                bui.buttonwidget(
80                    edit=tab.button,
81                    color=(0.52, 0.48, 0.63),
82                    textcolor=(0.65, 0.6, 0.7),
83                )  # unlit

Update appearances to make the provided tab appear selected.