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

kvex.behaviors

Home of XThemed and XFocusBehavior.

  1"""Home of `XThemed` and `XFocusBehavior`."""
  2
  3from typing import Optional
  4from . import kivy as kv
  5from .util import schedule_once
  6from .colors import SubTheme
  7
  8
  9class XThemed(kv.EventDispatcher):
 10    """A mixin for theming widgets.
 11
 12    Each widget is configured to follow a particular subtheme by setting
 13    `XThemed.subtheme_name` (defaults to `kvex.app.XApp.subtheme_name`).
 14
 15    Theming can be disabled by passing False to `enable_theming` on initialization.
 16
 17    The `on_subtheme` event will be triggered whenever `kvex.app.XApp.theme` changes or
 18    when `XThemed.subtheme_name` is set.
 19    """
 20
 21    def __init__(
 22        self,
 23        *args,
 24        subtheme_name: Optional[str] = None,
 25        enable_theming: bool = True,
 26        **kwargs,
 27    ):
 28        """See class documentation for details.
 29
 30        Args:
 31            subtheme_name: Set `XThemed.subtheme_name`.
 32            enable_theming: Enable the `on_subtheme` event.
 33        """
 34        super().__init__(*args, **kwargs)
 35        self._subtheme_name = subtheme_name or kv.App.get_running_app().subtheme_name
 36        self._subtheme = None
 37        # The reason for using events instead of properties is due to initialization
 38        # order: some use cases require that all classes in the MRO are initialized
 39        # before an `on_subtheme` event is triggered. For this reason also, an initial
 40        # `on_subtheme` event is scheduled for the next frame after initialization.
 41        self._refresh_subtheme(trigger_event=False)
 42        self.register_event_type("on_subtheme")
 43        if enable_theming:
 44            schedule_once(self.trigger_subtheme)
 45            kv.App.get_running_app().bind(on_theme=self._refresh_subtheme)
 46
 47    def on_subtheme(self, subtheme: SubTheme):
 48        """Called when the subtheme changes.
 49
 50        Use the `kvex.colors.SubTheme` object to configure relevant colors.
 51        """
 52        pass
 53
 54    @property
 55    def subtheme_name(self) -> str:
 56        """Current subtheme name. See also: `kvex.colors.SUBTHEME_NAMES`."""
 57        return self._subtheme_name
 58
 59    @subtheme_name.setter
 60    def subtheme_name(self, subtheme_name: str, /):
 61        """Set `subtheme_name`."""
 62        self._subtheme_name = subtheme_name
 63        self._refresh_subtheme()
 64
 65    @property
 66    def subtheme(self) -> SubTheme:
 67        """Current subtheme."""
 68        return self._subtheme
 69
 70    def trigger_subtheme(self, *args):
 71        """Force the `on_subtheme` event to trigger."""
 72        self.dispatch("on_subtheme", self._subtheme)
 73
 74    def _refresh_subtheme(self, *args, trigger_event: bool = True):
 75        old_subtheme = self._subtheme
 76        new_subtheme = getattr(kv.App.get_running_app().theme, self._subtheme_name)
 77        self._subtheme = new_subtheme
 78        if new_subtheme is not old_subtheme and trigger_event:
 79            self.dispatch("on_subtheme", new_subtheme)
 80
 81
 82class XFocusBehavior(kv.FocusBehavior):
 83    """Like Kivy's `FocusBehavior` with option to disable defocusing on escape key."""
 84
 85    escape_unfocuses = kv.BooleanProperty(False)
 86    """Enables defocusing when pressing escape. Defaults to False."""
 87
 88    def keyboard_on_key_up(self, w, key_pair):
 89        """Overrides base method to manually defocus on escape."""
 90        keycode, key = key_pair
 91        if self.escape_unfocuses and key == "escape":
 92            self.focus = False
 93            return True
 94        return False
 95
 96
 97__all__ = (
 98    "XThemed",
 99    "XFocusBehavior",
100)
class XThemed(kivy._event.EventDispatcher):
10class XThemed(kv.EventDispatcher):
11    """A mixin for theming widgets.
12
13    Each widget is configured to follow a particular subtheme by setting
14    `XThemed.subtheme_name` (defaults to `kvex.app.XApp.subtheme_name`).
15
16    Theming can be disabled by passing False to `enable_theming` on initialization.
17
18    The `on_subtheme` event will be triggered whenever `kvex.app.XApp.theme` changes or
19    when `XThemed.subtheme_name` is set.
20    """
21
22    def __init__(
23        self,
24        *args,
25        subtheme_name: Optional[str] = None,
26        enable_theming: bool = True,
27        **kwargs,
28    ):
29        """See class documentation for details.
30
31        Args:
32            subtheme_name: Set `XThemed.subtheme_name`.
33            enable_theming: Enable the `on_subtheme` event.
34        """
35        super().__init__(*args, **kwargs)
36        self._subtheme_name = subtheme_name or kv.App.get_running_app().subtheme_name
37        self._subtheme = None
38        # The reason for using events instead of properties is due to initialization
39        # order: some use cases require that all classes in the MRO are initialized
40        # before an `on_subtheme` event is triggered. For this reason also, an initial
41        # `on_subtheme` event is scheduled for the next frame after initialization.
42        self._refresh_subtheme(trigger_event=False)
43        self.register_event_type("on_subtheme")
44        if enable_theming:
45            schedule_once(self.trigger_subtheme)
46            kv.App.get_running_app().bind(on_theme=self._refresh_subtheme)
47
48    def on_subtheme(self, subtheme: SubTheme):
49        """Called when the subtheme changes.
50
51        Use the `kvex.colors.SubTheme` object to configure relevant colors.
52        """
53        pass
54
55    @property
56    def subtheme_name(self) -> str:
57        """Current subtheme name. See also: `kvex.colors.SUBTHEME_NAMES`."""
58        return self._subtheme_name
59
60    @subtheme_name.setter
61    def subtheme_name(self, subtheme_name: str, /):
62        """Set `subtheme_name`."""
63        self._subtheme_name = subtheme_name
64        self._refresh_subtheme()
65
66    @property
67    def subtheme(self) -> SubTheme:
68        """Current subtheme."""
69        return self._subtheme
70
71    def trigger_subtheme(self, *args):
72        """Force the `on_subtheme` event to trigger."""
73        self.dispatch("on_subtheme", self._subtheme)
74
75    def _refresh_subtheme(self, *args, trigger_event: bool = True):
76        old_subtheme = self._subtheme
77        new_subtheme = getattr(kv.App.get_running_app().theme, self._subtheme_name)
78        self._subtheme = new_subtheme
79        if new_subtheme is not old_subtheme and trigger_event:
80            self.dispatch("on_subtheme", new_subtheme)

