[MouseFox logo]
The MouseFox Project
Join The Community Discord Server
[Discord logo]
Edit on GitHub

kvex.widgets.buttonbar

Home of XButtonBar.

  1"""Home of `XButtonBar`."""
  2
  3from typing import Optional, Callable
  4from functools import partial
  5from .layouts import XFrame, XBox
  6from .dropdown import XDropDown
  7from .spinner import XSpinner, XSpinnerOption
  8from ..colors import THEME_NAMES
  9
 10
 11class XButtonBar(XFrame):
 12    """A bar of buttons nested in two layers."""
 13
 14    def __init__(
 15        self,
 16        *,
 17        category_subtheme: Optional[str] = None,
 18        dropdown_subtheme: Optional[str] = None,
 19        nested_subtheme: Optional[str] = None,
 20        **kwargs,
 21    ):
 22        """Initialize the class.
 23
 24        Args:
 25            category_subtheme: Subtheme of category buttons.
 26            dropdown_subtheme: Subtheme of dropdown.
 27            nested_subtheme: Subtheme of nested buttons.
 28        """
 29        super().__init__(**kwargs)
 30        self._category_subtheme = category_subtheme
 31        self._dropdown_subtheme = dropdown_subtheme
 32        self._nested_subtheme = nested_subtheme
 33        self._names: dict[list[str]] = dict()
 34        self._spinners: dict[XSpinner] = dict()
 35        self._callbacks: dict[str, Callable] = dict()
 36        self._box = XBox()
 37        self.add_widget(self._box)
 38        self.register_event_type("on_select")
 39
 40    def _dropdown_factory(self, *args, **kwargs):
 41        return XDropDown(*args, subtheme_name=self._dropdown_subtheme, **kwargs)
 42
 43    def add_category(self, category: str, /, *, display_as: Optional[str] = None):
 44        """Add a category for buttons.
 45
 46        Args:
 47            category: Category name, used for callbacks.
 48            display_as: Button text, defaults to the capitalized category name.
 49        """
 50        if category in self._names:
 51            raise ValueError(f"Category {category!r} already in use.")
 52        if display_as is None:
 53            display_as = category.capitalize()
 54        spinner = XSpinner(
 55            text=display_as,
 56            dropdown_cls=self._dropdown_factory,
 57            option_cls=XButtonBarSpinnerOption,
 58            subtheme_name=self._category_subtheme,
 59        )
 60        self._spinners[category] = spinner
 61        self._box.add_widget(spinner)
 62        self._names[category] = []
 63        spinner.bind(on_select=partial(self._on_spinner_select, category))
 64
 65    def add_button(
 66        self,
 67        category: str,
 68        name: str,
 69        /,
 70        callback: Optional[Callable] = None,
 71        *,
 72        display_as: Optional[str] = None,
 73    ):
 74        """Add a button in a category.
 75
 76        Args:
 77            category: Category name, used for callbacks.
 78            name: Button name, used for callbacks.
 79            callback: Callback when button is pressed.
 80            display_as: Button text, defaults to a the button name formatted.
 81        """
 82        if category not in self._names:
 83            self.add_category(category)
 84        if display_as is None:
 85            display_as = name.replace("_", " ").capitalize()
 86        spinner = self._spinners[category]
 87        with self.app.subtheme_context(self._nested_subtheme):
 88            spinner.values.append(display_as)
 89        self._names[category].append(name)
 90        self._callbacks[f"{category}.{name}"] = callback
 91
 92    def get_button(
 93        self,
 94        category: str,
 95        button: Optional[str] = None,
 96    ) -> XDropDown | XSpinnerOption:
 97        """Get the XSpinnerOption button or XDropDown if no button specified."""
 98        spinner = self._spinners[category]
 99        if not button:
100            return spinner
101        idx = self._names[category].index(button)
102        return spinner._dropdown.container.children[-idx - 1]
103
104    def set_callback(self, category: str, button: str, callback: Callable, /):
105        """Change a callback."""
106        self._callbacks[f"{category}.{button}"] = callback
107
108    def on_select(self, category: str, button: str):
109        """Called when a button is pressed."""
110        pass
111
112    def _on_spinner_select(self, category, w, index, text):
113        button = self._names[category][index]
114        callback = self._callbacks.get(f"{category}.{button}")
115        if callback:
116            callback()
117        self.dispatch("on_select", category, button)
118
119    def add_theme_selectors(
120        self,
121        *,
122        category: str = "Themes",
123        prefix: str = "Change to: ",
124        suffix: str = "",
125    ):
126        """Add theme selection buttons."""
127        for tname in THEME_NAMES:
128            self.add_button(
129                "theme",
130                tname,
131                display_as=f"{prefix}{tname.capitalize()}{suffix}",
132                callback=lambda *a, t=tname: self.app.set_theme(t),
133            )
134
135
136class XButtonBarSpinnerOption(XSpinnerOption):
137    """SpinnerOption."""
138
139    def __init__(self, *args, **kwargs):
140        """Initialize the class."""
141        kwargs |= dict(
142            halign="left",
143            valign="middle",
144            padding=(10, 0),
145            height="32dp",
146        )
147        super().__init__(*args, **kwargs)
148        self.bind(size=self.on_size)
149
150    def on_size(self, w, size):
151        """Fix text size to widget size for alignment."""
152        self.text_size = size
153
154
155__all__ = (
156    "XButtonBar",
157    "XButtonBarSpinnerOption",
158)
class XButtonBar(kvex.widgets.layouts.XFrame):
 12class XButtonBar(XFrame):
 13    """A bar of buttons nested in two layers."""
 14
 15    def __init__(
 16        self,
 17        *,
 18        category_subtheme: Optional[str] = None,
 19        dropdown_subtheme: Optional[str] = None,
 20        nested_subtheme: Optional[str] = None,
 21        **kwargs,
 22    ):
 23        """Initialize the class.
 24
 25        Args:
 26            category_subtheme: Subtheme of category buttons.
 27            dropdown_subtheme: Subtheme of dropdown.
 28            nested_subtheme: Subtheme of nested buttons.
 29        """
 30        super().__init__(**kwargs)
 31        self._category_subtheme = category_subtheme
 32        self._dropdown_subtheme = dropdown_subtheme
 33        self._nested_subtheme = nested_subtheme
 34        self._names: dict[list[str]] = dict()
 35        self._spinners: dict[XSpinner] = dict()
 36        self._callbacks: dict[str, Callable] = dict()
 37        self._box = XBox()
 38        self.add_widget(self._box)
 39        self.register_event_type("on_select")
 40
 41    def _dropdown_factory(self, *args, **kwargs):
 42        return XDropDown(*args, subtheme_name=self._dropdown_subtheme, **kwargs)
 43
 44    def add_category(self, category: str, /, *, display_as: Optional[str] = None):
 45        """Add a category for buttons.
 46
 47        Args:
 48            category: Category name, used for callbacks.
 49            display_as: Button text, defaults to the capitalized category name.
 50        """
 51        if category in self._names:
 52            raise ValueError(f"Category {category!r} already in use.")
 53        if display_as is None:
 54            display_as = category.capitalize()
 55        spinner = XSpinner(
 56            text=display_as,
 57            dropdown_cls=self._dropdown_factory,
 58            option_cls=XButtonBarSpinnerOption,
 59            subtheme_name=self._category_subtheme,
 60        )
 61        self._spinners[category] = spinner
 62        self._box.add_widget(spinner)
 63        self._names[category] = []
 64        spinner.bind(on_select=partial(self._on_spinner_select, category))
 65
 66    def add_button(
 67        self,
 68        category: str,
 69        name: str,
 70        /,
 71        callback: Optional[Callable] = None,
 72        *,
 73        display_as: Optional[str] = None,
 74    ):
 75        """Add a button in a category.
 76
 77        Args:
 78            category: Category name, used for callbacks.
 79            name: Button name, used for callbacks.
 80            callback: Callback when button is pressed.
 81            display_as: Button text, defaults to a the button name formatted.
 82        """
 83        if category not in self._names:
 84            self.add_category(category)
 85        if display_as is None:
 86            display_as = name.replace("_", " ").capitalize()
 87        spinner = self._spinners[category]
 88        with self.app.subtheme_context(self._nested_subtheme):
 89            spinner.values.append(display_as)
 90        self._names[category].append(name)
 91        self._callbacks[f"{category}.{name}"] = callback
 92
 93    def get_button(
 94        self,
 95        category: str,
 96        button: Optional[str] = None,
 97    ) -> XDropDown | XSpinnerOption:
 98        """Get the XSpinnerOption button or XDropDown if no button specified."""
 99        spinner = self._spinners[category]
100        if not button:
101            return spinner
102        idx = self._names[category].index(button)
103        return spinner._dropdown.container.children[-idx - 1]
104
105    def set_callback(self, category: str, button: str, callback: Callable, /):
106        """Change a callback."""
107        self._callbacks[f"{category}.{button}"] = callback
108
109    def on_select(self, category: str, button: str):
110        """Called when a button is pressed."""
111        pass
112
113    def _on_spinner_select(self, category, w, index, text):
114        button = self._names[category][index]
115        callback = self._callbacks.get(f"{category}.{button}")
116        if callback:
117            callback()
118        self.dispatch("on_select", category, button)
119
120    def add_theme_selectors(
121        self,
122        *,
123        category: str = "Themes",
124        prefix: str = "Change to: ",
125        suffix: str = "",
126    ):
127        """Add theme selection buttons."""
128        for tname in THEME_NAMES:
129            self.add_button(
130                "theme",
131                tname,
132                display_as=f"{prefix}{tname.capitalize()}{suffix}",
133                callback=lambda *a, t=tname: self.app.set_theme(t),
134            )

A bar of buttons nested in two layers.

XButtonBar( *, category_subtheme: Optional[str] = None, dropdown_subtheme: Optional[str] = None, nested_subtheme: Optional[str] = None, **kwargs)
15    def __init__(
16        self,
17        *,
18        category_subtheme: Optional[str] = None,
19        dropdown_subtheme: Optional[str] = None,
20        nested_subtheme: Optional[str] = None,
21        **kwargs,
22    ):
23        """Initialize the class.
24
25        Args:
26            category_subtheme: Subtheme of category buttons.
27            dropdown_subtheme: Subtheme of dropdown.
28            nested_subtheme: Subtheme of nested buttons.
29        """
30        super().__init__(**kwargs)
31        self._category_subtheme = category_subtheme
32        self._dropdown_subtheme = dropdown_subtheme
33        self._nested_subtheme = nested_subtheme
34        self._names: dict[list[str]] = dict()
35        self._spinners: dict[XSpinner] = dict()
36        self._callbacks: dict[str, Callable] = dict()
37        self._box = XBox()
38        self.add_widget(self._box)
39        self.register_event_type("on_select")

Initialize the class.

Arguments:
  • category_subtheme: Subtheme of category buttons.
  • dropdown_subtheme: Subtheme of dropdown.
  • nested_subtheme: Subtheme of nested buttons.
def add_category(self, category: str, /, *, display_as: Optional[str] = None):
44    def add_category(self, category: str, /, *, display_as: Optional[str] = None):
45        """Add a category for buttons.
46
47        Args:
48            category: Category name, used for callbacks.
49            display_as: Button text, defaults to the capitalized category name.
50        """
51        if category in self._names:
52            raise ValueError(f"Category {category!r} already in use.")
53        if display_as is None:
54            display_as = category.capitalize()
55        spinner = XSpinner(
56            text=display_as,
57            dropdown_cls=self._dropdown_factory,
58            option_cls=XButtonBarSpinnerOption,
59            subtheme_name=self._category_subtheme,
60        )
61        self._spinners[category] = spinner
62        self._box.add_widget(spinner)
63        self._names[category] = []
64        spinner.bind(on_select=partial(self._on_spinner_select, category))

