]> git.mar77i.info Git - zenbook_conf/commitdiff
add some hierarchical structure
authormar77i <mar77i@protonmail.ch>
Thu, 19 Dec 2024 16:16:06 +0000 (17:16 +0100)
committermar77i <mar77i@protonmail.ch>
Thu, 19 Dec 2024 16:16:06 +0000 (17:16 +0100)
ui.py
zenbook_conf.py

diff --git a/ui.py b/ui.py
index 48ee7cd189f56a2205ebe1671e967368f2ec1e2b..34d88d6d8f4dc1e7c486d63021c04e17bc144d47 100755 (executable)
--- a/ui.py
+++ b/ui.py
@@ -9,6 +9,71 @@ import pygame
 tau = 2 * pi
 
 
+class UIParent:
+    BACKGROUND_COLOR = None
+
+    def __init__(self, surf, font):
+        self.surf = surf
+        self.font = font
+        self.running = True
+        self.dirty = False
+        self.children = []
+        self.clock = pygame.time.Clock()
+
+    def handle_event(self, ev):
+        if ev.type == pygame.QUIT:
+            self.running = False
+            return False
+        elif ev.type == pygame.WINDOWEXPOSED:
+            self.dirty = True
+        elif ev.type == pygame.KEYDOWN:
+            if ev.key == pygame.K_ESCAPE:
+                self.running = False
+                return False
+        method_name = f"handle_{pygame.event.event_name(ev.type).lower()}"
+        for child in self.children:
+            if not hasattr(child, method_name):
+                continue
+            getattr(child, method_name)(ev)
+        return True
+
+    def update(self):
+        for child in self.children:
+            child.update()
+
+    def draw(self):
+        background_color = getattr(self, "BACKGROUND_COLOR", None)
+        if background_color is not None:
+            self.surf.fill(background_color)
+        for child in self.children:
+            child.draw()
+
+    def run(self):
+        while True:
+            for ev in pygame.event.get():
+                if not self.handle_event(ev):
+                    break
+            if not self.running:
+                break
+            self.update()
+            if self.dirty:
+                self.draw()
+                pygame.display.update()
+                self.dirty = False
+            self.clock.tick(60)
+
+
+class UIChild:
+    def __init__(self, parent):
+        self.parent = parent
+
+    def draw(self):
+        pass
+
+    def update(self):
+        pass
+
+
 def ease_in_out_elastic(mag):
     p = 1 - mag
     s = p / tau * asin(1)
@@ -26,12 +91,12 @@ def ease_in_out_elastic(mag):
     return inner
 
 
-class Switch:
+class Switch(UIChild):
     MOVE_FOR_SEC = 1
     EASE = staticmethod(ease_in_out_elastic((5 ** .5 - 1) / 2))
 
     def __init__(self, parent, rect, update_callback, setting=False):
-        self.parent = parent
+        super().__init__(parent)
         self.rect = rect
         self.update_callback = update_callback
         if setting is not None and not isinstance(setting, bool):
@@ -55,7 +120,7 @@ class Switch:
             if self.setting is None:
                 current = 0.5
             else:
-                current = min(max(self.setting, 0), 1)
+                current = min(max(int(self.setting), 0), 1)
         else:
             current = (t - self.moving_since) / self.MOVE_FOR_SEC
             if not self.setting:
@@ -95,9 +160,9 @@ class Switch:
                 self.moving_since = time() - offset
 
 
-class Button:
+class Button(UIChild):
     def __init__(self, parent, rect, label, callback):
-        self.parent = parent
+        super().__init__(parent)
         self.rect = rect
         self.label = label
         self.pushed = False
@@ -118,9 +183,6 @@ class Button:
             fs, (center[0] - fs_size[0] // 2, center[1] - fs_size[1] // 2)
         )
 
-    def update(self):
-        pass
-
     def handle_mousebuttondown(self, ev):
         if ev.button == 1 and self.rect.collidepoint(ev.pos):
             self.pushed = True
@@ -140,55 +202,34 @@ class Button:
             self.parent.dirty = True
 
 
-class IconButton:
-    def __init__(self, parent, name, shape, shape_size, rect):
-        self.parent = parent
-        self.name = name
+class IconButton(Button):
+    def __init__(self, parent, shape, shape_size, rect, callback, is_active):
+        super().__init__(parent, rect, None, callback)
         self.shape = shape
         self.shape_size = shape_size
-        self.rect = rect
+        self.is_active = is_active
 
     def draw(self):
