-from .base import Child, Parent, Root
from .button import Button
+from .child import Child
from .drop_down import DropDown
+from .event_method_dispatcher import EventMethodDispatcher
from .fps_widget import FPSWidget
from .icon import Icon
from .icon_button import IconButton
from .label import Label
from .message_box import MessageBox
from .modal import Modal
+from .parent import Parent
+from .root import Root
from .scroll import Scroll
from .slider import Slider
from .spinner import Spinner
+++ /dev/null
-from functools import cached_property, partial
-
-import pygame
-
-from .focus import FocusRootMixin
-
-
-class EventMethodDispatcher:
- MODS = (pygame.KMOD_CTRL, pygame.KMOD_ALT, pygame.KMOD_META, pygame.KMOD_SHIFT)
- KEY_METHODS = {}
-
- def get_key_method(self, key, mod):
- mods = set()
- for mask in self.MODS:
- if mod & mask:
- mods.add(mask)
- method = self.KEY_METHODS.get(frozenset(mods), {}).get(key)
- if method is not None:
- return partial(method, self)
- return None
-
- def handle_keydown(self, ev):
- if not self.KEY_METHODS:
- return
- key_method = self.get_key_method(ev.key, ev.mod)
- if key_method is not None:
- key_method()
-
- def handle_event(self, ev):
- method_name = f"handle_{pygame.event.event_name(ev.type).lower()}"
- if hasattr(self, method_name):
- getattr(self, method_name)(ev)
-
- def update(self):
- pass
-
- def draw(self):
- pass
-
-
-class Parent(EventMethodDispatcher):
- root: "Root"
- running: bool
- stop_event: bool
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.children = []
-
- def handle_event(self, ev):
- super().handle_event(ev)
- if not self.running or self.stop_event:
- return
- for child in self.children:
- child.handle_event(ev)
- if not self.running or self.stop_event:
- break
-
- def update(self):
- super().update()
- for child in self.children:
- child.update()
-
- def draw(self):
- super().draw()
- for child in self.children:
- child.draw()
-
-
-class Child(EventMethodDispatcher):
- def __init__(self, parent):
- self._parent = parent
- if parent is not None:
- parent.children.append(self)
-
- @property
- def parent(self):
- return self._parent
-
- @parent.setter
- def parent(self, parent):
- if self._parent is not None:
- self._parent.children.remove(self)
- self._parent = parent
- if parent is not None:
- parent.children.append(self)
- if "root" in self.__dict__:
- self.__dict__.pop("root")
-
- @cached_property
- def root(self):
- parent = self.parent
- while hasattr(parent, "parent"):
- parent = parent.root or parent.parent
- if not isinstance(parent, Root):
- raise AttributeError(f"No root found for {self}")
- return parent
-
- @property
- def dirty(self):
- return self.root.dirty
-
- @dirty.setter
- def dirty(self, value):
- self.root.dirty = value
-
- @cached_property
- def font(self):
- return self.root.font
-
- @property
- def surf(self):
- parent = self.parent
- while not hasattr(parent, "surf"):
- parent = parent.root or parent.parent
- return parent.surf
-
- @property
- def running(self):
- return self.root.running
-
- @property
- def stop_event(self):
- return self.root.stop_event
-
-
-class Root(FocusRootMixin, Parent):
- BACKGROUND_COLOR: pygame.Color
-
- def __init__(self, surf, font=None):
- super().__init__()
- self.font = font
- self.running = True
- self.dirty = False
- self.surf = surf
- self.clock = pygame.time.Clock()
- self.stop_event = False
- self.root = self
-
- def handle_quit(self, _=None):
- self.running = False
-
- KEY_METHODS = {frozenset(set()): {pygame.K_ESCAPE: handle_quit}}
-
- def handle_event(self, ev):
- if ev.type in (pygame.WINDOWEXPOSED, pygame.ACTIVEEVENT):
- self.dirty = True
- return
- super().handle_event(ev)
-
- def draw(self):
- if hasattr(self, "BACKGROUND_COLOR"):
- self.surf.fill(self.BACKGROUND_COLOR)
- super().draw()
-
- def run(self):
- while True:
- for ev in pygame.event.get():
- self.stop_event = False
- self.handle_event(ev)
- if not self.running:
- break
- if not self.running:
- break
- self.update()
- if self.dirty:
- self.draw()
- pygame.display.update()
- self.dirty = False
- self.clock.tick(60)
import pygame
-from .base import Child
+from .child import Child
class Button(Child):
--- /dev/null
+from functools import cached_property
+
+from .event_method_dispatcher import EventMethodDispatcher
+from .root import Root
+
+
+class Child(EventMethodDispatcher):
+ def __init__(self, parent):
+ self._parent = parent
+ if parent is not None:
+ parent.children.append(self)
+
+ @property
+ def parent(self):
+ return self._parent
+
+ @parent.setter
+ def parent(self, parent):
+ if self._parent is not None:
+ self._parent.children.remove(self)
+ self._parent = parent
+ if parent is not None:
+ parent.children.append(self)
+ if "root" in self.__dict__:
+ self.__dict__.pop("root")
+
+ @cached_property
+ def root(self):
+ parent = self.parent
+ while hasattr(parent, "parent"):
+ parent = parent.root or parent.parent
+ if not isinstance(parent, Root):
+ raise AttributeError(f"No root found for {self}")
+ return parent
+
+ @property
+ def dirty(self):
+ return self.root.dirty
+
+ @dirty.setter
+ def dirty(self, value):
+ self.root.dirty = value
+
+ @cached_property
+ def font(self):
+ return self.root.font
+
+ @property
+ def surf(self):
+ parent = self.parent
+ while not hasattr(parent, "surf"):
+ parent = parent.root or parent.parent
+ return parent.surf
+
+ @property
+ def running(self):
+ return self.root.running
+
+ @property
+ def stop_event(self):
+ return self.root.stop_event
import pygame
-from .base import Parent
from .button import Button
from .modal import Modal
+from .parent import Parent
class DropDownMenu(Modal):
--- /dev/null
+from functools import partial
+
+import pygame
+
+
+class EventMethodDispatcher:
+ MODS = (pygame.KMOD_CTRL, pygame.KMOD_ALT, pygame.KMOD_META, pygame.KMOD_SHIFT)
+ KEY_METHODS = {}
+
+ def get_key_method(self, key, mod):
+ mods = set()
+ for mask in self.MODS:
+ if mod & mask:
+ mods.add(mask)
+ method = self.KEY_METHODS.get(frozenset(mods), {}).get(key)
+ if method is not None:
+ return partial(method, self)
+ return None
+
+ def handle_keydown(self, ev):
+ if not self.KEY_METHODS:
+ return
+ key_method = self.get_key_method(ev.key, ev.mod)
+ if key_method is not None:
+ key_method()
+
+ def handle_event(self, ev):
+ method_name = f"handle_{pygame.event.event_name(ev.type).lower()}"
+ if hasattr(self, method_name):
+ getattr(self, method_name)(ev)
+
+ def update(self):
+ pass
+
+ def draw(self):
+ pass
-from .base import Child
+from .child import Child
class FPSWidget(Child):
-from .base import Child
+from .child import Child
class Icon(Child):
-from .base import Child
+from .child import Child
class Label(Child):
import pygame
-from .base import Child,Parent
+from .child import Child
from .focus import FocusableMixin
+from .parent import Parent
class Modal(FocusableMixin, Parent, Child):
--- /dev/null
+from .event_method_dispatcher import EventMethodDispatcher
+
+
+class Parent(EventMethodDispatcher):
+ root: "root.Root"
+ running: bool
+ stop_event: bool
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.children = []
+
+ def handle_event(self, ev):
+ super().handle_event(ev)
+ if not self.running or self.stop_event:
+ return
+ for child in self.children:
+ child.handle_event(ev)
+ if not self.running or self.stop_event:
+ break
+
+ def update(self):
+ super().update()
+ for child in self.children:
+ child.update()
+
+ def draw(self):
+ super().draw()
+ for child in self.children:
+ child.draw()
import pygame
-from .base import Child
+from .child import Child
class Rect(Child):
--- /dev/null
+import pygame
+
+from .parent import Parent
+from .focus import FocusRootMixin
+
+
+class Root(FocusRootMixin, Parent):
+ BACKGROUND_COLOR: pygame.Color
+
+ def __init__(self, surf, font=None):
+ super().__init__()
+ self.font = font
+ self.running = True
+ self.dirty = False
+ self.surf = surf
+ self.clock = pygame.time.Clock()
+ self.stop_event = False
+ self.root = self
+
+ def handle_quit(self, _=None):
+ self.running = False
+
+ KEY_METHODS = {frozenset(set()): {pygame.K_ESCAPE: handle_quit}}
+
+ def handle_event(self, ev):
+ if ev.type in (pygame.WINDOWEXPOSED, pygame.ACTIVEEVENT):
+ self.dirty = True
+ return
+ super().handle_event(ev)
+
+ def draw(self):
+ if hasattr(self, "BACKGROUND_COLOR"):
+ self.surf.fill(self.BACKGROUND_COLOR)
+ super().draw()
+
+ def run(self):
+ while True:
+ for ev in pygame.event.get():
+ self.stop_event = False
+ self.handle_event(ev)
+ if not self.running:
+ break
+ if not self.running:
+ break
+ self.update()
+ if self.dirty:
+ self.draw()
+ pygame.display.update()
+ self.dirty = False
+ self.clock.tick(60)
import pygame
-from .base import Child, Parent
+from .child import Child
+from .parent import Parent
class Scroll(Parent, Child):
import pygame
-from .base import Child
+from .child import Child
class Slider(Child):
import pygame
-from .base import Child, Parent
+from .child import Child
from .button import Button
+from .parent import Parent
from .text_input import TextInput
from colorsys import hsv_to_rgb
from time import time
-from .base import Child
+from .child import Child
class EaseInOutElastic:
import pygame
-from .base import Child, Parent
from .button import Button
+from .child import Child
+from .parent import Parent
class TabBar(Parent, Child):
import pygame
-from .base import Child
+from .child import Child
from .focus import FocusableMixin