Skip to content

Instantly share code, notes, and snippets.

@Bakterija
Created April 10, 2017 22:19
Show Gist options
  • Save Bakterija/086eace0003e0bf53ca6244a07e80687 to your computer and use it in GitHub Desktop.
Save Bakterija/086eace0003e0bf53ca6244a07e80687 to your computer and use it in GitHub Desktop.
from __future__ import division
import math
from operator import itemgetter
import kivy
from kivy.app import App
from kivy.properties import ReferenceListProperty, ObjectProperty, StringProperty, ListProperty, BooleanProperty, NumericProperty, DictProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color, Bezier
class Scroller(ScrollView):
def on_touch_down(self, touch):
return super(Scroller, self).on_touch_down(touch)
class Curves(FloatLayout):
points = ListProperty()
current_point = ListProperty()
moving = BooleanProperty(False)
touch_range = NumericProperty(0.1)
scroller = ObjectProperty()
def __init__(self, **kwargs):
super(Curves, self).__init__(**kwargs)
self.bind(pos=self.refresh, size=self.refresh)
self.reset()
def reset(self):
'''Clears the canvas and sets up the default curve'''
self.points = [[0,0], [1,1]]
self.refresh()
def refresh(self, *args):
'''Sorts and redraws points on the canvas'''
if len(self.points) < 2:
self.reset()
self.points = sorted(self.points, key=itemgetter(0))
self.points[0][0] = 0
self.points[-1][0] = 1
canvas = self.canvas
canvas.clear()
canvas.before.add(Color(.3,.3,.3))
canvas.before.add(Rectangle(size=self.size, pos=self.pos))
canvas.add(Color(1,1,1))
for index in range(len(self.points) - 1):
current = self.points[index]
next = self.points[index+1]
self.draw_line(canvas, current, next)
self.draw_point(canvas, current)
self.draw_point(canvas, self.points[-1])
def relative_to_local(self, point):
x = point[0]*self.width + self.pos[0]
y = point[1]*self.height + self.pos[1]
return [x, y]
def local_to_relative(self, point):
x = (point[0] - self.pos[0])/self.width
y = (point[1] - self.pos[1])/self.height
return [x, y]
def draw_line(self, canvas, startpoint, endpoint):
real_startpoint = self.relative_to_local(startpoint)
real_endpoint = self.relative_to_local(endpoint)
canvas.add(Bezier(points=(real_startpoint[0],real_startpoint[1],real_endpoint[0],real_endpoint[1])))
def draw_point(self, canvas, point):
size = 20
real_point = self.relative_to_local(point)
if point == self.current_point:
source = 'curve_point_selected.png'
else:
source = 'curve_point.png'
canvas.add(Rectangle(source=source, pos=(real_point[0]-(size/2),real_point[1]-(size/2)), size=(size,size)))
def add_point(self, point):
'''Adds a new point to the curve'''
x = point[0]
y = point[1]
#dont allow illegal values for x or y
if x > 1 or y > 1 or x < 0 or y < 0:
return
#dont allow point on an x position that already exists
for point in self.points:
if point[0] == x:
return
self.points.append([x,y])
self.current_point = [x,y]
self.refresh()
def remove_point(self):
'''Removes the last moved point if it is not the start or end'''
if self.current_point:
for index, point in enumerate(self.points):
if point[0] == self.current_point[0] and point[1] == self.current_point[1]:
self.points.pop(index)
self.refresh()
def generate_curve(self, resolution=256):
'''Returns a list of vertical points representing the current curve'''
#todo
pass
def near(self, first, second):
if abs(second-first) <= self.touch_range:
return True
else:
return False
def on_touch_down(self, touch):
## STOP SCROLL HERE
global asd
asd.scroll_timeout = 0
if self.collide_point(*touch.pos):
point = self.local_to_relative(touch.pos)
self.moving = True
for existing in self.points:
if self.near(point[0], existing[0]) and self.near(point[1], existing[1]):
self.current_point = existing
self.refresh()
return
self.add_point(point)
return True
def on_touch_move(self, touch):
if self.collide_point(*touch.pos):
new_point = self.local_to_relative(touch.pos)
if self.moving:
for index, point in enumerate(self.points):
if point[0] == self.current_point[0]:
too_close = False
for other_point in self.points:
if other_point != point:
if self.near(other_point[0], new_point[0]) and self.near(other_point[1], new_point[1]):
too_close = True
if point[0] == 0:
new_point[0] = 0
elif new_point[0] <= 0:
too_close = True
if point[0] == 1:
new_point[0] = 1
elif new_point[0] >= 1:
too_close = True
if not too_close:
self.points[index] = new_point
self.current_point = new_point
self.refresh()
break
return True
def on_touch_up(self, touch):
## START SCROLL HERE
global asd
asd.scroll_timeout = 100
self.moving = False
if self.collide_point(*touch.pos):
return True
class PhotoManager(App):
def build(self):
global asd
scroller = Scroller()
grid = GridLayout(cols=1, height=1000, size_hint_y=None)
grid.add_widget(Label(text='scroll here'))
grid.add_widget(Curves())
grid.add_widget(Label(text='scroll here'))
scroller.add_widget(grid)
asd = scroller
return scroller
if __name__ == '__main__':
PhotoManager().run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment