]> git.mar77i.info Git - zenbook_gui/commitdiff
import zenbook_conf
authormar77i <mar77i@protonmail.ch>
Tue, 21 Jan 2025 17:41:34 +0000 (18:41 +0100)
committermar77i <mar77i@protonmail.ch>
Tue, 21 Jan 2025 17:41:34 +0000 (18:41 +0100)
ui/__init__.py [new file with mode: 0644]
ui/ui.py
zenbook_conf.py [new file with mode: 0755]
zenbook_conf/shapes.py
zenbook_conf/zenbook_conf.py [new file with mode: 0644]

diff --git a/ui/__init__.py b/ui/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
index 3a846280102386ebd27deb561e944cec7c42b3d8..27c2035f2c19ea0092e2b6073aa63bbe7df41693 100644 (file)
--- a/ui/ui.py
+++ b/ui/ui.py
@@ -355,14 +355,21 @@ class Switch(UIChild):
         if self.moving_since is not nan:
             self.dirty = True
 
+    def set_value(self, value):
+        if value == self.value:
+            return
+        self.value = value
+        if value is None:
+            self.moving_since = time() - self.MOVE_FOR_SEC / 2
+        else:
+            self.moving_since = time()
+
     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
                 return
-            self.value = bool(self.value) ^ True
-            offset = self.MOVE_FOR_SEC / 2 if self.value is None else 0
-            self.moving_since = time() - offset
+            self.set_value(bool(self.value) ^ True)
 
 
 class Cursor(EventMethodDispatcher):
@@ -602,3 +609,55 @@ class TextInput(UIChild):
                 self.focus()
             elif self.cursor is not None:
                 self.blur(True)
+
+
+class FPSWidget(UIChild):
+    FPS_COLOR = "yellow"
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.clock = self.parent.clock
+        self.current_fps = None
+
+    def update(self):
+        new_fps = int(self.clock.get_fps())
+        if self.current_fps != new_fps:
+            self.current_fps = new_fps
+            self.dirty = True
+
+    def draw(self):
+        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 Icon(UIChild):
+    def __init__(self, parent, shape):
+        super().__init__(parent)
+        self.shape = shape
+
+    def draw(self):
+        self.shape.draw(self.surf, "gray")
+
+
+class IconButton(Button):
+    def __init__(self, parent, shape, *args, **kwargs):
+        super().__init__(parent, *args, **kwargs)
+        self.shape = shape
+
+    def draw(self):
+        if self.pushed:
+            pygame.draw.rect(self.parent.surf, "honeydew4", self.rect)
+        self.shape.draw(self.parent.surf, "black" if self.pushed else "white")
+        if self.is_active:
+            color = "lime"
+        elif self.pushed:
+            color = "red"
+        else:
+            color = "gray"
+        pygame.draw.rect(self.parent.surf, color, self.rect, 8)
diff --git a/zenbook_conf.py b/zenbook_conf.py
new file mode 100755 (executable)
index 0000000..fd44ccb
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/env python3
+
+import sys
+from contextlib import redirect_stdout
+from io import StringIO
+from pathlib import Path
+
+sys.path.append(str(Path(__file__).parent))
+
+from zenbook_conf.zenbook_conf import ZenbookConf
+
+with redirect_stdout(StringIO()):
+    import pygame  # type: ignore
+
+ZenbookConf().run()
index 4d7be4b01d9292e26d546adb96ada221d1ca3cb1..a9c7c6ddc80f2ab4cdee5393a2718d0550b4df3a 100644 (file)
@@ -1,6 +1,6 @@
 from math import cos, pi, sin, tau
 
-from vectors import (
+from vectors.vectors import (
     Polygon, Rect, Shapes, StrokeCircleSegment, StrokeRoundLine, StrokeSquareLine
 )
 
diff --git a/zenbook_conf/zenbook_conf.py b/zenbook_conf/zenbook_conf.py
new file mode 100644 (file)
index 0000000..e6f3f49
--- /dev/null
@@ -0,0 +1,191 @@
+from functools import partial
+
+import pygame
+
+from .bluetooth import BluetoothConf
+from ui.ui import Button, FPSWidget, Icon, IconButton, Switch, UIParent
+from .shapes import (
+    bluetooth,
+    laptop_double,
+    laptop_single,
+    laptop_vertical,
+    touchscreen,
+    stylus,
+)
+from .xinput import XinputConf
+from .xrandr import XrandrConf
+
+
+class ZenbookConf(UIParent):
+    BACKGROUND_COLOR = 0x333333
+
+    def __init__(self):
+        pygame.init()
+        pygame.display.set_icon(self.get_icon())
+        pygame.display.set_caption("Zenbook Config")
+        window_size = (1536, 1200)
+        super().__init__(
+            pygame.display.set_mode(window_size, display=0),
+            pygame.font.Font(None, size=96),
+        )
+        self.current_display = 0
+        self.xrandr_conf = XrandrConf()
+        self.xinput_conf = XinputConf(self.xrandr_conf)
+        self.bluetooth_conf = BluetoothConf()
+        bt_switch = Switch(
+            self,
+            pygame.Rect((128, 612), (256, 128)),
+            self.bluetooth_conf.update,
+            self.bluetooth_conf.conf
+        )
+        touch_switch = Switch(
+            self,
+            pygame.Rect((128, 808), (256, 128)),
+            partial(self.xinput_conf.update_by_type, "touchpad"),
+            self.xinput_conf.conf_by_type("touchpad"),
+        )
+        stylus_switch = Switch(
+            self,
+            pygame.Rect((128, 1004), (256, 128)),
+            partial(self.xinput_conf.update_by_type, "stylus"),
+            self.xinput_conf.conf_by_type("stylus"),
+        )
+        top = 128
+        self.single_button = IconButton(
+            self,
+            laptop_single.fit((100, top + 32), (16, 16)),
+            pygame.Rect((68, top), (416, 416)),
+            None,
+            partial(
+                self.laptop_cb, "single", bt_switch, touch_switch, stylus_switch
+            ),
+            self.xrandr_conf.is_active("single"),
+        )
+        self.double_button = IconButton(
+            self,
+            laptop_double.fit((600, top + 32), (16, 16)),
+            pygame.Rect((568, top), (416, 416)),
+            None,
+            partial(
+                self.laptop_cb, "double", bt_switch, touch_switch, stylus_switch
+            ),
+            self.xrandr_conf.is_active("double"),
+        )
+        self.vertical_button = IconButton(
+            self,
+            laptop_vertical.fit((1100, top + 32), (16, 16)),
+            pygame.Rect((1068, top), (416, 416)),
+            None,
+            partial(
+                self.laptop_cb,
+                "vertical",
+                bt_switch,
+                touch_switch,
+                stylus_switch,
+            ),
+            self.xrandr_conf.is_active("vertical"),
+        )
+        self.children.extend(
+            (
+                FPSWidget(self),
+                self.single_button,
+                self.double_button,
+                self.vertical_button,
+                bt_switch,
+                Icon(
+                    self,
+                    bluetooth.fit(
+                        (bt_switch.rect.right + 68, bt_switch.rect.centery - 88),
+                        (8, 8),
+                    ),
+                ),
+                touch_switch,
+                Icon(
+                    self,
+                    touchscreen.fit(
+                        (touch_switch.rect.right + 68, touch_switch.rect.centery - 88),
+                        (8, 8),
+                    ),
+                ),
+                stylus_switch,
+                Icon(
+                    self,
+                    stylus.fit(
+                        (
+                            stylus_switch.rect.right + 68,
+                            stylus_switch.rect.centery - 88,
+                        ),
+                        (8, 8),
+                    ),
+                ),
+                Button(
+                    self,
+                    pygame.Rect((784, touch_switch.rect.top), (384, 128)),
+                    "Re-apply",
+                    partial(self.xinput_conf.reapply_by_type, "touchpad")
+                ),
+                Button(
+                    self,
+                    pygame.Rect((784, stylus_switch.rect.top), (384, 128)),
+                    "Re-apply",
+                    partial(self.xinput_conf.reapply_by_type, "stylus")
+                ),
+                Button(
+                    self,
+                    pygame.Rect((window_size[0] - 128, 0), (128, 96)),
+                    "×",
+                    self.quit,
+                ),
+                Button(
+                    self,
+                    pygame.Rect((window_size[0] - 256, 0), (128, 96)),
+                    "_",
+                    self.iconify,
+                ),
+                Button(
+                    self,
+                    pygame.Rect((window_size[0] - 384, 0), (128, 96)),
+                    "»",
+                    self.next_display,
+                ),
+            )
+        )
+
+    def get_icon(self):
+        surf = pygame.Surface((512, 512), pygame.SRCALPHA, 32)
+        surf.fill(0x0)
+        v = 512 // 22
+        laptop_single.fit((0, 0), (v, v)).draw(surf, "white")
+        return pygame.transform.scale(surf, (32, 32))
+
+    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.set_value(True)
+        settings_per_device_type = {
+            "touchpad": touch_switch.value,
+            "stylus": stylus_switch.value,
+        }
+        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.dirty = True
+
+    def quit(self):
+        self.running = False
+
+    def iconify(self):
+        pygame.display.iconify()
+
+    def next_display(self):
+        current_display = (self.current_display + 1) % self.xrandr_conf.count_active()
+        if current_display != self.current_display:
+            self.current_display = current_display
+            self.surf = pygame.display.set_mode(
+                self.surf.get_size(), display=self.current_display
+            )
+            self.dirty = True