]> git.mar77i.info Git - zenbook_gui/commitdiff
consolidate bookpaint_menu<->draw_image interactions
authormar77i <mar77i@protonmail.ch>
Thu, 20 Feb 2025 13:56:00 +0000 (14:56 +0100)
committermar77i <mar77i@protonmail.ch>
Thu, 20 Feb 2025 13:56:00 +0000 (14:56 +0100)
bookpaint/bookpaint.py
bookpaint/bookpaint_menu.py
bookpaint/draw_image.py
ui/parent.py
vectors/polygon.py

index 1468f9ec8db23a19f4b19c930636af8375a0a265..20b4f3bbf9b6da9faa9685ef337ccc5676a6706b 100644 (file)
@@ -4,7 +4,7 @@ from ui import Root
 from zenbook_conf.xrandr import XrandrConf
 
 from .bookpaint_menu import BookPaintMenu
-from .draw_image import DrawImage, StrokeMethod
+from .draw_image import DrawImage
 
 
 class BookPaint(Root):
@@ -20,14 +20,8 @@ class BookPaint(Root):
             ),
             pygame.font.Font(None, size=96),
         )
-        self.background_color = self.BACKGROUND_COLOR
-        self.foreground_color = "white"
-        self.drawing_color = "foreground_color"
-        self.line_width = 1
-        self.stroke_method = StrokeMethod.PYGAME
-        self.menu = BookPaintMenu(self)
-        self.draw_image = DrawImage(self)
-        self.clear()
+        self.draw_image = DrawImage(self, self.BACKGROUND_COLOR, "white")
+        self.menu = BookPaintMenu(self, self.draw_image)
         self.xrandr_conf = XrandrConf(True)
 
     def key_escape(self):
@@ -57,6 +51,3 @@ class BookPaint(Root):
             (0, 0), self.display_flags, display=self.current_display
         )
         self.dirty = True
-
-    def clear(self):
-        self.draw_image.clear(self.background_color)
index 80a2dc8f6daa276e259c0354ccc9a0e6a5300b21..8dd9154d805071901a136480749823a8c136361a 100644 (file)
@@ -18,18 +18,26 @@ from ui import (
 )
 
 from .color_chooser import ColorChooser
-from .draw_image import StrokeMethod
+from .draw_image import InputMethod, StrokeMethod
 
 
 class BookPaintMenu(Modal):
     def get_stroke_methods(self):
         return (
-            self.root.stroke_method.name.title(),
+            self.draw_image.stroke_method.name.title(),
             [stroke_method.name.title() for stroke_method in StrokeMethod],
         )
 
-    def __init__(self, parent):
+    def get_input_methods(self):
+        labels = InputMethod.labels()
+        return (
+            labels[tuple(InputMethod).index(self.draw_image.input_method)],
+            labels,
+        )
+
+    def __init__(self, parent, draw_image):
         super().__init__(parent)
+        self.draw_image = draw_image
         Button(
             self,
             pygame.Rect((self.surf.get_width() - 128, 0), (128, 128)),
@@ -95,26 +103,26 @@ class BookPaintMenu(Modal):
         self.background_color = ColorButton(
             self,
             grid_layout.get_rect((1, 1)).inflate((pad, pad)),
-            self.root.background_color,
+            self.draw_image.background_color,
             partial(color_chooser.activate_for, "background_color"),
         )
         Button(
             self,
             grid_layout.get_rect((2, 1)).inflate((pad, pad)),
             "Fill Page",
-            self.root.clear,
+            self.draw_image.clear,
         )
         self.foreground_color = ColorButton(
             self,
             grid_layout.get_rect((1, 2)).inflate((pad, pad)),
-            self.root.foreground_color,
+            self.draw_image.foreground_color,
             partial(color_chooser.activate_for, "foreground_color"),
         )
         self.width_slider = Slider(
             self,
             grid_layout.get_rect((1, 3)).inflate((pad, pad)),
             Slider.HORIZONTAL,
-            self.root.line_width - 1,
+            self.draw_image.line_width - 1,
             96,
             self.set_width,
         )
@@ -129,12 +137,11 @@ class BookPaintMenu(Modal):
             *self.get_stroke_methods(),
             self.set_stroke_method,
         )
