123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- from dataclasses import dataclass
- from inspect import Parameter, signature
- from typing import TYPE_CHECKING, Any, Awaitable, BinaryIO, Callable, Dict, List, Optional
- from . import background_tasks, globals
- from .helpers import KWONLY_SLOTS
- if TYPE_CHECKING:
- from .client import Client
- from .element import Element
- @dataclass(**KWONLY_SLOTS)
- class EventArguments:
- sender: 'Element'
- client: 'Client'
- @dataclass(**KWONLY_SLOTS)
- class GenericEventArguments(EventArguments):
- args: Dict[str, Any]
- def __getitem__(self, key: str) -> Any:
- if key == 'args':
- globals.log.warning('msg["args"] is deprecated, use e.args instead '
- '(see https://github.com/zauberzeug/nicegui/pull/1095)') # DEPRECATED
- return self.args
- raise KeyError(key)
- @dataclass(**KWONLY_SLOTS)
- class ClickEventArguments(EventArguments):
- pass
- @dataclass(**KWONLY_SLOTS)
- class SceneClickHit:
- object_id: str
- object_name: str
- x: float
- y: float
- z: float
- @dataclass(**KWONLY_SLOTS)
- class SceneClickEventArguments(ClickEventArguments):
- click_type: str
- button: int
- alt: bool
- ctrl: bool
- meta: bool
- shift: bool
- hits: List[SceneClickHit]
- @dataclass(**KWONLY_SLOTS)
- class ColorPickEventArguments(EventArguments):
- color: str
- @dataclass(**KWONLY_SLOTS)
- class MouseEventArguments(EventArguments):
- type: str
- image_x: float
- image_y: float
- button: int
- buttons: int
- alt: bool
- ctrl: bool
- meta: bool
- shift: bool
- @dataclass(**KWONLY_SLOTS)
- class JoystickEventArguments(EventArguments):
- action: str
- x: Optional[float] = None
- y: Optional[float] = None
- @dataclass(**KWONLY_SLOTS)
- class UploadEventArguments(EventArguments):
- content: BinaryIO
- name: str
- type: str
- @dataclass(**KWONLY_SLOTS)
- class ValueChangeEventArguments(EventArguments):
- value: Any
- @dataclass(**KWONLY_SLOTS)
- class TableSelectionEventArguments(EventArguments):
- selection: List[Any]
- @dataclass(**KWONLY_SLOTS)
- class KeyboardAction:
- keydown: bool
- keyup: bool
- repeat: bool
- @dataclass(**KWONLY_SLOTS)
- class KeyboardModifiers:
- alt: bool
- ctrl: bool
- meta: bool
- shift: bool
- @dataclass(**KWONLY_SLOTS)
- class KeyboardKey:
- name: str
- code: str
- location: int
- def __eq__(self, other: object) -> bool:
- if isinstance(other, str):
- return self.name == other or self.code == other
- elif isinstance(other, KeyboardKey):
- return self == other
- else:
- return False
- def __repr__(self):
- return str(self.name)
- @property
- def is_cursorkey(self):
- return self.code.startswith('Arrow')
- @property
- def number(self) -> Optional[int]:
- """Integer value of a number key."""
- return int(self.code.removeprefix('Digit')) if self.code.startswith('Digit') else None
- @property
- def backspace(self) -> bool:
- return self.name == 'Backspace'
- @property
- def tab(self) -> bool:
- return self.name == 'Tab'
- @property
- def enter(self) -> bool:
- return self.name == 'enter'
- @property
- def shift(self) -> bool:
- return self.name == 'Shift'
- @property
- def control(self) -> bool:
- return self.name == 'Control'
- @property
- def alt(self) -> bool:
- return self.name == 'Alt'
- @property
- def pause(self) -> bool:
- return self.name == 'Pause'
- @property
- def caps_lock(self) -> bool:
- return self.name == 'CapsLock'
- @property
- def escape(self) -> bool:
- return self.name == 'Escape'
- @property
- def space(self) -> bool:
- return self.name == 'Space'
- @property
- def page_up(self) -> bool:
- return self.name == 'PageUp'
- @property
- def page_down(self) -> bool:
- return self.name == 'PageDown'
- @property
- def end(self) -> bool:
- return self.name == 'End'
- @property
- def home(self) -> bool:
- return self.name == 'Home'
- @property
- def arrow_left(self) -> bool:
- return self.name == 'ArrowLeft'
- @property
- def arrow_up(self) -> bool:
- return self.name == 'ArrowUp'
- @property
- def arrow_right(self) -> bool:
- return self.name == 'ArrowRight'
- @property
- def arrow_down(self) -> bool:
- return self.name == 'ArrowDown'
- @property
- def print_screen(self) -> bool:
- return self.name == 'PrintScreen'
- @property
- def insert(self) -> bool:
- return self.name == 'Insert'
- @property
- def delete(self) -> bool:
- return self.name == 'Delete'
- @property
- def meta(self) -> bool:
- return self.name == 'Meta'
- @property
- def f1(self) -> bool:
- return self.name == 'F1'
- @property
- def f2(self) -> bool:
- return self.name == 'F2'
- @property
- def f3(self) -> bool:
- return self.name == 'F3'
- @property
- def f4(self) -> bool:
- return self.name == 'F4'
- @property
- def f5(self) -> bool:
- return self.name == 'F5'
- @property
- def f6(self) -> bool:
- return self.name == 'F6'
- @property
- def f7(self) -> bool:
- return self.name == 'F7'
- @property
- def f8(self) -> bool:
- return self.name == 'F8'
- @property
- def f9(self) -> bool:
- return self.name == 'F9'
- @property
- def f10(self) -> bool:
- return self.name == 'F10'
- @property
- def f11(self) -> bool:
- return self.name == 'F11'
- @property
- def f12(self) -> bool:
- return self.name == 'F12'
- @dataclass(**KWONLY_SLOTS)
- class KeyEventArguments(EventArguments):
- action: KeyboardAction
- key: KeyboardKey
- modifiers: KeyboardModifiers
- @dataclass(**KWONLY_SLOTS)
- class ScrollEventArguments(EventArguments):
- vertical_position: float
- vertical_percentage: float
- vertical_size: float
- vertical_container_size: float
- horizontal_position: float
- horizontal_percentage: float
- horizontal_size: float
- horizontal_container_size: float
- def handle_event(handler: Optional[Callable[..., Any]], arguments: EventArguments) -> None:
- if handler is None:
- return
- try:
- expects_arguments = any(p.default is Parameter.empty and
- p.kind is not Parameter.VAR_POSITIONAL and
- p.kind is not Parameter.VAR_KEYWORD
- for p in signature(handler).parameters.values())
- if arguments.sender.is_ignoring_events:
- return
- parent_slot = arguments.sender.parent_slot
- assert parent_slot is not None
- with parent_slot:
- result = handler(arguments) if expects_arguments else handler()
- if isinstance(result, Awaitable):
- async def wait_for_result():
- with parent_slot:
- try:
- await result
- except Exception as e:
- globals.handle_exception(e)
- if globals.loop and globals.loop.is_running():
- background_tasks.create(wait_for_result(), name=str(handler))
- else:
- globals.app.on_startup(wait_for_result())
- except Exception as e:
- globals.handle_exception(e)
|