PyBitmessage/src/kivymd/ripplebehavior.py

170 lines
6.7 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
from kivy.properties import ListProperty, NumericProperty, StringProperty, \
BooleanProperty
from kivy.animation import Animation
from kivy.graphics import Color, Ellipse, StencilPush, StencilPop, \
StencilUse, StencilUnUse, Rectangle
class CommonRipple(object):
ripple_rad = NumericProperty()
ripple_rad_default = NumericProperty(1)
ripple_post = ListProperty()
ripple_color = ListProperty()
ripple_alpha = NumericProperty(.5)
ripple_scale = NumericProperty(None)
ripple_duration_in_fast = NumericProperty(.3)
# FIXME: These speeds should be calculated based on widget size in dp
ripple_duration_in_slow = NumericProperty(2)
ripple_duration_out = NumericProperty(.3)
ripple_func_in = StringProperty('out_quad')
ripple_func_out = StringProperty('out_quad')
doing_ripple = BooleanProperty(False)
finishing_ripple = BooleanProperty(False)
fading_out = BooleanProperty(False)
def on_touch_down(self, touch):
if touch.is_mouse_scrolling:
return False
if not self.collide_point(touch.x, touch.y):
return False
if not self.disabled:
if self.doing_ripple:
Animation.cancel_all(self, 'ripple_rad', 'ripple_color',
'rect_color')
self.anim_complete()
self.ripple_rad = self.ripple_rad_default
self.ripple_pos = (touch.x, touch.y)
if self.ripple_color != []:
pass
elif hasattr(self, 'theme_cls'):
self.ripple_color = self.theme_cls.ripple_color
else:
# If no theme, set Grey 300
self.ripple_color = [0.8784313725490196, 0.8784313725490196,
0.8784313725490196, self.ripple_alpha]
self.ripple_color[3] = self.ripple_alpha
self.lay_canvas_instructions()
self.finish_rad = max(self.width, self.height) * self.ripple_scale
self.start_ripple()
return super(CommonRipple, self).on_touch_down(touch)
def lay_canvas_instructions(self):
raise NotImplementedError
def on_touch_move(self, touch, *args):
if not self.collide_point(touch.x, touch.y):
if not self.finishing_ripple and self.doing_ripple:
self.finish_ripple()
return super(CommonRipple, self).on_touch_move(touch, *args)
def on_touch_up(self, touch):
if self.collide_point(touch.x, touch.y) and self.doing_ripple:
self.finish_ripple()
return super(CommonRipple, self).on_touch_up(touch)
def start_ripple(self):
if not self.doing_ripple:
anim = Animation(
ripple_rad=self.finish_rad,
t='linear',
duration=self.ripple_duration_in_slow)
anim.bind(on_complete=self.fade_out)
self.doing_ripple = True
anim.start(self)
def _set_ellipse(self, instance, value):
self.ellipse.size = (self.ripple_rad, self.ripple_rad)
# Adjust ellipse pos here
def _set_color(self, instance, value):
self.col_instruction.a = value[3]
def finish_ripple(self):
if self.doing_ripple and not self.finishing_ripple:
Animation.cancel_all(self, 'ripple_rad')
anim = Animation(ripple_rad=self.finish_rad,
t=self.ripple_func_in,
duration=self.ripple_duration_in_fast)
anim.bind(on_complete=self.fade_out)
self.finishing_ripple = True
anim.start(self)
def fade_out(self, *args):
rc = self.ripple_color
if not self.fading_out:
Animation.cancel_all(self, 'ripple_color')
anim = Animation(ripple_color=[rc[0], rc[1], rc[2], 0.],
t=self.ripple_func_out,
duration=self.ripple_duration_out)
anim.bind(on_complete=self.anim_complete)
self.fading_out = True
anim.start(self)
def anim_complete(self, *args):
self.doing_ripple = False
self.finishing_ripple = False
self.fading_out = False
self.canvas.after.clear()
class RectangularRippleBehavior(CommonRipple):
ripple_scale = NumericProperty(2.75)
def lay_canvas_instructions(self):
with self.canvas.after:
StencilPush()
Rectangle(pos=self.pos, size=self.size)
StencilUse()
self.col_instruction = Color(rgba=self.ripple_color)
self.ellipse = \
Ellipse(size=(self.ripple_rad, self.ripple_rad),
pos=(self.ripple_pos[0] - self.ripple_rad / 2.,
self.ripple_pos[1] - self.ripple_rad / 2.))
StencilUnUse()
Rectangle(pos=self.pos, size=self.size)
StencilPop()
self.bind(ripple_color=self._set_color,
ripple_rad=self._set_ellipse)
def _set_ellipse(self, instance, value):
super(RectangularRippleBehavior, self)._set_ellipse(instance, value)
self.ellipse.pos = (self.ripple_pos[0] - self.ripple_rad / 2.,
self.ripple_pos[1] - self.ripple_rad / 2.)
class CircularRippleBehavior(CommonRipple):
ripple_scale = NumericProperty(1)
def lay_canvas_instructions(self):
with self.canvas.after:
StencilPush()
self.stencil = Ellipse(size=(self.width * self.ripple_scale,
self.height * self.ripple_scale),
pos=(self.center_x - (
self.width * self.ripple_scale) / 2,
self.center_y - (
self.height * self.ripple_scale) / 2))
StencilUse()
self.col_instruction = Color(rgba=self.ripple_color)
self.ellipse = Ellipse(size=(self.ripple_rad, self.ripple_rad),
pos=(self.center_x - self.ripple_rad / 2.,
self.center_y - self.ripple_rad / 2.))
StencilUnUse()
Ellipse(pos=self.pos, size=self.size)
StencilPop()
self.bind(ripple_color=self._set_color,
ripple_rad=self._set_ellipse)
def _set_ellipse(self, instance, value):
super(CircularRippleBehavior, self)._set_ellipse(instance, value)
if self.ellipse.size[0] > self.width * .6 and not self.fading_out:
self.fade_out()
self.ellipse.pos = (self.center_x - self.ripple_rad / 2.,
self.center_y - self.ripple_rad / 2.)