]> git.mar77i.info Git - zenbook_gui/commitdiff
cleanup: add enabled flag rather than reparenting with tab_bar
authormar77i <mar77i@protonmail.ch>
Fri, 14 Feb 2025 00:45:53 +0000 (01:45 +0100)
committermar77i <mar77i@protonmail.ch>
Fri, 14 Feb 2025 00:50:49 +0000 (01:50 +0100)
12 files changed:
ui/button.py
ui/child.py
ui/drop_down.py
ui/focus.py
ui/icon_button.py
ui/modal.py
ui/parent.py
ui/root.py
ui/spinner.py
ui/tab_bar.py
ui/text_input.py
zenbook_conf/zenbook_conf.py

index 26345cfa29006d59a0f693988479a9b49f205b8e..15cf575d179971b3dc3b21cdd476b600f7e9e82b 100644 (file)
@@ -4,12 +4,12 @@ from .child import Child
 
 
 class Button(Child):
-    def __init__(self, parent, rect, value, callback, is_active=False):
+    def __init__(self, parent, rect, value, callback, highlight=False):
         super().__init__(parent)
         self.rect = rect
         self.value = value
         self.callback = callback
-        self.is_active = is_active
+        self.highlight = highlight
         self.pushed = False
 
     def draw_value(self, color):
@@ -20,7 +20,7 @@ class Button(Child):
 
     def draw(self):
         if not self.pushed:
-            value_color = "lime" if self.is_active else "gray"
+            value_color = "lime" if self.highlight else "gray"
             colors = ("black", value_color, value_color)
         else:
             colors = ("darkgray", "lightgray", "black")
index d70296d09658d599d93203ad5d7bfeab22ab7315..35e0a84f897d1d042cde52c7a7aa123a9dbc8334 100644 (file)
@@ -5,24 +5,10 @@ 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")
+    def __init__(self, parent, enabled=True):
+        self.parent = parent
+        parent.children.append(self)
+        self.enabled = enabled
 
     @cached_property
     def root(self):
index ac48dee40c10b1e419ec4c965d26984759cd809c..8a76442c604868b20912bcba70923a63f8b7f10d 100644 (file)
@@ -4,7 +4,6 @@ import pygame
 
 from .button import Button
 from .modal import Modal
-from .parent import Parent
 
 
 class DropDownMenu(Modal):
@@ -36,6 +35,6 @@ class DropDownMenu(Modal):
 
 
 class DropDown(Button):
-    def __init__(self, parent, rect, value, entries, callback, is_active=False):
+    def __init__(self, parent, rect, value, entries, callback, highlight=False):
         self.dropdown_menu = DropDownMenu(parent, rect, entries, callback)
-        super().__init__(parent, rect, value, self.dropdown_menu.activate, is_active)
+        super().__init__(parent, rect, value, self.dropdown_menu.activate, highlight)
index 07fe6d177254a6f49717aefba0866a92f8a8cdc7..2d3c609c0d7909eb1cba479af0b3149dafc21dec 100644 (file)
@@ -1,37 +1,20 @@
-import pygame
+from .root import Root
 
 
-class FocusRootMixin:
-    surf: pygame.Surface
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.focus_stack: list[FocusableMixin | FocusRootMixin] = [self]
-
-    @property
-    def active(self):
-        return self.focus_stack[-1] is self
-
-    def handle_event(self, ev):
-        focused = self.focus_stack[-1]
-        (super() if focused is self else focused).handle_event(ev)
-
-
-class FocusableMixin:
-    root: FocusRootMixin
+class Focusable:
+    root: Root
+    dirty: bool
 
     @property
-    def active(self):
+    def focused(self):
         return self.root.focus_stack[-1] is self
 
     def activate(self):
-        focus_stack = self.root.focus_stack
-        assert self not in focus_stack
-        focus_stack.append(self)
+        assert self not in self.root.focus_stack
+        self.root.focus_stack.append(self)
         self.dirty = True
 
     def deactivate(self):
-        focus_stack = self.root.focus_stack
-        assert self.active
-        focus_stack.pop()
+        assert self.focused
+        self.root.focus_stack.pop()
         self.dirty = True
index 9b952a6e9c36a5e02a00855af96e3ec7b4dcb5df..a08aec045eb56936b60e37482f21e1d882f2cc32 100644 (file)
@@ -12,7 +12,7 @@ class IconButton(Button):
         if self.pushed:
             pygame.draw.rect(self.surf, "honeydew4", self.rect)
         self.shape.draw(self.surf, "black" if self.pushed else "white")
-        if self.is_active:
+        if self.highlight:
             color = "lime"
         elif self.pushed:
             color = "red"
