]> git.mar77i.info Git - zenbook_conf/commitdiff
make fitting move/scale great again
authormar77i <mar77i@protonmail.ch>
Thu, 26 Dec 2024 04:29:09 +0000 (05:29 +0100)
committermar77i <mar77i@protonmail.ch>
Thu, 26 Dec 2024 04:29:09 +0000 (05:29 +0100)
ui.py [changed mode: 0755->0644]
vector_assets.py
vectors.py
zenbook_conf.py

diff --git a/ui.py b/ui.py
old mode 100755 (executable)
new mode 100644 (file)
index 34d88d6..0f0a9d5
--- a/ui.py
+++ b/ui.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-
 from math import asin, nan, pi, sin
 from time import time
 from colorsys import hsv_to_rgb
@@ -203,33 +201,23 @@ class Button(UIChild):
 
 
 class IconButton(Button):
-    def __init__(self, parent, shape, shape_size, rect, callback, is_active):
+    def __init__(self, parent, shape, rect, callback, is_active):
         super().__init__(parent, rect, None, callback)
         self.shape = shape
-        self.shape_size = shape_size
         self.is_active = is_active
 
     def draw(self):
-        units = (16, 16)
-        full_size = (units[0] * self.shape_size[0], units[1] * self.shape_size[1])
-        center = self.rect.center
         if self.pushed:
             pygame.draw.rect(self.parent.surf, "honeydew4", self.rect)