-        DropDown(
+        self.input_method = DropDown(
             self,
-            grid_layout.get_rect((1, 5)).inflate((pad, pad)),
-            "<choose>",
-            ["a", "b", "c"],
-            lambda _: None,
+            grid_layout.get_rect((1, 5), (2, 1)).inflate((pad, pad)),
+            *self.get_input_methods(),
+            self.set_input_method,
         )
         rect = pygame.Rect(
             (512, size[1] - 384),
@@ -192,7 +199,7 @@ class BookPaintMenu(Modal):
         print("book path", value)
 
     def set_color(self, attr, color):
-        setattr(self.root, attr, color)
+        setattr(self.draw_image, attr, color)
         getattr(self, attr).color = color
         self.dirty = True
 
@@ -203,11 +210,15 @@ class BookPaintMenu(Modal):
             self.width_slider.value = slider_width
             self.dirty = True
         width = (slider_width * 256 // self.width_slider.extent) + 1
-        if self.root.line_width != width:
-            self.root.line_width = width
+        if self.draw_image.line_width != width:
+            self.draw_image.line_width = width
             self.width_label.value = str(width)
             self.dirty = True
 
     def set_stroke_method(self, i):
-        self.root.stroke_method = StrokeMethod(i + 1)
-        self.stroke_method.value = self.root.stroke_method.name.title()
+        self.draw_image.stroke_method = StrokeMethod(i + 1)
+        self.stroke_method.value = self.draw_image.stroke_method.name.title()
+
+    def set_input_method(self, i):
+        self.draw_image.input_method = InputMethod(i + 1)
+        self.input_method.value = InputMethod.labels()[i]
index af7bb3f59796c52f0f5c32e0c4c770bfb2dff44e..141c56a3f3b61b7c0afb351205fde3281384c0a0 100644 (file)
@@ -1,4 +1,5 @@
 from enum import Enum, auto
+from time import time
 
 import pygame
 
@@ -7,65 +8,154 @@ from vectors import StrokeRoundLine, StrokeSquareLine
 
 
 class StrokeMethod(Enum):
-    PYGAME = auto()
     ROUND = auto()
     SQUARE = auto()
+    PYGAME = auto()
+
+
+class InputMethod(Enum):
+    SDL_ANY = auto()
+    SDL_MOUSE = auto()
+    SDL_FINGERS = auto()
+    SDL_KEYBOARD = auto()
+
+    @staticmethod
+    def labels():
+        return (
+            "Mouse or Fingers (SDL)",
+            "Mouse/Stylus (SDL)",
+            "Fingers (SDL)",
+            "Keyboard (SDL)",
+        )
 
 
 class DrawImage(Child):
-    def __init__(self, parent):
+    FINGER_TIMEOUT = 30
+
+    def __init__(self, parent, background_color, foreground_color):
         super().__init__(parent)
+        self.background_color = background_color
+        self.foreground_color = foreground_color
+        self.drawing_color = "foreground_color"
+        self.line_width = 1
+
         self.surface = pygame.Surface(self.surf.get_size(), 0, 24)
-        self.clear(self.root.BACKGROUND_COLOR)
-        self.prev_pos = None
+        self.clear()
+        self.stroke_method = next(iter(StrokeMethod))
+        self.input_method = next(iter(InputMethod))
+        self.mouse_pos = None
+        self.fingers = {}
 
-    def clear(self, background_color):
-        self.surface.fill(background_color)
+    def clear(self):
+        self.surface.fill(self.background_color)
+
+    def handle_mousebuttondown(self, ev):
+        if self.input_method in (InputMethod.SDL_ANY, InputMethod.SDL_MOUSE):
+            if ev.button == 1:
+                self.drawing_color = "foreground_color"
+                self.mouse_pos = ev.pos
+            elif ev.button == 3:
+                self.drawing_color = "background_color"
+                self.mouse_pos = ev.pos
+
+    def mouse_stroke(self, buttons, pos):
+        if (
+            self.input_method in (InputMethod.SDL_ANY, InputMethod.SDL_MOUSE)
+            and self.mouse_pos is not None
+            and (buttons[0] or buttons[2])
+        ):
+            self.STROKE_MAPPING[self.stroke_method](self, self.mouse_pos, pos)
+            self.mouse_pos = pos
+            self.dirty = True
+
+    def handle_mousemotion(self, ev):
+        self.mouse_stroke(ev.buttons, ev.pos)
+
+    def handle_mousebuttonup(self, ev):
+        self.mouse_stroke(tuple(ev.button == i for i in range(1, 4)), ev.pos)
+
+    def get_finger_pos(self, key):
+        item = self.fingers.get(key)
+        if item is None:
+            return None
+        prev_pos, t = item
+        if t < time():
+            self.fingers.pop(key)
+            return None
+        return prev_pos
+
+    def handle_fingerdown(self, ev):
+        if self.input_method not in (InputMethod.SDL_ANY, InputMethod.SDL_FINGERS):
+            self.fingers.clear()
+            return
+        key = (ev.touch_id, ev.finger_id)
+        size = self.surface.get_size()
+        pos = (int(size[0] * ev.x), int(size[1] * ev.y))
+        prev_pos = self.get_finger_pos(key)
+        if prev_pos is not None:
+            self.STROKE_MAPPING[self.stroke_method](self, prev_pos, pos)
+            self.dirty = True
+        if ev.type == pygame.FINGERUP:
+            self.fingers.pop(key, None)
+        else:
+            self.fingers[key] = pos, time() + self.FINGER_TIMEOUT
+
+    handle_fingermotion = handle_fingerdown
+    handle_fingerup = handle_fingerdown
+
+    def update(self):
+        if not self.root.focused:
+            if self.mouse_pos is not None:
+                self.mouse_pos = None
+                self.dirty = True
+            if len(self.fingers) > 0:
+                self.fingers.clear()
+                self.dirty = True
+            return
+        buttons = pygame.mouse.get_pressed()
+        if buttons[0] or buttons[2]:
+            return
+        pos = pygame.mouse.get_pos()
+        if pos != self.mouse_pos:
+            self.mouse_pos = pos
+            self.dirty = True
 
     def draw(self):
         self.surf.blit(self.surface, (0, 0))
+        if self.mouse_pos is not None:
+            pygame.draw.circle(
+                self.surf,
+                getattr(self, self.drawing_color),
+                self.mouse_pos,
+                self.line_width // 2,
+            )
+            pygame.draw.circle(
+                self.surf,
+                "black",
+                self.mouse_pos,
+                self.line_width // 2,
+                2,
+            )
 
     def pygame_stroke(self, a, b):
-        root = self.root
         pygame.draw.line(
-            self.surface, getattr(root, root.drawing_color), a, b, root.line_width
+            self.surface, getattr(self, self.drawing_color), a, b, self.line_width
         )
 
     def round_stroke(self, a, b):
-        root = self.root
         StrokeRoundLine(
-            a, b, root.line_width
-        ).draw(self.surface, getattr(root, root.drawing_color))
+            a, b, self.line_width
+        ).draw(self.surface, getattr(self, self.drawing_color))
 
     def square_stroke(self, a, b):
-        root = self.root
+        if a == b:
+            return
         StrokeSquareLine(
-            a, b, root.line_width
-        ).draw(self.surface, getattr(root, root.drawing_color))
+            a, b, self.line_width
+        ).draw(self.surface, getattr(self, self.drawing_color))
 
     STROKE_MAPPING = {
         StrokeMethod.PYGAME: pygame_stroke,
         StrokeMethod.ROUND: round_stroke,
         StrokeMethod.SQUARE: square_stroke
     }
-
-    def handle_mousebuttondown(self, ev):
-        if ev.button == 1:
-            self.root.drawing_color = "foreground_color"
-        elif ev.button == 3:
-            self.root.drawing_color = "background_color"
-        else:
-            return
-        self.prev_pos = ev.pos
-
-    def handle_mousemotion(self, ev):
-        if self.prev_pos is not None:
-            self.STROKE_MAPPING[self.root.stroke_method](self, self.prev_pos, ev.pos)
-            self.prev_pos = ev.pos
-            self.dirty = True
-
-    def handle_mousebuttonup(self, ev):
-        if self.prev_pos is not None:
-            self.STROKE_MAPPING[self.root.stroke_method](self, self.prev_pos, ev.pos)
-            self.prev_pos = None
-            self.dirty = True
index 47c9a772c60c7ed907198bd4e2ccb601ae5c6ffa..210cc3f3077a417d88191cda07a2b031a1cbc62a 100644 (file)
@@ -4,7 +4,6 @@ from .event_method_dispatcher import EventMethodDispatcher
 class Parent(EventMethodDispatcher):
     running: bool
     stop_event: bool
-    parent: "root.Root"
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
index 0e6a785db900a224f2bbc2bbeec75f070a93dcf2..b37ef9e69cb506115e45822a88949293c167d8e7 100644 (file)
@@ -18,4 +18,10 @@ class Polygon(Shape):
         )
 
     def draw(self, surf, color):
-        pygame.draw.polygon(surf, color, self.points)
+        num_points = len(self.points)
+        if num_points == 1:
+            surf.set_at(self.points[0], color)
+        elif num_points == 2:
+            pygame.draw.aaline(surf, color, *self.points)
+        elif num_points > 2:
+            pygame.draw.polygon(surf, color, self.points)