index 20c3b37a069dc381800439c25b45c38936687f6a..55808f9277760b588d45e1ad9041915a821f43e3 100644 (file)
@@ -1,33 +1,35 @@
 import pygame
 
 from .child import Child
-from .focus import FocusableMixin
+from .focus import Focusable
 from .parent import Parent
 
 
-class Modal(FocusableMixin, Parent, Child):
+class Modal(Focusable, Parent, Child):
     def __init__(self, parent):
-        super().__init__(parent)
-        self.draw = self._check_active(self.draw)
-        self.update = self._check_active(self.update)
-        self.handle_event = self._check_active(self.handle_event)
-        self.activate = self._check_active(self.activate, False)
-        self.deactivate = self._check_active(self.deactivate)
+        super().__init__(parent, False)
+        self.draw = self._check_enabled(self.draw)
+        self.update = self._check_enabled(self.update)
+        self.handle_event = self._check_enabled(self.handle_event)
+        self.activate = self._check_enabled(self.activate, False)
+        self.deactivate = self._check_enabled(self.deactivate)
 
-    def _check_active(self, method, cmp=True):
+    def _check_enabled(self, method, cmp=True):
         def inner(*args, **kwargs):
-            if self.active is cmp:
+            if self.enabled is cmp:
                 return method(*args, **kwargs)
             return None
         return inner
 
     def activate(self):
         super().activate()
+        self.enabled = True
         self.root.stop_event = True
         self.dirty = True
 
     def deactivate(self):
         super().deactivate()
+        self.enabled = False
         self.root.stop_event = True
         self.dirty = True
 
index 22fed96cc9418680309a4953c6d1f374be681014..f5e5cb47819e5d236c9b089c24c27c431dd34d87 100644 (file)
@@ -15,14 +15,24 @@ class Parent(EventMethodDispatcher):
         if not self.running or self.stop_event:
             return
         for child in self.children:
+            if not child.enabled:
+                continue
             child.handle_event(ev)
             if not self.running or self.stop_event:
                 break
 
     def update(self):
+        s = super()
+        if hasattr(s, "update"):
+            s.update()
         for child in self.children:
-            child.update()
+            if child.enabled:
+                child.update()
 
     def draw(self):
+        s = super()
+        if hasattr(s, "draw"):
+            s.draw()
         for child in self.children:
-            child.draw()
+            if child.enabled:
+                child.draw()
index 89974c69c3fa449b72210bf5e80b1dff7f46d986..6d6f24124d53dc3e6ebcf60d6b3145123f9f9512 100644 (file)
@@ -1,13 +1,14 @@
 import pygame
 
 from .parent import Parent
-from .focus import FocusRootMixin
 
 
-class Root(FocusRootMixin, Parent):
+class Root(Parent):
     BACKGROUND_COLOR: pygame.Color
 
     def __init__(self, surf, font=None):
+        from .child import Child
+
         super().__init__()
         self.font = font
         self.running = True
@@ -16,17 +17,25 @@ class Root(FocusRootMixin, Parent):
         self.clock = pygame.time.Clock()
         self.stop_event = False
         self.root = self
+        self.focus_stack: list[Root | Child] = [self]
 
     def handle_quit(self, _=None):
         self.running = False
 
     KEY_METHODS = {frozenset(set()): {pygame.K_ESCAPE: handle_quit}}
 
+    @property
+    def focused(self):
+        return self.focus_stack[-1] is self
+
     def handle_event(self, ev):
         if ev.type in (pygame.WINDOWEXPOSED, pygame.ACTIVEEVENT):
             self.dirty = True
             return
-        super().handle_event(ev)
+        focused = self.focus_stack[-1]
+        if focused is self:
+            focused = super()
+        focused.handle_event(ev)
 
     def draw(self):
         if hasattr(self, "BACKGROUND_COLOR"):
index 86bd7d37528a0e0e5973a61aa4eddb9f7209786a..ff66c0a9332912504b5b25527748a1d5d9591817 100644 (file)
@@ -15,9 +15,9 @@ class RepeatButton(Button):
     DELAY_MS = 500
     REPEAT_MS = 100
 
-    def __init__(self, parent, rect, value, callback, is_active=False):
+    def __init__(self, parent, rect, value, callback, highlight=False):
         self._pushed = False
-        super().__init__(parent, rect, value, callback, is_active)
+        super().__init__(parent, rect, value, callback, highlight)
         self.repeat_ts = None
 
     @property
index c1732ec55010fb2d2d5cdf67936b748fb5a969a2..8ee76fcdd03d10c8cc8fbfcdfee3182ce8058ef3 100644 (file)
@@ -8,11 +8,11 @@ from .parent import Parent
 
 
 class TabBar(Parent, Child):
