/usr/share/pyshared/kivy/effects/kinetic.py is in python-kivy 1.7.2-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | '''
Kinetic effect
==============
.. versionadded:: 1.7.0
The :class:`KineticEffect` is the base class that is used to compute the
velocity out of a movement. When the movement is finished, the effect will
compute the position of the movement according to the velocity, and reduce the
velocity with a friction. The movement stop until the velocity is 0.
Conceptually, the usage could be::
>>> effect = KineticEffect()
>>> effect.start(10)
>>> effect.update(15)
>>> effect.update(30)
>>> effect.stop(48)
Over the time, you will start a movement of a value, update it, and stop the
movement. At this time, you'll get the movement value into
:data:`KineticEffect.value`. On the example i've typed manually, the computed
velocity will be::
>>> effect.velocity
3.1619100231163046
After multiple clock interaction, the velocity will decrease according to
:data:`KineticEffect.friction`. The computed value will be stored in
:data:`KineticEffect.value`. The output of this `value` could be::
46.30038145219605
54.58302451968686
61.9229016256196
# ...
'''
__all__ = ('KineticEffect', )
from time import time
from kivy.event import EventDispatcher
from kivy.properties import NumericProperty, BooleanProperty
from kivy.clock import Clock
class KineticEffect(EventDispatcher):
'''Kinetic effect class. See module documentation for more information.
'''
velocity = NumericProperty(0)
'''Velocity of the movement.
:data:`velocity` is a :class:`~kivy.properties.NumericProperty`, default to
0
'''
friction = NumericProperty(0.05)
'''Friction to apply on the velocity
:data:`velocity` is a :class:`~kivy.properties.NumericProperty`, default to
0.05
'''
value = NumericProperty(0)
'''Value (during the movement and computed) of the effect.
:data:`velocity` is a :class:`~kivy.properties.NumericProperty`, default to
0
'''
is_manual = BooleanProperty(False)
'''Indicate if a movement is in progress (True) or not (False).
:data:`velocity` is a :class:`~kivy.properties.BooleanProperty`, default to
False
'''
max_history = NumericProperty(5)
'''Save up to `max_history` movement value into the history. This is used
for correctly calculating the velocity according to the movement.
:data:`max_history` is a :class:`~kivy.properties.NumericProperty`, default
to 5.
'''
def __init__(self, **kwargs):
self.history = []
self.trigger_velocity_update = Clock.create_trigger(self.update_velocity, 0)
super(KineticEffect, self).__init__(**kwargs)
def apply_distance(self, distance):
if abs(distance) < 0.1:
self.velocity = 0
self.value += distance
def start(self, val, t=None):
'''Start the movement.
:Parameters:
`val`: float or int
Value of the movement
`t`: float, default to None
Time when the movement happen. If no time is set, it will use
time.time()
'''
self.is_manual = True
t = t or time()
self.velocity = 0
self.history = [(t, val)]
def update(self, val, t=None):
'''Update the movement.
See :meth:`start` for the arguments.
'''
t = t or time()
distance = val - self.history[-1][1]
self.apply_distance(distance)
self.history.append((t, val))
if len(self.history) > self.max_history:
self.history.pop(0)
def stop(self, val, t=None):
'''Stop the movement.
See :meth:`start` for the arguments.
'''
self.is_manual = False
t = t or time()
distance = val - self.history[-1][1]
self.apply_distance(distance)
newest_sample = (t, val)
old_sample = self.history[0]
for sample in self.history:
if (newest_sample[0] - sample[0]) < 10. / 60.:
break
old_sample = sample
distance = newest_sample[1] - old_sample[1]
duration = abs(newest_sample[0] - old_sample[0])
self.velocity = (distance / max(duration, 0.0001))
self.trigger_velocity_update()
def cancel(self):
'''Cancel a movement. This can be used in case of :meth:`stop` cannot be
called. It will reset :data:`is_manual` to False, and compute the
movement if the velocity is > 0.
'''
self.is_manual = False
self.trigger_velocity_update()
def update_velocity(self, dt):
'''(internal) Update the velocity according to a frametime and the
friction.
'''
if abs(self.velocity) <= 0.5:
self.velocity = 0
return
self.velocity -= self.velocity * self.friction
self.apply_distance(self.velocity * dt)
self.trigger_velocity_update()
|