-        color = "lime " if self.parent.xrandr_conf.is_active(self.name) else "gray"
-        pygame.draw.rect(self.parent.surf, color, self.rect, 8)
         units = (16, 16)
         full_size = (units[0] * self.shape_size[0], units[1] * self.shape_size[1])
         center = self.rect.center
+        if self.pushed:
+            pygame.draw.rect(self.parent.surf, "honeydew4", self.rect)
         self.shape.draw(
             self.parent.surf,
             (center[0] - full_size[0] // 2, center[1] - full_size[1] // 2),
             units,
-            "white",
+            "black" if self.pushed else "white",
         )
+        color = "lime" if self.is_active() else ("red" if self.pushed else "gray")
+        pygame.draw.rect(self.parent.surf, color, self.rect, 8)
 
-    def update(self):
-        pass
 
-    def handle_mousebuttondown(self, ev):
-        if not self.rect.collidepoint(ev.pos):
-            return
-        self.parent.xrandr_conf.update(self.name)
-        if self.name != "single":
-            self.parent.bluetooth_conf.update(True)
-            self.parent.bt_switch.update(True)
-        settings_per_device_type = {
-            "touchpad": self.parent.touch_switch.setting,
-            "stylus": self.parent.stylus_switch.setting,
-        }
-        for device_type, setting in settings_per_device_type.items():
-            if setting is not None:
-                self.parent.xinput_conf.update_by_type(device_type, setting)
-        self.parent.dirty = True
-
-
-class Icon:
+class Icon(UIChild):
     def __init__(self, parent, shape, pos):
-        self.parent = parent
+        super().__init__(parent)
         self.shape = shape
         self.pos = pos
 
-    def update(self):
-        pass
-
     def draw(self):
         self.shape.draw(self.parent.surf, self.pos, (8, 8), "gray")
index 5d7479b846254cff485037edd0b35a42b8941ade..19aece51ea148ece63460100bd69f6ab211d3698 100755 (executable)
@@ -5,7 +5,7 @@ from functools import partial
 import pygame
 
 from bluetooth import BluetoothConf
-from ui import Button, Icon, IconButton, Switch
+from ui import Button, Icon, IconButton, Switch, UIParent
 from vectors import (
     bluetooth,
     laptop_double,
@@ -18,18 +18,41 @@ from xinput import XinputConf
 from xrandr import XrandrConf
 
 
-class ZenbookConf:
+class FPSMixin:
+    FPS_COLOR = "yellow"
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.current_fps = None
+
+    def update(self):
+        super().update()
+        new_fps = int(self.clock.get_fps())
+        if self.current_fps != new_fps:
+            self.current_fps = new_fps
+            self.dirty = True
+
+    def draw(self):
+        super().draw()
+        surf_size = self.surf.get_size()
+        fs = self.font.render(f"{int(self.current_fps)} FPS", True, self.FPS_COLOR)
+        fs_size = fs.get_size()
+        self.surf.blit(
+            fs, (surf_size[0] - fs_size[0] - 7, surf_size[1] - fs_size[1] - 7)
+        )
+
+
+class ZenbookConf(FPSMixin, UIParent):
+    BACKGROUND_COLOR = 0x333333
+
     def __init__(self):
         pygame.init()
-        self.surf = pygame.display.set_mode((1536, 1200))
-        self.font = pygame.font.Font(None, size=96)
-        self.clock = pygame.time.Clock()
-        self.running = True
-        self.dirty = False
+        super().__init__(
+            pygame.display.set_mode((1536, 1200)), pygame.font.Font(None, size=96),
+        )
         self.xrandr_conf = XrandrConf()
         self.xinput_conf = XinputConf(self.xrandr_conf)
         self.bluetooth_conf = BluetoothConf()
-        self.current_fps = -1
         bt_switch = Switch(
             self,
             pygame.Rect((128, 552), (256, 128)),
@@ -48,103 +71,91 @@ class ZenbookConf:
             partial(self.xinput_conf.update_by_type, "stylus"),
             self.xinput_conf.conf_by_type("stylus"),
         )
-        self.children = (
-            IconButton(
-                self,
-                "single",
-                laptop_single,
-                (22, 22),
-                pygame.Rect((68, 68), (416, 416)),
-            ),
-            IconButton(
-                self,
-                "double",
-                laptop_double,
-                (22, 22),
-                pygame.Rect((568, 68), (416, 416)),
-            ),
-            IconButton(
-                self,
-                "vertical",
-                laptop_vertical,
-                (22, 22),
-                pygame.Rect((1068, 68), (416, 416)),
-            ),
-            bt_switch,
-            Icon(
-                self,
-                bluetooth,
-                (bt_switch.rect.right + 68, bt_switch.rect.centery - 88),
-            ),
-            touch_switch,
-            Icon(
-                self,
-                touchscreen,
-                (touch_switch.rect.right + 68, touch_switch.rect.centery - 88),
-            ),
-            stylus_switch,
-            Icon(
-                self,
-                stylus,
-                (stylus_switch.rect.right + 68, stylus_switch.rect.centery - 88),
-            ),
-            Button(
-                self,
-                pygame.Rect((784, 748), (384, 128)),
-                "Re-apply",
-                partial(self.xinput_conf.reapply_by_type, "touchpad")
-            ),
-            Button(
-                self,
-                pygame.Rect((784, 944), (384, 128)),
-                "Re-apply",
-                partial(self.xinput_conf.reapply_by_type, "stylus")
-            ),
+        self.children.extend(
+            (
+                IconButton(
+                    self,
+                    laptop_single,
+                    (22, 22),
+                    pygame.Rect((68, 68), (416, 416)),
+                    partial(
+                        self.laptop_cb, "single", bt_switch, touch_switch, stylus_switch
+                    ),
+                    partial(self.laptop_is_active, "single"),
+                ),
+                IconButton(
+                    self,
+                    laptop_double,
+                    (22, 22),
+                    pygame.Rect((568, 68), (416, 416)),
+                    partial(
+                        self.laptop_cb, "double", bt_switch, touch_switch, stylus_switch
+                    ),
+                    partial(self.laptop_is_active, "double"),
+                ),
+                IconButton(
+                    self,
+                    laptop_vertical,
+                    (22, 22),
+                    pygame.Rect((1068, 68), (416, 416)),
+                    partial(
+                        self.laptop_cb,
+                        "vertical",
+                        bt_switch,
+                        touch_switch,
+                        stylus_switch,
+                    ),
+                    partial(self.laptop_is_active, "vertical"),
+                ),
+                bt_switch,
+                Icon(
+                    self,
+                    bluetooth,
+                    (bt_switch.rect.right + 68, bt_switch.rect.centery - 88),
+                ),
+                touch_switch,
+                Icon(
+                    self,
+                    touchscreen,
+                    (touch_switch.rect.right + 68, touch_switch.rect.centery - 88),
+                ),
+                stylus_switch,
+                Icon(
+                    self,
+                    stylus,
+                    (stylus_switch.rect.right + 68, stylus_switch.rect.centery - 88),
+                ),
+                Button(
+                    self,
+                    pygame.Rect((784, 748), (384, 128)),
+                    "Re-apply",
+                    partial(self.xinput_conf.reapply_by_type, "touchpad")
+                ),
+                Button(
+                    self,
+                    pygame.Rect((784, 944), (384, 128)),
+                    "Re-apply",
+                    partial(self.xinput_conf.reapply_by_type, "stylus")
+                ),
+            )
         )
 
-    def handle_event(self, ev):
-        if ev.type == pygame.QUIT:
-            self.running = False
-            return False
-        elif ev.type == pygame.WINDOWEXPOSED:
-            self.dirty = True
-        elif ev.type == pygame.KEYDOWN:
-            if ev.key == pygame.K_ESCAPE:
-                self.running = False
-                return False
-        method_name = f"handle_{pygame.event.event_name(ev.type).lower()}"
-        for child in self.children:
-            method = getattr(child, method_name, None)
-            if method is None:
-                continue
-            method(ev)
-        return True
-
-    def update(self):
-        for child in self.children:
-            child.update()
-        if self.clock.get_fps() != self.current_fps:
-            self.current_fps = int(self.clock.get_fps())
-            self.dirty = True
-
-    def draw(self):
-        self.surf.fill(0x333333)
-        for child in self.children:
-            child.draw()
+    def laptop_cb(self, name, bt_switch, touch_switch, stylus_switch):
+        self.xrandr_conf.update(name)
+        if name != "single":
+            self.bluetooth_conf.update(True)
+            bt_switch.update(True)
+        settings_per_device_type = {
+            "touchpad": touch_switch.setting,
+            "stylus": stylus_switch.setting,
+        }
+        for device_type, setting in settings_per_device_type.items():
+            if setting is not None:
+                self.xinput_conf.update_by_type(device_type, setting)
+        self.dirty = True
 
-    def run(self):
-        while True:
-            for ev in pygame.event.get():
-                if not self.handle_event(ev):
-                    break
-            if not self.running:
-                break
-            self.update()
-            if self.dirty:
-                self.draw()
-                pygame.display.update()
-                self.dirty = False
-            self.clock.tick(60)
+    def laptop_is_active(self, name):
+        return self.xrandr_conf.is_active(name)
 
 
 if __name__ == "__main__":