A mixin for theming widgets.

Each widget is configured to follow a particular subtheme by setting XThemed.subtheme_name (defaults to kvex.app.XApp.subtheme_name).

Theming can be disabled by passing False to enable_theming on initialization.

The on_subtheme event will be triggered whenever kvex.app.XApp.theme changes or when XThemed.subtheme_name is set.

XThemed( *args, subtheme_name: Optional[str] = None, enable_theming: bool = True, **kwargs)
22    def __init__(
23        self,
24        *args,
25        subtheme_name: Optional[str] = None,
26        enable_theming: bool = True,
27        **kwargs,
28    ):
29        """See class documentation for details.
30
31        Args:
32            subtheme_name: Set `XThemed.subtheme_name`.
33            enable_theming: Enable the `on_subtheme` event.
34        """
35        super().__init__(*args, **kwargs)
36        self._subtheme_name = subtheme_name or kv.App.get_running_app().subtheme_name
37        self._subtheme = None
38        # The reason for using events instead of properties is due to initialization
39        # order: some use cases require that all classes in the MRO are initialized
40        # before an `on_subtheme` event is triggered. For this reason also, an initial
41        # `on_subtheme` event is scheduled for the next frame after initialization.
42        self._refresh_subtheme(trigger_event=False)
43        self.register_event_type("on_subtheme")
44        if enable_theming:
45            schedule_once(self.trigger_subtheme)
46            kv.App.get_running_app().bind(on_theme=self._refresh_subtheme)

See class documentation for details.

Arguments:
def on_subtheme(self, subtheme: kvex.colors.SubTheme):
48    def on_subtheme(self, subtheme: SubTheme):
49        """Called when the subtheme changes.
50
51        Use the `kvex.colors.SubTheme` object to configure relevant colors.
52        """
53        pass

Called when the subtheme changes.

Use the kvex.colors.SubTheme object to configure relevant colors.

subtheme_name: str

Current subtheme.

def trigger_subtheme(self, *args):
71    def trigger_subtheme(self, *args):
72        """Force the `on_subtheme` event to trigger."""
73        self.dispatch("on_subtheme", self._subtheme)

Force the on_subtheme event to trigger.

Inherited Members
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
proxy_ref
class XFocusBehavior(kivy.uix.behaviors.focus.FocusBehavior):
83class XFocusBehavior(kv.FocusBehavior):
84    """Like Kivy's `FocusBehavior` with option to disable defocusing on escape key."""
85
86    escape_unfocuses = kv.BooleanProperty(False)
87    """Enables defocusing when pressing escape. Defaults to False."""
88
89    def keyboard_on_key_up(self, w, key_pair):
90        """Overrides base method to manually defocus on escape."""
91        keycode, key = key_pair
92        if self.escape_unfocuses and key == "escape":
93            self.focus = False
94            return True
95        return False

Like Kivy's FocusBehavior with option to disable defocusing on escape key.

escape_unfocuses

Enables defocusing when pressing escape. Defaults to False.

def keyboard_on_key_up(self, w, key_pair):
89    def keyboard_on_key_up(self, w, key_pair):
90        """Overrides base method to manually defocus on escape."""
91        keycode, key = key_pair
92        if self.escape_unfocuses and key == "escape":
93            self.focus = False
94            return True
95        return False

Overrides base method to manually defocus on escape.

Inherited Members
kivy.uix.behaviors.focus.FocusBehavior
FocusBehavior
ignored_touch
keyboard
is_focusable
focus
focused
keyboard_suggestions
focus_next
focus_previous
keyboard_mode
input_type
unfocus_on_touch
keyboard_on_textinput
on_touch_down
get_focus_next
get_focus_previous
keyboard_on_key_down
show_keyboard
hide_keyboard