From: mar77i Date: Fri, 17 Jan 2025 02:18:29 +0000 (+0100) Subject: initial commit: buttons. X-Git-Url: https://git.mar77i.info/?a=commitdiff_plain;h=36038ce3a8782074690c5ca563d153cec31e8536;p=zenbook_gui initial commit: buttons. --- 36038ce3a8782074690c5ca563d153cec31e8536 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2483976 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +__pycache__/ diff --git a/ui/ui.py b/ui/ui.py new file mode 100644 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