]> git.mar77i.info Git - zenbook_gui/commitdiff
initial commit: buttons.
authormar77i <mar77i@protonmail.ch>
Fri, 17 Jan 2025 02:18:29 +0000 (03:18 +0100)
committermar77i <mar77i@protonmail.ch>
Fri, 17 Jan 2025 02:18:29 +0000 (03:18 +0100)
.gitignore [new file with mode: 0644]
ui/ui.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..2483976
--- /dev/null
@@ -0,0 +1,2 @@
+.idea/
+__pycache__/
diff --git a/ui/ui.py b/ui/ui.py
new file mode 100644 (file)
index 0000000..024c705
--- /dev/null
+++ b/ui/ui.py
@@ -0,0 +1,144 @@
+import pygame
+
+
+class EventMethodDispatcher:
+    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)
+
+
+class UIParent(EventMethodDispatcher):
+    BACKGROUND_COLOR: pygame.Color
+
+    def __init__(self, surf, font=None):
+        super().__init__()
+        self.surf = surf
+        self.font = font
+        self.running = True
+        self.dirty = False
+        self.clock = pygame.time.Clock()
+        self.children = []
+
+    def handle_quit(self, _):
+        self.running = False
+
+    def handle_windowexposed(self, _):
+        self.dirty = True
+
+    handle_activeevent = handle_windowexposed
+
+    def handle_keydown(self, ev):
+        if ev.key == pygame.K_ESCAPE:
+            self.running = False
+            return
+
+    def handle_event(self, ev):
+        super().handle_event(ev)
+        if not self.running:
+            return
+        for child in self.children:
+            child.handle_event(ev)
+            if not self.running:
+                break
+
+    def update(self):
+        for child in self.children:
+            child.update()
+
+    def draw(self):
+        if hasattr(self, "BACKGROUND_COLOR"):
+            self.surf.fill(self.BACKGROUND_COLOR)
+        for child in self.children:
+            child.draw()
+
+    def run(self):
+        while True:
+            for ev in pygame.event.get():
+                self.handle_event(ev)
+                if not self.running:
+                    return
+            self.update()
+            if self.dirty:
+                self.draw()
+                pygame.display.update()
+                self.dirty = False
+            self.clock.tick(60)
+
+
+class UIChild(EventMethodDispatcher):
+    parent: "UIParent"
+
+    def __init__(self, parent):
+        self.parent = parent
+
+    @property
+    def dirty(self):
+        return self.parent.dirty
+
+    @dirty.setter
+    def dirty(self, value):
+        self.parent.dirty = value
+
+    @property
+    def font(self):
+        return self.parent.font
+
+    @property
+    def surf(self):
+        return self.parent.surf
+
+    def draw(self):
+        pass
+
+    def update(self):
+        pass
+
+
+class Button(UIChild):
+    def __init__(self, parent, rect, label, callback, is_active=None):
+        super().__init__(parent)
+        self.rect = rect
+        self.label = label
+        self.callback = callback
+        self.is_active = is_active
+        self.pushed = False
+
+    def draw(self):
+        if not self.pushed:
+            label_color = (
+                "lime" if callable(self.is_active) and self.is_active() else "gray"
+            )
+            frame_color = label_color
+        else:
+            pygame.draw.rect(self.parent.surf, "darkgray", self.rect)
+            frame_color = "lightgray"
+            label_color = "black"
+        label = self.label
+        if callable(label):
+            label = label()
+        fs = self.parent.font.render(label, True, label_color)
+        pygame.draw.rect(self.parent.surf, frame_color, self.rect, 8)
+        fs_size = fs.get_size()
+        center = self.rect.center
+        self.parent.surf.blit(
+            fs, (center[0] - fs_size[0] // 2, center[1] - fs_size[1] // 2)
+        )
+
+    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