Add a category for buttons.

Arguments:
  • category: Category name, used for callbacks.
  • display_as: Button text, defaults to the capitalized category name.
def add_button( self, category: str, name: str, /, callback: Optional[Callable] = None, *, display_as: Optional[str] = None):
66    def add_button(
67        self,
68        category: str,
69        name: str,
70        /,
71        callback: Optional[Callable] = None,
72        *,
73        display_as: Optional[str] = None,
74    ):
75        """Add a button in a category.
76
77        Args:
78            category: Category name, used for callbacks.
79            name: Button name, used for callbacks.
80            callback: Callback when button is pressed.
81            display_as: Button text, defaults to a the button name formatted.
82        """
83        if category not in self._names:
84            self.add_category(category)
85        if display_as is None:
86            display_as = name.replace("_", " ").capitalize()
87        spinner = self._spinners[category]
88        with self.app.subtheme_context(self._nested_subtheme):
89            spinner.values.append(display_as)
90        self._names[category].append(name)
91        self._callbacks[f"{category}.{name}"] = callback

Add a button in a category.

Arguments:
  • category: Category name, used for callbacks.
  • name: Button name, used for callbacks.
  • callback: Callback when button is pressed.
  • display_as: Button text, defaults to a the button name formatted.
def get_button( self, category: str, button: Optional[str] = None) -> kvex.widgets.dropdown.XDropDown | kvex.widgets.spinner.XSpinnerOption:
 93    def get_button(
 94        self,
 95        category: str,
 96        button: Optional[str] = None,
 97    ) -> XDropDown | XSpinnerOption:
 98        """Get the XSpinnerOption button or XDropDown if no button specified."""
 99        spinner = self._spinners[category]
100        if not button:
101            return spinner
102        idx = self._names[category].index(button)
103        return spinner._dropdown.container.children[-idx - 1]

Get the XSpinnerOption button or XDropDown if no button specified.

def set_callback(self, category: str, button: str, callback: Callable, /):
105    def set_callback(self, category: str, button: str, callback: Callable, /):
106        """Change a callback."""
107        self._callbacks[f"{category}.{button}"] = callback

Change a callback.

def on_select(self, category: str, button: str):
109    def on_select(self, category: str, button: str):
110        """Called when a button is pressed."""
111        pass

Called when a button is pressed.

def add_theme_selectors( self, *, category: str = 'Themes', prefix: str = 'Change to: ', suffix: str = ''):
120    def add_theme_selectors(
121        self,
122        *,
123        category: str = "Themes",
124        prefix: str = "Change to: ",
125        suffix: str = "",
126    ):
127        """Add theme selection buttons."""
128        for tname in THEME_NAMES:
129            self.add_button(
130                "theme",
131                tname,
132                display_as=f"{prefix}{tname.capitalize()}{suffix}",
133                callback=lambda *a, t=tname: self.app.set_theme(t),
134            )

Add theme selection buttons.

Inherited Members
kivy.uix.anchorlayout.AnchorLayout
padding
anchor_x
anchor_y
do_layout
kivy.uix.layout.Layout
add_widget
remove_widget
layout_hint_with_bounds
kivy.uix.widget.Widget
proxy_ref
apply_class_lang_rules
collide_point
collide_widget
on_motion
on_touch_down
on_touch_move
on_touch_up
on_kv_post
clear_widgets
register_for_motion_event
unregister_for_motion_event
export_to_png
export_as_image
get_root_window
get_parent_window
walk
walk_reverse
to_widget
to_window
to_parent
to_local
get_window_matrix
x
y
width
height
pos
size
get_right
set_right
right
get_top
set_top
top
get_center_x
set_center_x
center_x
get_center_y
set_center_y
center_y
center
cls
children
parent
size_hint_x
size_hint_y
size_hint
pos_hint
size_hint_min_x
size_hint_min_y
size_hint_min
size_hint_max_x
size_hint_max_y
size_hint_max
ids
opacity
on_opacity
canvas
get_disabled
set_disabled
inc_disabled
dec_disabled
disabled
motion_filter
kivy._event.EventDispatcher
register_event_type
unregister_event_types
unregister_event_type
is_event_type
bind
unbind
fbind
funbind
unbind_uid
get_property_observers
events
dispatch
dispatch_generic
dispatch_children
setter
getter
property
properties
create_property
apply_property
class XButtonBarSpinnerOption(kvex.widgets.spinner.XSpinnerOption):
137class XButtonBarSpinnerOption(XSpinnerOption):
138    """SpinnerOption."""
139
140    def __init__(self, *args, **kwargs):
141        """Initialize the class."""
142        kwargs |= dict(
143            halign="left",
144            valign="middle",
145            padding=(10, 0),
146            height="32dp",
147        )
148        super().__init__(*args, **kwargs)
149        self.bind(size=self.on_size)
150
151    def on_size(self, w, size):
152        """Fix text size to widget size for alignment."""
153        self.text_size = size

SpinnerOption.

XButtonBarSpinnerOption(*args, **kwargs)
140    def __init__(self, *args, **kwargs):
141        """Initialize the class."""
142        kwargs |= dict(
143            halign="left",
144            valign="middle",
145            padding=(10, 0),
146            height="32dp",
147        )
148        super().__init__(*args, **kwargs)
149        self.bind(size=self.on_size)

Initialize the class.

def on_size(self, w, size):
151    def on_size(self, w, size):
152        """Fix text size to widget size for alignment."""
153        self.text_size = size

Fix text size to widget size for alignment.

Inherited Members
kivy.uix.button.Button
background_color
background_normal
background_down
background_disabled_normal
background_disabled_down
border
kivy.uix.behaviors.button.ButtonBehavior
state
last_touch
min_state_time
always_release
cancel_event
on_touch_down
on_touch_move
on_touch_up
on_press
on_release
trigger_action
kivy.uix.label.Label
texture_update
on_ref_press
disabled_color
text
text_size
base_direction
text_language
font_context
font_family
font_name
font_size
font_features
line_height
bold
italic
underline
strikethrough
padding_x
padding_y
padding
halign
valign
color
outline_width
outline_color
disabled_outline_color
texture
texture_size
mipmap
shorten
shorten_from
is_shortened
split_str
ellipsis_options
unicode_errors
markup
refs
anchors
max_lines
strip
font_hinting
font_kerning
font_blended
kivy.uix.widget.Widget
proxy_ref
apply_class_lang_rules
collide_point
collide_widget
on_motion
on_kv_post
add_widget
remove_widget
clear_widgets
register_for_motion_event
unregister_for_motion_event
export_to_png
export_as_image
get_root_window
get_parent_window
walk
walk_reverse
to_widget
to_window
to_parent
to_local
get_window_matrix
x
y
width
height
pos
size
get_right
set_right
right
get_top
set_top
top
get_center_x
set_center_x
center_x
get_center_y
set_center_y
center_y
center
cls
children
parent
size_hint_x
size_hint_y
size_hint
pos_hint
size_hint_min_x
size_hint_min_y
size_hint_min
size_hint_max_x
size_hint_max_y
size_hint_max
ids
opacity
on_opacity
canvas
get_disabled
set_disabled
inc_disabled
dec_disabled
disabled
motion_filter
kivy._event.EventDispatcher
register_event_type
unregister_event_types
unregister_event_type
is_event_type
bind
unbind
fbind
funbind
unbind_uid
get_property_observers
events
dispatch
dispatch_generic
dispatch_children
setter
getter
property
properties
create_property
apply_property