You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
3.6 KiB
98 lines
3.6 KiB
# -*- coding: utf-8 -*- |
|
|
|
import math |
|
from kivy.uix.widget import Widget |
|
from kivy.graphics import Color, Line |
|
from kivy.vector import Vector |
|
from kivy.properties import StringProperty, DictProperty, BooleanProperty, BoundedNumericProperty, ListProperty |
|
|
|
|
|
class Painter(Widget): |
|
tools = DictProperty({'arrow': {'color': (1, 1, 1, 1), 'thickness': 0.5}, |
|
'line': {'color': (1, 1, 1, 1), 'thickness': 0.5}, |
|
'freeline': {'color': (1, 1, 1, 1), 'thickness': 0.5}, |
|
'eraser': {'thickness': 0.4} |
|
}) |
|
current_tool = StringProperty('arrow') |
|
thickness = BoundedNumericProperty(1, min=0.5, max=10, errorvalue=0.5) |
|
color = ListProperty((1, 1, 1, 1)) |
|
locked = BooleanProperty(False) |
|
|
|
def on_thickness(self, instance, value): |
|
self.tools[self.current_tool]['thickness'] = value |
|
|
|
def on_color(self, instance, value): |
|
self.tools[self.current_tool]['color'] = value |
|
|
|
def on_current_tool(self, instance, value): |
|
self.color = self.tools[value]['color'] |
|
self.thickness = self.tools[value]['thickness'] |
|
|
|
def on_touch_down(self, touch): |
|
if not self.locked and self.collide_point(*touch.pos): |
|
touch.grab(self) |
|
with self.canvas: |
|
Color(*self.color, mode='rgba') |
|
touch.ud['line'] = Line(points=(touch.x, touch.y), width=self.thickness, cap='round', joint='miter') |
|
if self.current_tool == 'arrow': |
|
touch.ud['arrowhead'] = Line(width=self.thickness, cap='square', joint='miter') |
|
touch.ud['initial_pos'] = touch.pos |
|
else: |
|
return False |
|
|
|
return super(Painter, self).on_touch_down(touch) |
|
|
|
def on_touch_move(self, touch): |
|
if not self.locked and self.collide_point(*touch.pos): |
|
try: |
|
if self.current_tool == 'freeline': |
|
touch.ud['line'].points += [touch.x, touch.y] |
|
else: |
|
touch.ud['line'].points = [touch.ox, touch.oy, touch.x, touch.y] |
|
except KeyError: |
|
pass |
|
else: |
|
return False |
|
|
|
return super(Painter, self).on_touch_move(touch) |
|
|
|
def arrowhead(self, start, end): |
|
''' |
|
start : list of points (x, y) for the start of the arrow. |
|
end : list of points (x, y) for the end of the arrow. |
|
|
|
return : list of points for each line forming the arrow head. |
|
''' |
|
# TODO: Adjust arrowhead size according to line thickness. |
|
A = Vector(start) |
|
B = Vector(end) |
|
h = 10 * math.sqrt(3) |
|
w = 10 |
|
U = (B - A) / Vector(B - A).length() |
|
V = Vector(-U.y, U.x) |
|
v1 = B - h * U + w * V |
|
v2 = B - h * U - w * V |
|
return (v1, v2) |
|
|
|
def on_touch_up(self, touch): |
|
if not self.locked and touch.grab_current == self and \ |
|
self.collide_point(*touch.pos) and self.current_tool == 'arrow': |
|
try: |
|
arrowhead = self.arrowhead(touch.ud['initial_pos'], touch.pos) |
|
except KeyError: |
|
pass |
|
except ZeroDivisionError: |
|
pass |
|
else: |
|
touch.ud['arrowhead'].points += arrowhead[0] |
|
touch.ud['arrowhead'].points += (touch.x, touch.y) |
|
touch.ud['arrowhead'].points += arrowhead[1] |
|
touch.ungrab(self) |
|
else: |
|
return False |
|
|
|
return super(Painter, self).on_touch_up(touch) |
|
|
|
def on_size(self, *kwargs): |
|
# TODO: Update every drawing according to size. |
|
self.canvas.clear()
|
|
|