-    def __init__(self, parent, rect, labels, groups, active):
+    def __init__(self, parent, rect, labels, groups, current_tab):
         super().__init__(parent)
         self.labels = labels
         self.groups = groups
-        self.active = active
+        self.current_tab = current_tab
         num_labels = len(labels)
         self.buttons = [
             Button(
@@ -31,23 +31,23 @@ class TabBar(Parent, Child):
 
     def update_children(self, i=None):
         if i is not None:
-            if self.active == i:
+            if self.current_tab == i:
                 return
-            self.active = i
+            self.current_tab = i
         for i, (button, group) in enumerate(zip(self.buttons, self.groups)):
-            is_group_active = i == self.active
-            if button.is_active != is_group_active:
-                button.is_active = is_group_active
+            is_current_tab = i == self.current_tab
+            if button.highlight != is_current_tab:
+                button.highlight = is_current_tab
                 self.dirty = True
             for item in group:
                 if item.parent is not self:
                     item.parent = self
-                is_child_active = item in self.children
-                if is_group_active == is_child_active:
+                is_child_enabled = item.enabled
+                if is_current_tab == is_child_enabled:
                     continue
-                if is_group_active:
-                    self.children.append(item)
-                elif is_child_active:
-                    self.children.remove(item)
+                if is_current_tab:
+                    item.enabled = True
+                elif is_child_enabled:
+                    item.enabled = False
                 self.dirty = True
         assert len(self.children) == len(set(self.children))
index 772c621b4297f25f53f43f72d3e4d0fce8cca039..3f30c358d98526cef9b1a1cf48af726b922453d5 100644 (file)
@@ -8,7 +8,7 @@ from typing import Optional, Callable
 import pygame
 
 from .child import Child
-from .focus import FocusableMixin
+from .focus import Focusable
 
 
 @dataclass
@@ -64,7 +64,7 @@ def search_same_isspace_forward(value, pos):
     return pos
 
 
-class TextInput(FocusableMixin, Child):
+class TextInput(Focusable, Child):
     def __init__(self, parent, rect, callback, value="", value_filter=None):
         super().__init__(parent)
         self.rect = rect
@@ -123,7 +123,7 @@ class TextInput(FocusableMixin, Child):
 
     def draw(self):
         pygame.draw.rect(self.surf, "black", self.rect)
-        if self.active:
+        if self.focused:
             fs = self.get_font_surface()
         else:
             fs = self.font.render(self.value, True, "gray")
@@ -162,7 +162,7 @@ class TextInput(FocusableMixin, Child):
                 self.cursor.pos = self.pos_from_offset(
                     ev.pos[0] - self.rect.left - 16 + self.offset
                 )
-        elif self.active:
+        elif self.focused:
             self.deactivate(True)
 
     @contextmanager
@@ -223,13 +223,13 @@ class TextInput(FocusableMixin, Child):
             self.cursor.pos = pos
 
     def activate(self):
-        if self.active:
+        if self.focused:
             return
         super().activate()
         self.cursor = Cursor(self.value)
 
     def deactivate(self, restore=False):
-        if not self.active:
+        if not self.focused:
             return
         if restore:
             self.value = self.cursor.old_value
@@ -257,7 +257,7 @@ class TextInput(FocusableMixin, Child):
     }
 
     def handle_keydown(self, ev):
-        if not self.active:
+        if not self.focused:
             return
         if (key_method := self.get_key_method(ev.key, ev.mod)) is not None:
             key_callback = key_method
@@ -267,7 +267,7 @@ class TextInput(FocusableMixin, Child):
             return
         with self.check_dirty():
             key_callback()
-        if self.active:
+        if self.focused:
             self.cursor.press_key(key_callback, ev.key)
 
     def handle_keyup(self, ev):
index a0ec61a5d2ee1ab8a8c1d92cc8c6ca693f955627..41f8d6688b794112da42e05ddf524986b41bdd06 100644 (file)
@@ -160,9 +160,9 @@ class ZenbookConf(Root):
         for device_type, value in settings_per_device_type.items():
             if value is not None:
                 self.xinput_conf.update_by_type(device_type, value)
-        self.single_button.is_active = self.xrandr_conf.is_active("single")
-        self.double_button.is_active = self.xrandr_conf.is_active("double")
-        self.vertical_button.is_active = self.xrandr_conf.is_active("vertical")
+        self.single_button.highlight = self.xrandr_conf.is_active("single")
+        self.double_button.highlight = self.xrandr_conf.is_active("double")
+        self.vertical_button.highlight = self.xrandr_conf.is_active("vertical")
         self.dirty = True
 
     def quit(self):