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

# -*- 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()