-        self.shape.draw(
-            self.parent.surf,
-            (center[0] - full_size[0] // 2, center[1] - full_size[1] // 2),
-            units,
-            "black" if self.pushed else "white",
-        )
+        self.shape.draw(self.parent.surf, "black" if self.pushed else "white")
         color = "lime" if self.is_active() else ("red" if self.pushed else "gray")
         pygame.draw.rect(self.parent.surf, color, self.rect, 8)
 
 
 class Icon(UIChild):
-    def __init__(self, parent, shape, pos):
+    def __init__(self, parent, shape):
         super().__init__(parent)
         self.shape = shape
-        self.pos = pos
 
     def draw(self):
-        self.shape.draw(self.parent.surf, self.pos, (8, 8), "gray")
+        self.shape.draw(self.parent.surf, "gray")
index 3a887bad3a9fc208e65779ff4c153f6415407b4e..2f6d4162131b45fb47012c78e2503757d9379fbe 100755 (executable)
@@ -1,9 +1,20 @@
+#!/usr/bin/env python3
+
 from math import cos, pi, sin
 
 import pygame
 
 from vectors import (
-    Polygon, Rect, Shapes, StrokeCircleSegment, StrokeRoundLine, StrokeSquareLine
+    Circle,
+    Ellipse,
+    Polygon,
+    Rect,
+    Shapes,
+    StrokeCircle,
+    StrokeCircleSegment,
+    StrokePath,
+    StrokeRoundLine,
+    StrokeSquareLine,
 )
 
 tau = 2 * pi
@@ -117,31 +128,24 @@ bluetooth = Shapes(
 
 
 def main():
+    unit = (16, 16)
     shapes = [
-        {
-            "shape": laptop_single,
-            "pos": (100, 100),
-        },
-        {
-            "shape": laptop_double,
-            "pos": (600, 100),
-        },
-        {
-            "shape": laptop_vertical,
-            "pos": (1100, 100),
-        },
-        {
-            "shape": touchscreen,
-            "pos": (100, 600),
-        },
-        {
-            "shape": stylus,
-            "pos": (600, 600),
-        },
-        {
-            "shape": bluetooth,
-            "pos": (1100, 600),
-        },
+        laptop_single.fit((100, 100), unit),
+        laptop_double.fit((600, 100), unit),
+        laptop_vertical.fit((1100, 100), unit),
+        touchscreen.fit((100, 600), unit),
+        stylus.fit((600, 600), unit),
+        bluetooth.fit((1100, 600), unit),
+        Shapes(
+            [
+                Ellipse((50, 550), (32, 64)).fit((0, 0), (2, 2)),
+                Circle((150, 582), 32).fit((0, 0), (2, 2)),
+                StrokePath(
+                    [(250, 550), (275, 550), (325, 600), (300, 600)], True, 4,
+                ).fit((0, 0), (2, 2)),
+                StrokeCircle((400, 614), 64, 4).fit((0, 0), (2, 2)),
+            ],
+        ),
     ]
     surf = pygame.display.set_mode((2000, 1600))
     running = True
@@ -163,7 +167,7 @@ def main():
         elif dirty:
             surf.fill("black")
             for item in shapes:
-                item["shape"].draw(surf, item["pos"], (16, 16), "green")
+                item.draw(surf, "green")
             pygame.display.update()
             dirty = False
         clock.tick(60)
index be4c4fb10c03b3e877a6896ec00a83271cd2e9e7..55a024c46597948c77df4e704d4e0fae54c0ef1e 100644 (file)
@@ -10,6 +10,9 @@ class Shape:
     def fit(self, pos, unit):
         raise NotImplementedError
 
+    def draw(self, surf, color):
+        pass
+
 
 class Rect(Shape):
     def __init__(self, *args):
@@ -18,13 +21,25 @@ class Rect(Shape):
         self.left, self.top, self.width, self.height = args
 
     def fit(self, pos, unit):
-        return pygame.Rect(
+        klass = type(self)
+        if klass not in (Rect, Ellipse):
+            raise NotImplementedError
+        return klass(
             (round(pos[0] + self.left * unit[0]), round(pos[1] + self.top * unit[1])),
             (round(self.width * unit[0]), round(self.height * unit[1])),
         )
 
-    def draw(self, surf, pos, unit, color):
-        pygame.draw.rect(surf, color, self.fit(pos, unit))
+    def draw(self, surf, color):
+        pygame.draw.rect(
+            surf, color, pygame.Rect(self.left, self.top, self.width, self.height)
+        )
+
+
+class Ellipse(Rect):
+    def draw(self, surf, color):
+        pygame.draw.ellipse(
+            surf, color, pygame.Rect(self.left, self.top, self.width, self.height)
+        )
 
 
 class Polygon(Shape):
@@ -32,31 +47,45 @@ class Polygon(Shape):
         self.points = list(points)
 
     def fit(self, pos, unit):
-        return [
-            (round(pos[0] + point[0] * unit[0]), round(pos[1] + point[1] * unit[1]))
-            for point in self.points
-        ]
+        if type(self) != Polygon:
+            raise NotImplementedError
+        return Polygon(
+            [
+                (round(pos[0] + point[0] * unit[0]), round(pos[1] + point[1] * unit[1]))
+                for point in self.points
+            ]
+        )
 
-    def draw(self, surf, pos, unit, color):
-        pygame.draw.polygon(surf, color, self.fit(pos, unit))
+    def draw(self, surf, color):
+        pygame.draw.polygon(surf, color, self.points)
 
 
 class Circle(Shape):
-    def __init__(self, pos, radius):
-        self.pos = pos
+    def __init__(self, center, radius):
+        self.center = center
         self.radius = radius
 
     def fit(self, pos, unit):
-        return pygame.Rect(
+        if type(self) != Circle:
+            raise NotImplementedError
+        if unit[0] == unit[1]:
+            return Circle(
+                (
+                    pos[0] + self.center[0] * unit[0],
+                    pos[1] + self.center[1] * unit[1],
+                ),
+                self.radius * unit[0],
+            )
+        return Ellipse(
             (
-                round(pos[0] + (self.pos[0] - self.radius) * unit[0]),
-                round(pos[1] + (self.pos[1] - self.radius) * unit[1]),
+                round(pos[0] + (self.center[0] - self.radius) * unit[0]),
+                round(pos[1] + (self.center[1] - self.radius) * unit[1]),
             ),
             (round(self.radius * 2 * unit[0]), round(self.radius * 2 * unit[1])),
         )
 
-    def draw(self, surf, pos, unit, color):
-        pygame.draw.ellipse(surf, color, self.fit(pos, unit))
+    def draw(self, surf, color):
+        pygame.draw.circle(surf, color, self.center, self.radius)
 
 
 class StrokeSquareLine(Polygon):
@@ -64,24 +93,38 @@ class StrokeSquareLine(Polygon):
     Rotate a rectangle along the direction in which we're drawing.
     """
     def __init__(self, p1, p2, width):
-        p_rel = (p1[0] - p2[0], p1[1] - p2[1])
+        self.p1 = p1
+        self.p2 = p2
+        self.width = width
+        super().__init__(self.get_points())
+
+    def get_points(self):
+        p_rel = (self.p1[0] - self.p2[0], self.p1[1] - self.p2[1])
         twice_distance = 2 * sqrt(p_rel[0] * p_rel[0] + p_rel[1] * p_rel[1])
         if twice_distance:
             back = (
-                p_rel[0] * width / twice_distance, p_rel[1] * width / twice_distance
+                p_rel[0] * self.width / twice_distance,
+                p_rel[1] * self.width / twice_distance,
             )
             back_sum, back_diff = back[0] + back[1], back[0] - back[1]
         else:
-            back_sum, back_diff = -width / 2, width / 2
+            back_sum, back_diff = -self.width / 2, self.width / 2
         # left is aka: (back[1], -back[0])
         # right is aka: (-back[1], back[0])
-        super().__init__(
-            [
-                (p1[0] + back_sum, p1[1] - back_diff),
-                (p1[0] + back_diff, p1[1] + back_sum),
-                (p2[0] - back_sum, p2[1] + back_diff),
-                (p2[0] - back_diff, p2[1] - back_sum),
-            ]
+        return [
+            (self.p1[0] + back_sum, self.p1[1] - back_diff),
+            (self.p1[0] + back_diff, self.p1[1] + back_sum),
+            (self.p2[0] - back_sum, self.p2[1] + back_diff),
+            (self.p2[0] - back_diff, self.p2[1] - back_sum),
+        ]
+
+    def fit(self, pos, unit):
+        if type(self) != StrokeSquareLine:
+            raise NotImplementedError
+        return StrokeSquareLine(
+            (pos[0] + self.p1[0] * unit[0], pos[1] + self.p1[1] * unit[1]),
+            (pos[0] + self.p2[0] * unit[0], pos[1] + self.p2[1] * unit[1]),
+            self.width * max(unit),
         )
 
 
@@ -91,9 +134,15 @@ class StrokeRoundLine(Polygon):
     that should be visually indistinguishable with a half circle
     """
     def __init__(self, p1, p2, width):
-        radius = width / 2
+        self.p1 = p1
+        self.p2 = p2
+        self.width = width
+        super().__init__(self.get_points())
+
+    def get_points(self):
+        radius = self.width / 2
         num_vertices = self.corners_needed_to_appear_round(radius)
-        delta = (p1[0] - p2[0], p1[1] - p2[1])
+        delta = (self.p1[0] - self.p2[0], self.p1[1] - self.p2[1])
         distance = sqrt(delta[0] * delta[0] + delta[1] * delta[1])
         points = []
         if distance == 0:
@@ -109,41 +158,58 @@ class StrokeRoundLine(Polygon):
             back = (delta[0] * radius / distance, delta[1] * radius / distance)
             points.extend(
                 (
-                    (p2[0] + back[1], p2[1] - back[0]),
-                    (p1[0] + back[1], p1[1] - back[0]),
+                    (self.p2[0] + back[1], self.p2[1] - back[0]),
+                    (self.p1[0] + back[1], self.p1[1] - back[0]),
                 )
             )
-        p = p1
+        p = self.p1
         for i in range(num_vertices):
             angle = (i + initial_corner) * tau / num_vertices
             points.append((p[0] + cos(angle) * radius, p[1] + sin(angle) * radius))
             if i == opposing_corner:
                 points.extend(
                     (
-                        (p1[0] - back[1], p1[1] + back[0]),
-                        (p2[0] - back[1], p2[1] + back[0]),
+                        (self.p1[0] - back[1], self.p1[1] + back[0]),
+                        (self.p2[0] - back[1], self.p2[1] + back[0]),
                     )
                 )
-                p = p2
-        super().__init__(points)
+                p = self.p2
+        return points
 
     @staticmethod
     def corners_needed_to_appear_round(radius, threshold=.5):
         return ceil(pi / acos(1 - threshold / radius))
 
+    def fit(self, pos, unit):
+        if type(self) != StrokeRoundLine:
+            raise NotImplementedError
+        return StrokeRoundLine(
+            (pos[0] + self.p1[0] * unit[0], pos[1] + self.p1[1] * unit[1]),
+            (pos[0] + self.p2[0] * unit[0], pos[1] + self.p2[1] * unit[1]),
+            self.width * max(unit),
+        )
+
+    def draw(self, surf, pos):
+        super().draw(surf, pos)
+
 
 class Shapes(Shape):
     def __init__(self, shapes):
         self.shapes = list(shapes)
 
-    def draw(self, surf, pos, unit, color):
+    def fit(self, pos, unit):
+        if type(self) != Shapes:
+            raise NotImplementedError
+        return Shapes([s.fit(pos, unit) for s in self.shapes])
+
+    def draw(self, surf, pos):
         for shape in self.shapes:
-            shape.draw(surf, pos, unit, color)
+            shape.draw(surf, pos)
 
 
 class StrokePath:
     def __init__(self, points, closed, width):
-        self.points = list(*points)
+        self.points = list(points)
         self.closed = bool(closed)
         self.width = width
 
@@ -163,6 +229,18 @@ class StrokePath:
             yield StrokeRoundLine(old, new, self.width)
             old = new
 
+    def fit(self, pos, unit):
+        if type(self) != StrokePath:
+            raise NotImplementedError
+        return StrokePath(
+            [
+                (pos[0] + point[0] * unit[0], pos[1] + point[1] * unit[1])
+                for point in self.points
+            ],
+            self.closed,
+            self.width,
+        )
+
     draw = Shapes.draw
 
 
@@ -171,9 +249,10 @@ class StrokeCircle(StrokePath):
         self.center = center
         self.radius = radius
         super().__init__([], True, width)
+        self.points.extend(self.get_points())
 
-    def get_points(self, unit):
-        num_vertices = StrokeRoundLine.corners_needed_to_appear_round(self.radius * max(unit))
+    def get_points(self):
+        num_vertices = StrokeRoundLine.corners_needed_to_appear_round(self.radius)
         return [
             (
                 self.center[0] + cos(a) * self.radius,
@@ -182,10 +261,17 @@ class StrokeCircle(StrokePath):
             for a in (tau * i / num_vertices for i in range(num_vertices))
         ]
 
-    def draw(self, surf, pos, unit, color):
-        if not self.points:
-            self.points.extend(self.get_points(unit))
-        super().draw(surf, pos, unit, color)
+    def fit(self, pos, unit):
+        if type(self) != StrokeCircle:
+            raise NotImplementedError
+        return StrokeCircle(
+            (pos[0] + self.center[0] * unit[0], pos[1] + self.center[1] * unit[1]),
+            self.radius * max(unit),
+            self.width * max(unit),
+        )
+
+    def draw(self, surf, pos):
+        super().draw(surf, pos)
 
 
 class StrokeCircleSegment(StrokeCircle):
@@ -195,13 +281,13 @@ class StrokeCircleSegment(StrokeCircle):
         super().__init__(center, radius, width)
         self.closed = False
 
-    def get_points(self, unit):
+    def get_points(self):
         return [
             (self.center[0] + cos(a) * self.radius, self.center[1] + sin(a) * self.radius)
             for a in self.get_angle_segments(
                 self.start_angle,
                 self.end_angle,
-                StrokeRoundLine.corners_needed_to_appear_round(self.radius * max(unit)),
+                StrokeRoundLine.corners_needed_to_appear_round((self.radius + self.width / 2)),
             )
         ]
 
@@ -214,3 +300,14 @@ class StrokeCircleSegment(StrokeCircle):
                 yield end_angle
                 break
             yield start_angle + a
+
+    def fit(self, pos, unit):
+        if type(self) != StrokeCircleSegment:
+            raise NotImplementedError
+        return StrokeCircleSegment(
+            (pos[0] + self.center[0] * unit[0], pos[1] + self.center[1] * unit[1]),
+            self.radius * max(unit),
+            self.start_angle,
+            self.end_angle,
+            self.width * max(unit),
+        )
index d69fab5b2b3429816f5f586f95970d8d7da24f22..8a399835a8e96692e67478dc13d2a8332b97976a 100755 (executable)
@@ -75,8 +75,7 @@ class ZenbookConf(FPSMixin, UIParent):
             (
                 IconButton(
                     self,
-                    laptop_single,
-                    (22, 22),
+                    laptop_single.fit((100, 100), (16, 16)),
                     pygame.Rect((68, 68), (416, 416)),
                     partial(
                         self.laptop_cb, "single", bt_switch, touch_switch, stylus_switch
@@ -85,8 +84,7 @@ class ZenbookConf(FPSMixin, UIParent):
                 ),
                 IconButton(
                     self,
-                    laptop_double,
-                    (22, 22),
+                    laptop_double.fit((600, 100), (16, 16)),
                     pygame.Rect((568, 68), (416, 416)),
                     partial(
                         self.laptop_cb, "double", bt_switch, touch_switch, stylus_switch
@@ -95,8 +93,7 @@ class ZenbookConf(FPSMixin, UIParent):
                 ),
                 IconButton(
                     self,
-                    laptop_vertical,
-                    (22, 22),
+                    laptop_vertical.fit((1100, 100), (16, 16)),
                     pygame.Rect((1068, 68), (416, 416)),
                     partial(
                         self.laptop_cb,
@@ -110,20 +107,29 @@ class ZenbookConf(FPSMixin, UIParent):
                 bt_switch,
                 Icon(
                     self,
-                    bluetooth,
-                    (bt_switch.rect.right + 68, bt_switch.rect.centery - 88),
+                    bluetooth.fit(
+                        (bt_switch.rect.right + 68, bt_switch.rect.centery - 88),
+                        (8, 8),
+                    ),
                 ),
                 touch_switch,
                 Icon(
                     self,
-                    touchscreen,
-                    (touch_switch.rect.right + 68, touch_switch.rect.centery - 88),
+                    touchscreen.fit(
+                        (touch_switch.rect.right + 68, touch_switch.rect.centery - 88),
+                        (8, 8),
+                    ),
                 ),
                 stylus_switch,
                 Icon(
                     self,
-                    stylus,
-                    (stylus_switch.rect.right + 68, stylus_switch.rect.centery - 88),
+                    stylus.fit(
+                        (
+                            stylus_switch.rect.right + 68,
+                            stylus_switch.rect.centery - 88,
+                        ),
+                        (8, 8),
+                    ),
                 ),
                 Button(
                     self,