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):
),
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):
(0, 0), self.display_flags, display=self.current_display
)
self.dirty = True
-
- def clear(self):
- self.draw_image.clear(self.background_color)
)
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)),
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,
)
*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),
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
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]
from enum import Enum, auto
+from time import time
import pygame
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
class Parent(EventMethodDispatcher):
running: bool
stop_event: bool
- parent: "root.Root"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
)
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)