Module botroyale.gui.kex.widgets.app
App and associated widgets.
Generally, to use the GUI, one would initialize and then run an App:
app = XApp()
app.hook(func_to_call_every_frame, fps=20)
app.run()
Expand source code Browse git
"""App and associated widgets.
Generally, to use the GUI, one would initialize and then run an `App`:
```python
app = XApp()
app.hook(func_to_call_every_frame, fps=20)
app.run()
```
"""
from typing import Callable, Optional
from functools import partial
from .. import kivy as kv
from ..util import (
XColor,
XWindow,
XWidget,
consume_args,
SimpleCallable,
queue_around_frame,
)
from .layouts import XAnchor
from .uix import XLabel
class XOverlay(kv.FocusBehavior, XAnchor):
"""Overlay to be displayed on top of other widgets."""
def __init__(self, **kwargs):
"""Initialize like an XAnchor."""
super().__init__()
self.make_bg(XColor(a=0.5))
self.label = self.add(XLabel(**kwargs))
self.label.set_size(x=500, y=150)
self.label.make_bg(XColor.from_name("red", 0.15))
class XRoot(kv.FocusBehavior, XAnchor):
"""Root widget for the app, with FocusBehavior."""
pass
class XApp(XWidget, kv.App):
"""See module documentation for details."""
block_input = kv.BooleanProperty(False)
"""If all user input should be blocked."""
def __init__(
self,
logger: Optional[Callable[[str], None]] = None,
escape_exits: bool = False,
enable_multitouch: bool = False,
**kwargs,
):
"""Initialize the class.
Args:
logger: Logging function for XWidgets. Used internally for debugging.
escape_exits: Enable exiting when the escape key is pressed.
enable_multitouch: Enable multitouch.
"""
super().__init__(**kwargs)
XWindow.enable_escape_exit(escape_exits)
self.root = XRoot()
self.keyboard = kv.Window.request_keyboard(consume_args, self.root)
self.__last_focused = None
self.__overlay = None
self.__enable_multitouch = enable_multitouch
if not enable_multitouch:
XWindow.disable_multitouch()
self.root.bind(
on_touch_down=self._is_touch_blocked,
on_touch_up=self._is_touch_blocked,
on_touch_move=self._is_touch_blocked,
)
def logger(self, message: str):
"""Log a message in the app's logger."""
if self.logger:
self.logger(message)
def hook(self, func: Callable[[float], None], fps: float):
"""Schedule *func* to be called *fps* times per seconds."""
kv.Clock.schedule_once(
lambda *a: kv.Clock.schedule_interval(func, 1 / fps),
0,
)
def open_settings(self, *args) -> False:
"""Overrides base class method to disable the builtin settings widget."""
return False
@property
def mouse_pos(self) -> tuple[float, float]:
"""The current position of the mouse."""
return XWindow.mouse_pos
def add(self, *args, **kwargs):
"""Add a widget to the root widget."""
return self.root.add(*args, **kwargs)
@property
def current_focus(self) -> kv.Widget:
"""The widget currently in focus."""
return self.keyboard.target
@property
def overlay(self) -> Optional[XOverlay]:
"""The current overlay."""
return self.__overlay
def _is_touch_blocked(self, w, m):
if self.block_input:
return True
if not self.__enable_multitouch:
if hasattr(m, "multitouch_sim") and m.multitouch_sim:
return True
return False
def __create_overlay(self, **kwargs):
self.__last_focused = self.current_focus
self.__overlay = XOverlay(**kwargs)
self.__overlay.focus = True
self.block_input = True
self.add(self.__overlay)
def __destroy_overlay(self, after: Optional[SimpleCallable] = None):
if self.__last_focused is not None:
self.__last_focused.focus = True
self.root.remove_widget(self.__overlay)
self.__overlay = None
self.block_input = False
if after is not None:
after()
def with_overlay(
self,
func: SimpleCallable,
after: Optional[SimpleCallable] = None,
**kwargs,
):
"""Queue a function with a temporary `XOverlay` that blocks input.
Uses the `botroyale.gui.kex.util.queue_around_frame` decorator to draw
a frame before calling the function, otherwise the added overlay will
not be seen until execution is yielded to kivy's clock.
Example usage:
```python
with_overlay(
func=lambda: my_func(arg1=True),
text="my_func is executing...",
after=lambda: print("finished executing my_func."),
)
```
Args:
func: Callback to queue after adding the overlay.
after: Optionally call after removing the overlay.
kwargs: Keyword arguments for the XOverlay object.
"""
if self.__overlay is not None:
raise RuntimeError("Cannot create an overlay when one already exists.")
queue_around_frame(
func,
before=partial(self.__create_overlay, **kwargs),
after=partial(self.__destroy_overlay, after),
)()
Classes
class XApp (logger: Optional[Callable[[str], None]] = None, escape_exits: bool = False, enable_multitouch: bool = False, **kwargs)-
See module documentation for details.
Initialize the class.
- Args
- -----=
logger- Logging function for XWidgets. Used internally for debugging.
escape_exits- Enable exiting when the escape key is pressed.
enable_multitouch- Enable multitouch.
Expand source code Browse git
class XApp(XWidget, kv.App): """See module documentation for details.""" block_input = kv.BooleanProperty(False) """If all user input should be blocked.""" def __init__( self, logger: Optional[Callable[[str], None]] = None, escape_exits: bool = False, enable_multitouch: bool = False, **kwargs, ): """Initialize the class. Args: logger: Logging function for XWidgets. Used internally for debugging. escape_exits: Enable exiting when the escape key is pressed. enable_multitouch: Enable multitouch. """ super().__init__(**kwargs) XWindow.enable_escape_exit(escape_exits) self.root = XRoot() self.keyboard = kv.Window.request_keyboard(consume_args, self.root) self.__last_focused = None self.__overlay = None self.__enable_multitouch = enable_multitouch if not enable_multitouch: XWindow.disable_multitouch() self.root.bind( on_touch_down=self._is_touch_blocked, on_touch_up=self._is_touch_blocked, on_touch_move=self._is_touch_blocked, ) def logger(self, message: str): """Log a message in the app's logger.""" if self.logger: self.logger(message) def hook(self, func: Callable[[float], None], fps: float): """Schedule *func* to be called *fps* times per seconds.""" kv.Clock.schedule_once( lambda *a: kv.Clock.schedule_interval(func, 1 / fps), 0, ) def open_settings(self, *args) -> False: """Overrides base class method to disable the builtin settings widget.""" return False @property def mouse_pos(self) -> tuple[float, float]: """The current position of the mouse.""" return XWindow.mouse_pos def add(self, *args, **kwargs): """Add a widget to the root widget.""" return self.root.add(*args, **kwargs) @property def current_focus(self) -> kv.Widget: """The widget currently in focus.""" return self.keyboard.target @property def overlay(self) -> Optional[XOverlay]: """The current overlay.""" return self.__overlay def _is_touch_blocked(self, w, m): if self.block_input: return True if not self.__enable_multitouch: if hasattr(m, "multitouch_sim") and m.multitouch_sim: return True return False def __create_overlay(self, **kwargs): self.__last_focused = self.current_focus self.__overlay = XOverlay(**kwargs) self.__overlay.focus = True self.block_input = True self.add(self.__overlay) def __destroy_overlay(self, after: Optional[SimpleCallable] = None): if self.__last_focused is not None: self.__last_focused.focus = True self.root.remove_widget(self.__overlay) self.__overlay = None self.block_input = False if after is not None: after() def with_overlay( self, func: SimpleCallable, after: Optional[SimpleCallable] = None, **kwargs, ): """Queue a function with a temporary `XOverlay` that blocks input. Uses the `botroyale.gui.kex.util.queue_around_frame` decorator to draw a frame before calling the function, otherwise the added overlay will not be seen until execution is yielded to kivy's clock. Example usage: ```python with_overlay( func=lambda: my_func(arg1=True), text="my_func is executing...", after=lambda: print("finished executing my_func."), ) ``` Args: func: Callback to queue after adding the overlay. after: Optionally call after removing the overlay. kwargs: Keyword arguments for the XOverlay object. """ if self.__overlay is not None: raise RuntimeError("Cannot create an overlay when one already exists.") queue_around_frame( func, before=partial(self.__create_overlay, **kwargs), after=partial(self.__destroy_overlay, after), )()Ancestors
- XWidget
- kivy.app.App
- kivy._event.EventDispatcher
- kivy._event.ObjectWithUid
Subclasses
Instance variables
var block_input-
If all user input should be blocked.
var current_focus : kivy.uix.widget.Widget-
The widget currently in focus.
Expand source code Browse git
@property def current_focus(self) -> kv.Widget: """The widget currently in focus.""" return self.keyboard.target var mouse_pos : tuple[float, float]-
The current position of the mouse.
Expand source code Browse git
@property def mouse_pos(self) -> tuple[float, float]: """The current position of the mouse.""" return XWindow.mouse_pos var overlay : Optional[XOverlay]-
The current overlay.
Expand source code Browse git
@property def overlay(self) -> Optional[XOverlay]: """The current overlay.""" return self.__overlay
Methods
def add(self, *args, **kwargs)-
Add a widget to the root widget.
Expand source code Browse git
def add(self, *args, **kwargs): """Add a widget to the root widget.""" return self.root.add(*args, **kwargs) def hook(self, func: Callable[[float], None], fps: float)-
Schedule func to be called fps times per seconds.
Expand source code Browse git
def hook(self, func: Callable[[float], None], fps: float): """Schedule *func* to be called *fps* times per seconds.""" kv.Clock.schedule_once( lambda *a: kv.Clock.schedule_interval(func, 1 / fps), 0, ) def logger(self, message: str)-
Log a message in the app's logger.
Expand source code Browse git
def logger(self, message: str): """Log a message in the app's logger.""" if self.logger: self.logger(message) def open_settings(self, *args)-
Overrides base class method to disable the builtin settings widget.
Expand source code Browse git
def open_settings(self, *args) -> False: """Overrides base class method to disable the builtin settings widget.""" return False def with_overlay(self, func: Callable[[], None], after: Optional[Callable[[], None]] = None, **kwargs)-
Queue a function with a temporary
XOverlaythat blocks input.Uses the
queue_around_frame()decorator to draw a frame before calling the function, otherwise the added overlay will not be seen until execution is yielded to kivy's clock.Example usage:
with_overlay( func=lambda: my_func(arg1=True), text="my_func is executing...", after=lambda: print("finished executing my_func."), )- Args
- -----=
func- Callback to queue after adding the overlay.
after- Optionally call after removing the overlay.
kwargs- Keyword arguments for the XOverlay object.
Expand source code Browse git
def with_overlay( self, func: SimpleCallable, after: Optional[SimpleCallable] = None, **kwargs, ): """Queue a function with a temporary `XOverlay` that blocks input. Uses the `botroyale.gui.kex.util.queue_around_frame` decorator to draw a frame before calling the function, otherwise the added overlay will not be seen until execution is yielded to kivy's clock. Example usage: ```python with_overlay( func=lambda: my_func(arg1=True), text="my_func is executing...", after=lambda: print("finished executing my_func."), ) ``` Args: func: Callback to queue after adding the overlay. after: Optionally call after removing the overlay. kwargs: Keyword arguments for the XOverlay object. """ if self.__overlay is not None: raise RuntimeError("Cannot create an overlay when one already exists.") queue_around_frame( func, before=partial(self.__create_overlay, **kwargs), after=partial(self.__destroy_overlay, after), )()
Inherited members
class XOverlay (**kwargs)-
Overlay to be displayed on top of other widgets.
Initialize like an XAnchor.
Expand source code Browse git
class XOverlay(kv.FocusBehavior, XAnchor): """Overlay to be displayed on top of other widgets.""" def __init__(self, **kwargs): """Initialize like an XAnchor.""" super().__init__() self.make_bg(XColor(a=0.5)) self.label = self.add(XLabel(**kwargs)) self.label.set_size(x=500, y=150) self.label.make_bg(XColor.from_name("red", 0.15))Ancestors
- kivy.uix.behaviors.focus.FocusBehavior
- XAnchor
- XWidget
- kivy.uix.anchorlayout.AnchorLayout
- kivy.uix.layout.Layout
- kivy.uix.widget.Widget
- kivy.uix.widget.WidgetBase
- kivy._event.EventDispatcher
- kivy._event.ObjectWithUid
Inherited members
class XRoot (**kwargs)-
Root widget for the app, with FocusBehavior.
Expand source code Browse git
class XRoot(kv.FocusBehavior, XAnchor): """Root widget for the app, with FocusBehavior.""" passAncestors
- kivy.uix.behaviors.focus.FocusBehavior
- XAnchor
- XWidget
- kivy.uix.anchorlayout.AnchorLayout
- kivy.uix.layout.Layout
- kivy.uix.widget.Widget
- kivy.uix.widget.WidgetBase
- kivy._event.EventDispatcher
- kivy._event.ObjectWithUid
Inherited members