kivy/examples/widgets/colorpicker.py

229 lines
6.5 KiB
Python

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scatter import Scatter
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty, StringProperty
from kivy.graphics import Line, Color, Point
from math import sqrt
from os import walk
from os.path import dirname, join
from kivy.lang import Builder
Builder.load_string('''
#:import os os
<Picture>:
# each time a picture is created, the image can delay the loading
# as soon as the image is loaded, ensure that the center is changed
# to the center of the screen.
on_size: self.center = app.main_root_widget.center
size: image.size
size_hint: None, None
on_touch_down: if self.collide_point(*args[1].pos): app.current_image = image
Image:
id: image
source: root.source
# create initial image to be 400 pixels width
size: 400, 400 / self.image_ratio
# add shadow background
canvas.before:
Color:
rgba: 1,1,1,1
BorderImage:
source: '../demo/pictures/shadow32.png'
border: (36,36,36,36)
size:(self.width+72, self.height+72)
pos: (-36,-36)
<ColorSelector>:
color: 1, 1, 1, 1
title: 'Color Slector'
content:content
BoxLayout:
id: content
orientation: 'vertical'
ColorPicker:
id: clr_picker
color: root.color
BoxLayout:
size_hint_y: None
height: '27sp'
Button:
text: 'ok'
on_release:
root.color = clr_picker.color
root.dismiss()
Button:
text: 'cancel'
on_release: root.dismiss()
<LeftPanel@BoxLayout>
orientation: 'vertical'
padding: '2pt'
canvas.before:
Color:
rgba: .5, .4, .9, .2
Rectangle:
pos: self.pos
size: self.size
Label:
size_hint_y: None
font_size: '18sp'
text_size: self.width, None
valign: 'middle'
halign: 'center'
height: self.texture.size[1] if self.texture else 10
text: 'Selected Image:\\n' + app.current_image.source.split(os.sep)[2] if app.current_image else 'None'
Button:
text: 'Brush'
size_hint_y: None
height: self.parent.width
on_release:
app.color_selector.open()
app.color_mode = 'brush'
Image:
color: app.color_selector.color
source: '../demo/touchtracer/particle.png'
allow_stretch: True
size: self.parent.size
pos: self.parent.pos
Button:
text: 'cursor'
on_release: app.color_mode = 'cursor'
Button:
text: 'clear'
on_release:
app.current_image.canvas.after.clear()
<MainRootWidget>
current_image: None
client_area: client_area
RelativeLayout:
id: client_area
Splitter:
sizable_from: 'left'
size_hint: None, 1
width: '99dp'
LeftPanel:
''')
def calculate_points(x1, y1, x2, y2, steps=5):
dx = x2 - x1
dy = y2 - y1
dist = sqrt(dx * dx + dy * dy)
if dist < steps:
return None
o = []
m = dist / steps
for i in range(1, int(m)):
mi = i / m
lastx = x1 + dx * mi
lasty = y1 + dy * mi
o.extend([lastx, lasty])
return o
class ColorSelector(Popup):
pass
class Picture(Scatter):
source = StringProperty(None)
'''path to the Image to be loaded
'''
def __init__(self, **kwargs):
super(Picture, self).__init__(**kwargs)
self._app = App.get_running_app()
def on_touch_down(self, touch):
_app = self._app
if (_app.color_mode[0] == 'c' or
not self.collide_point(*touch.pos)):
return super(Picture, self).on_touch_down(touch)
ud = touch.ud
ud['group'] = g = str(touch.uid)
_pos = list(self.ids.image.to_widget(*touch.pos))
_pos[0] += self.parent.x
with self.ids.image.canvas.after:
ud['color'] = Color(*_app.color_selector.color, group=g)
ud['lines'] = Point(points=(_pos),
source='../examples/demo/touchtracer/particle.png',
pointsize=5, group=g)
touch.grab(self)
return True
def on_touch_move(self, touch):
if touch.grab_current is not self:
return
_app = self._app
if _app.color_mode[0] == 'c' or not self.collide_point(*touch.pos):
return super(Picture, self).on_touch_move(touch)
ud = touch.ud
_pos = list(self.ids.image.to_widget(*touch.pos))
_pos[0] += self.parent.x
points = ud['lines'].points
oldx, oldy = points[-2], points[-1]
points = calculate_points(oldx, oldy, _pos[0], _pos[1])
if points:
try:
lp = ud['lines'].add_point
for idx in range(0, len(points), 2):
lp(points[idx], points[idx + 1])
except GraphicException:
pass
def on_touch_up(self, touch):
if touch.grab_current is not self:
return
_app = self._app
if _app.color_mode[0] == 'c':
return super(Picture, self).on_touch_up(touch)
touch.ungrab(self)
ud = touch.ud
self.canvas.remove_group(ud['group'])
class MainRootWidget(BoxLayout):
clent_area = ObjectProperty(None)
# The Client Area in which all editing is Done
def on_parent(self, instance, parent):
if parent:
_dir = join(dirname(__file__), 'lists/fruit_images/')
for image in list(walk(_dir))[0][2]:
if image.find('512') > -1:
self.client_area.add_widget(Picture(source=_dir + image))
class MainApp(App):
main_root_widget = ObjectProperty(None)
# we will be accessing this later as App.main_root_widget
current_image = ObjectProperty(None)
'''This is a handle to the currently selected image on which the effects
would be applied.'''
color_mode = StringProperty('cursor')
'''This defines the current mode `brush` or `cursor`. `brush` mode allows
adding brush strokes to the currently selected Image.
'''
def build(self):
self.color_selector = ColorSelector()
self.main_root_widget = MainRootWidget()
return self.main_root_widget
if __name__ == '__main__':
MainApp().run()