#!/usr/bin/env python
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.slider import Slider
from kivy.graphics import Color, Bezier, Line


class BezierTest(FloatLayout):

    def __init__(self, points=[], loop=False, *args, **kwargs):
        super(BezierTest, self).__init__(*args, **kwargs)
        self.d = 10
        self.points = points
        self.loop = loop
        self.current_point = None

        with self.canvas:
            Color(1.0, 0.0, 0.0)

            self.bezier = Bezier(
                    points=self.points,
                    segments=150,
                    loop=self.loop,
                    dash_length=100,
                    dash_offset=10)

            Color(1.0, 0.0, 1.0)
            self.line = Line(
                    points=self.points+self.points[:2],
                    dash_offset=10,
                    dash_length=100)

        s = Slider(y=0, pos_hint={'x': .3}, size_hint=(.7, None), height=50)
        s.bind(value=self._set_bezier_dash_offset)
        self.add_widget(s)

        s = Slider(y=50, pos_hint={'x': .3}, size_hint=(.7, None), height=50)
        s.bind(value=self._set_line_dash_offset)
        self.add_widget(s)

    def _set_bezier_dash_offset(self, instance, value):
        # effect to reduce length while increase offset
        self.bezier.dash_length = 100 - value
        self.bezier.dash_offset = value

    def _set_line_dash_offset(self, instance, value):
        # effect to reduce length while increase offset
        self.line.dash_length = 100 - value
        self.line.dash_offset = value

    def on_touch_down(self, touch):
        if self.collide_point(touch.pos[0], touch.pos[1]):
            for i, p in enumerate(list(zip(self.points[::2], self.points[1::2]))):
                if (
                        abs(touch.pos[0] - self.pos[0] - p[0]) < self.d and
                        abs(touch.pos[1] - self.pos[1] - p[1]) < self.d):
                    self.current_point = i + 1
                    return True
            return super(BezierTest, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        if self.collide_point(touch.pos[0], touch.pos[1]):
            if self.current_point:
                self.current_point = None
                return True
            return super(BezierTest, self).on_touch_up(touch)

    def on_touch_move(self, touch):
        if self.collide_point(touch.pos[0], touch.pos[1]):
            c = self.current_point
            if c:
                self.points[(c - 1) * 2] = touch.pos[0] - self.pos[0]
                self.points[(c - 1) * 2 + 1] = touch.pos[1] - self.pos[1]
                self.bezier.points = self.points
                self.line.points = self.points + self.points[:2]
                return True
            return super(BezierTest, self).on_touch_move(touch)


class Main(App):

    def build(self):
        from math import cos, sin, radians
        x = y = 150
        l = 100
        # Pacman !
        points = [x, y]
        for i in range(45, 360, 45):
            i = radians(i)
            points.extend([x + cos(i) * l, y + sin(i) * l])
        return BezierTest(points=points, loop=True)

if __name__ == '__main__':
    Main().run()


[(33, 'kivy.uix.slider.Slider', 'Slider', False, 'from kivy.uix.slider import Slider\n'), (37, 'kivy.uix.slider.Slider', 'Slider', False, 'from kivy.uix.slider import Slider\n'), (18, 'kivy.graphics.Color', 'Color', False, 'from kivy.graphics import Color, Bezier, Line\n'), (20, 'kivy.graphics.Bezier', 'Bezier', False, 'from kivy.graphics import Color, Bezier, Line\n'), (27, 'kivy.graphics.Color', 'Color', False, 'from kivy.graphics import Color, Bezier, Line\n'), (28, 'kivy.graphics.Line', 'Line', False, 'from kivy.graphics import Color, Bezier, Line\n'), (89, 'math.radians', 'radians', False, 'from math import cos, sin, radians\n'), (90, 'math.cos', 'cos', False, 'from math import cos, sin, radians\n'), (90, 'math.sin', 'sin', False, 'from math import cos, sin, radians\n')]