]> git.mar77i.info Git - zenbook_conf/commitdiff
consolidate component interactions
authormar77i <mar77i@protonmail.ch>
Wed, 18 Dec 2024 01:46:37 +0000 (02:46 +0100)
committermar77i <mar77i@protonmail.ch>
Wed, 18 Dec 2024 01:46:37 +0000 (02:46 +0100)
ui.py
vectors.py
zenbook_conf.py

diff --git a/ui.py b/ui.py
index c70307cba20949a0c12f6c6dc8173e9cc8eda70f..48ee7cd189f56a2205ebe1671e967368f2ec1e2b 100755 (executable)
--- a/ui.py
+++ b/ui.py
@@ -6,8 +6,6 @@ from colorsys import hsv_to_rgb
 
 import pygame
 
-from bluetooth import BluetoothConf
-
 tau = 2 * pi
 
 
@@ -32,7 +30,8 @@ class Switch:
     MOVE_FOR_SEC = 1
     EASE = staticmethod(ease_in_out_elastic((5 ** .5 - 1) / 2))
 
-    def __init__(self, rect, update_callback, setting=False):
+    def __init__(self, parent, rect, update_callback, setting=False):
+        self.parent = parent
         self.rect = rect
         self.update_callback = update_callback
         if setting is not None and not isinstance(setting, bool):
@@ -41,23 +40,8 @@ class Switch:
         self.moving_since = nan
         self.flip_again = False
 
-    def handle_mousebuttondown(self, ev):
-        if ev.button == 1 and self.rect.collidepoint(ev.pos):
-            if self.moving_since is not nan:
-                self.flip_again = True
-            else:
-                offset = self.MOVE_FOR_SEC / 2 if self.setting is None else 0
-                self.setting = bool(self.setting) ^ True
-                self.moving_since = time() - offset
-
-    def update(self, new_value=None):
-        if new_value is not None and new_value != self.setting:
-            self.setting = new_value
-            self.moving_since = time()
-        return self.moving_since is not nan
-
-    def draw(self, surf):
-        pygame.draw.rect(surf, "gray", self.rect, 8)
+    def draw(self):
+        pygame.draw.rect(self.parent.surf, "gray", self.rect, 8)
         t = time()
         if t > self.moving_since + self.MOVE_FOR_SEC:
             self.update_callback(self.setting)
@@ -88,90 +72,123 @@ class Switch:
             args = (1 / 3, 2 * normalized_current, 0.5 + normalized_current * 0.5)
         rgb = hsv_to_rgb(*args)
         pygame.draw.circle(
-            surf,
+            self.parent.surf,
             pygame.Color(*(int(x * 255) for x in rgb)),
             (base_left + eased_current * movement_width, self.rect.top + base_radius),
             base_radius
         )
 
+    def update(self, new_value=None):
+        if new_value is not None and new_value != self.setting:
+            self.setting = new_value
+            self.moving_since = time()
+        if self.moving_since is not nan:
+            self.parent.dirty = True
+
+    def handle_mousebuttondown(self, ev):
+        if ev.button == 1 and self.rect.collidepoint(ev.pos):
+            if self.moving_since is not nan:
+                self.flip_again = True
+            else:
+                offset = self.MOVE_FOR_SEC / 2 if self.setting is None else 0
+                self.setting = bool(self.setting) ^ True
+                self.moving_since = time() - offset
+
 
 class Button:
-    def __init__(self, rect, font, label, callback):
+    def __init__(self, parent, rect, label, callback):
+        self.parent = parent
         self.rect = rect
-        self.font = font
         self.label = label
         self.pushed = False
         self.callback = callback
 
-    def draw(self, surf):
+    def draw(self):
         if not self.pushed:
-            pygame.draw.rect(surf, "gray", self.rect, 8)
-            fs = self.font.render(self.label, True, "gray")
+            frame_color = "gray"
+            fs = self.parent.font.render(self.label, True, "gray")
         else:
-            pygame.draw.rect(surf, "darkgray", self.rect)
-            pygame.draw.rect(surf, "lightgray", self.rect, 4)
-            fs = self.font.render(self.label, True, "black")
+            pygame.draw.rect(self.parent.surf, "darkgray", self.rect)
+            frame_color = "lightgray"
+            fs = self.parent.font.render(self.label, True, "black")
+        pygame.draw.rect(self.parent.surf, frame_color, self.rect, 8)
         fs_size = fs.get_size()
         center = self.rect.center
-        surf.blit(fs, (center[0] - fs_size[0] // 2, center[1] - fs_size[1] // 2))
-
-    def handle_event(self, ev):
-        if ev.type == pygame.MOUSEBUTTONDOWN:
-            if ev.button == 1 and self.rect.collidepoint(ev.pos):
-                self.pushed = True
-                return True
-        elif ev.type == pygame.MOUSEBUTTONUP:
-            if ev.button == 1 and self.pushed and self.rect.collidepoint(ev.pos):
-                self.pushed = False
-                self.callback()
-                return True
-        elif ev.type == pygame.MOUSEMOTION:
-            if ev.buttons[0] and self.pushed and not self.rect.collidepoint(ev.pos):
-                self.pushed = False
-                return True
-        return False
-
-
-def main():
-    pygame.init()
-    surf = pygame.display.set_mode((800, 600))
-    clock = pygame.time.Clock()
-    font = pygame.font.Font(None, size=64)
-    bc = BluetoothConf()
-    switch = Switch(pygame.Rect((64, 64), (256, 128)), bc.update, bc.conf)
-
-    def cb():
-        switch.update(not bc.conf)
-        bc.update(not bc.conf)
-
-    button = Button(pygame.Rect((64, 256), (384, 128)), font, "Apply", cb)
-    running = True
-    dirty = False
-    while True:
-        for ev in pygame.event.get():
-            if ev.type == pygame.QUIT:
-                running = False
-                break
-            elif ev.type == pygame.WINDOWEXPOSED:
-                dirty = True
-            elif ev.type == pygame.KEYDOWN:
-                if ev.key == pygame.K_ESCAPE:
-                    running = False
-                    break
-            elif ev.type == pygame.MOUSEBUTTONDOWN:
-                switch.handle_mousebuttondown(ev)
-            dirty |= button.handle_event(ev)
-        if not running:
-            break
-        dirty |= switch.update()
-        if dirty:
-            surf.fill("black")
-            switch.draw(surf)
-            button.draw(surf)
-            pygame.display.update()
-            dirty = False
-        clock.tick(60)
-
-
-if __name__ == "__main__":
-    main()
+        self.parent.surf.blit(
+            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
+            self.parent.dirty = True
+
+    def handle_mousebuttonup(self, ev):
+        if ev.button == 1 and self.pushed and self.rect.collidepoint(ev.pos):
+            self.pushed = False
+            self.callback()
+            self.parent.dirty = True
+
+    def handle_mousemotion(self, ev):
+        if not self.pushed:
+            return
+        if ev.buttons[0] and not self.rect.collidepoint(ev.pos):
+            self.pushed = False
+            self.parent.dirty = True
+
+
+class IconButton:
+    def __init__(self, parent, name, shape, shape_size, rect):
+        self.parent = parent
+        self.name = name
+        self.shape = shape
+        self.shape_size = shape_size
+        self.rect = rect
+
+    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
+        self.shape.draw(
+            self.parent.surf,
+            (center[0] - full_size[0] // 2, center[1] - full_size[1] // 2),
+            units,
+            "white",
+        )
+
+    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:
+    def __init__(self, parent, shape, pos):
+        self.parent = 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 679a7c2ccceae74b83ce91cbb6ea9ce42be079a9..c157f79f0aaaa1c253382ec6f9296c49050083ff 100755 (executable)
@@ -258,6 +258,15 @@ stylus = Shapes(
         StrokeLine((11, 11), (12, 12), 1),
     ]
 )
+bluetooth = Shapes(
+    [
+        StrokeLine((10, 2), (15, 6), 1.5),
+        StrokeLine((15, 6), (5, 14), 1.5),
+        StrokeLine((10, 2), (10, 19), 1.5),
+        StrokeLine((10, 19), (15, 15), 1.5),
+        StrokeLine((15, 15), (5, 7), 1.5),
+    ]
+)
 shapes = [
     {
         "shape": laptop_single,
@@ -279,6 +288,10 @@ shapes = [
         "shape": stylus,
         "pos": (600, 600),
     },
+    {
+        "shape": bluetooth,
+        "pos": (1100, 600),
+    },
 ]
 
 
index afe2abcf74e6bd7c4e622074d349dcc42858a0bc..5d7479b846254cff485037edd0b35a42b8941ade 100755 (executable)
@@ -5,31 +5,20 @@ from functools import partial
 import pygame
 
 from bluetooth import BluetoothConf
-from ui import Button, Switch
-from vectors import laptop_double, laptop_single, laptop_vertical, touchscreen, stylus
+from ui import Button, Icon, IconButton, Switch
+from vectors import (
+    bluetooth,
+    laptop_double,
+    laptop_single,
+    laptop_vertical,
+    touchscreen,
+    stylus,
+)
 from xinput import XinputConf
 from xrandr import XrandrConf
 
 
 class ZenbookConf:
-    SHAPES = (
-        {
-            "name": "single",
-            "shape": laptop_single,
-            "rect": pygame.Rect((68, 68), (416, 416)),
-        },
-        {
-            "name": "double",
-            "shape": laptop_double,
-            "rect": pygame.Rect((568, 68), (416, 416)),
-        },
-        {
-            "name": "vertical",
-            "shape": laptop_vertical,
-            "rect": pygame.Rect((1068, 68), (416, 416)),
-        },
-    )
-
     def __init__(self):
         pygame.init()
         self.surf = pygame.display.set_mode((1536, 1200))
@@ -41,32 +30,76 @@ class ZenbookConf:
         self.xinput_conf = XinputConf(self.xrandr_conf)
         self.bluetooth_conf = BluetoothConf()
         self.current_fps = -1
-        self.bt_switch = Switch(
+        bt_switch = Switch(
+            self,
             pygame.Rect((128, 552), (256, 128)),
             self.bluetooth_conf.update,
             self.bluetooth_conf.conf
         )
-        self.touch_switch = Switch(
+        touch_switch = Switch(
+            self,
             pygame.Rect((128, 748), (256, 128)),
             partial(self.xinput_conf.update_by_type, "touchpad"),
             self.xinput_conf.conf_by_type("touchpad"),
         )
-        self.touch_button = Button(
-            pygame.Rect((784, 748), (384, 128)),
-            self.font,
-            "Re-apply",
-            partial(self.xinput_conf.reapply_by_type, "touchpad")
-        )
-        self.stylus_switch = Switch(
+        stylus_switch = Switch(
+            self,
             pygame.Rect((128, 944), (256, 128)),
             partial(self.xinput_conf.update_by_type, "stylus"),
             self.xinput_conf.conf_by_type("stylus"),
         )
-        self.stylus_button = Button(
-            pygame.Rect((784, 944), (384, 128)),
-            self.font,
-            "Re-apply",
-            partial(self.xinput_conf.reapply_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")
+            ),
         )
 
     def handle_event(self, ev):
@@ -79,73 +112,25 @@ class ZenbookConf:
             if ev.key == pygame.K_ESCAPE:
                 self.running = False
                 return False
-        elif ev.type == pygame.MOUSEBUTTONDOWN:
-            for item in self.SHAPES:
-                if item["rect"].collidepoint(ev.pos):
-                    self.xrandr_conf.update(item["name"])
-                    if item["name"] != "single":
-                        self.bluetooth_conf.update(True)
-                        self.bt_switch.update(True)
-                    settings_per_device_type = {
-                        "touchpad": self.touch_switch.setting,
-                        "stylus": self.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
-            else:
-                self.bt_switch.handle_mousebuttondown(ev)
-                self.touch_switch.handle_mousebuttondown(ev)
-                self.stylus_switch.handle_mousebuttondown(ev)
-        self.dirty |= self.touch_button.handle_event(ev)
-        self.dirty |= self.stylus_button.handle_event(ev)
+        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):
-        self.dirty |= self.bt_switch.update()
-        self.dirty |= self.touch_switch.update()
-        self.dirty |= self.stylus_switch.update()
+        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 item in self.SHAPES:
-            if self.xrandr_conf.is_active(item["name"]):
-                pygame.draw.rect(self.surf, "lime", item["rect"], 8)
-            else:
-                pygame.draw.rect(self.surf, "gray", item["rect"], 8)
-            item["shape"].draw(
-                self.surf,
-                (item["rect"].left + 32, item["rect"].top + 32),
-                (16, 16),
-                "white",
-            )
-
-        self.bt_switch.draw(self.surf)
-        fs = self.font.render("Bluetooth", True, "gray")
-        r = self.bt_switch.rect
-        self.surf.blit(fs, (r.right + 68, r.centery - fs.get_height() // 2))
-
-        self.touch_switch.draw(self.surf)
-        touchscreen.draw(
-            self.surf,
-            (self.touch_switch.rect.right + 68, self.touch_switch.rect.centery - 88),
-            (8, 8),
-            "gray",
-        )
-        self.touch_button.draw(self.surf)
-
-        self.stylus_switch.draw(self.surf)
-        stylus.draw(
-            self.surf,
-            (self.stylus_switch.rect.right + 68, self.stylus_switch.rect.centery - 88),
-            (8, 8),
-            "gray",
-        )
-        self.stylus_button.draw(self.surf)
+        for child in self.children:
+            child.draw()
 
     def run(self):
         while True: