first commit
This commit is contained in:
commit
417e54da96
5696 changed files with 900003 additions and 0 deletions
|
@ -0,0 +1,23 @@
|
|||
'''
|
||||
Effects
|
||||
=======
|
||||
|
||||
.. versionadded:: 1.7.0
|
||||
|
||||
Everything starts with the :class:`~kinetic.KineticEffect`, the base class for
|
||||
computing velocity out of a movement.
|
||||
|
||||
This base class is used to implement the :class:`~scroll.ScrollEffect`, a base
|
||||
class used for our :class:`~kivy.uix.scrollview.ScrollView` widget effect.
|
||||
We have multiple implementations:
|
||||
|
||||
- :class:`~kivy.effects.scroll.ScrollEffect`: base class used for implementing
|
||||
an effect. It only calculates the scrolling and the overscroll.
|
||||
- :class:`~kivy.effects.dampedscroll.DampedScrollEffect`: uses the overscroll
|
||||
information to allow the user to drag more than expected. Once the user stops
|
||||
the drag, the position is returned to one of the bounds.
|
||||
- :class:`~kivy.effects.opacityscroll.OpacityScrollEffect`: uses the overscroll
|
||||
information to reduce the opacity of the scrollview widget. When the user
|
||||
stops the drag, the opacity is set back to 1.
|
||||
|
||||
'''
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,114 @@
|
|||
'''
|
||||
Damped scroll effect
|
||||
====================
|
||||
|
||||
.. versionadded:: 1.7.0
|
||||
|
||||
This damped scroll effect will use the
|
||||
:attr:`~kivy.effects.scroll.ScrollEffect.overscroll` to calculate the scroll
|
||||
value, and slows going back to the upper or lower limit.
|
||||
|
||||
'''
|
||||
|
||||
__all__ = ('DampedScrollEffect',)
|
||||
|
||||
|
||||
from kivy.effects.scroll import ScrollEffect
|
||||
from kivy.properties import NumericProperty, BooleanProperty
|
||||
from kivy.metrics import sp
|
||||
|
||||
|
||||
class DampedScrollEffect(ScrollEffect):
|
||||
'''DampedScrollEffect class. See the module documentation for more
|
||||
information.
|
||||
'''
|
||||
|
||||
edge_damping = NumericProperty(0.25)
|
||||
'''Edge damping.
|
||||
|
||||
:attr:`edge_damping` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.25
|
||||
'''
|
||||
|
||||
spring_constant = NumericProperty(2.0)
|
||||
'''Spring constant.
|
||||
|
||||
:attr:`spring_constant` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 2.0
|
||||
'''
|
||||
|
||||
min_overscroll = NumericProperty(.5)
|
||||
'''An overscroll less than this amount will be normalized to 0.
|
||||
|
||||
.. versionadded:: 1.8.0
|
||||
|
||||
:attr:`min_overscroll` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to .5.
|
||||
'''
|
||||
|
||||
round_value = BooleanProperty(True)
|
||||
'''If True, when the motion stops, :attr:`value` is rounded to the nearest
|
||||
integer.
|
||||
|
||||
.. versionadded:: 1.8.0
|
||||
|
||||
:attr:`round_value` is a :class:`~kivy.properties.BooleanProperty` and
|
||||
defaults to True.
|
||||
'''
|
||||
|
||||
def update_velocity(self, dt):
|
||||
if abs(self.velocity) <= self.min_velocity and self.overscroll == 0:
|
||||
self.velocity = 0
|
||||
# why does this need to be rounded? For now refactored it.
|
||||
if self.round_value:
|
||||
self.value = round(self.value)
|
||||
return
|
||||
|
||||
total_force = self.velocity * self.friction * dt / self.std_dt
|
||||
if abs(self.overscroll) > self.min_overscroll:
|
||||
total_force += self.velocity * self.edge_damping
|
||||
total_force += self.overscroll * self.spring_constant
|
||||
else:
|
||||
self.overscroll = 0
|
||||
|
||||
stop_overscroll = ''
|
||||
if not self.is_manual:
|
||||
if self.overscroll > 0 and self.velocity < 0:
|
||||
stop_overscroll = 'max'
|
||||
elif self.overscroll < 0 and self.velocity > 0:
|
||||
stop_overscroll = 'min'
|
||||
|
||||
self.velocity = self.velocity - total_force
|
||||
if not self.is_manual:
|
||||
self.apply_distance(self.velocity * dt)
|
||||
if stop_overscroll == 'min' and self.value > self.min:
|
||||
self.value = self.min
|
||||
self.velocity = 0
|
||||
return
|
||||
if stop_overscroll == 'max' and self.value < self.max:
|
||||
self.value = self.max
|
||||
self.velocity = 0
|
||||
return
|
||||
self.trigger_velocity_update()
|
||||
|
||||
def on_value(self, *args):
|
||||
scroll_min = self.min
|
||||
scroll_max = self.max
|
||||
if scroll_min > scroll_max:
|
||||
scroll_min, scroll_max = scroll_max, scroll_min
|
||||
if self.value < scroll_min:
|
||||
self.overscroll = self.value - scroll_min
|
||||
elif self.value > scroll_max:
|
||||
self.overscroll = self.value - scroll_max
|
||||
else:
|
||||
self.overscroll = 0
|
||||
self.scroll = self.value
|
||||
|
||||
def on_overscroll(self, *args):
|
||||
self.trigger_velocity_update()
|
||||
|
||||
def apply_distance(self, distance):
|
||||
os = abs(self.overscroll)
|
||||
if os:
|
||||
distance /= 1. + os / sp(200.)
|
||||
super(DampedScrollEffect, self).apply_distance(distance)
|
193
kivy_venv/lib/python3.11/site-packages/kivy/effects/kinetic.py
Normal file
193
kivy_venv/lib/python3.11/site-packages/kivy/effects/kinetic.py
Normal file
|
@ -0,0 +1,193 @@
|
|||
'''
|
||||
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
|
||||
:attr:`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
|
||||
:attr:`KineticEffect.friction`. The computed value will be stored in
|
||||
:attr:`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.
|
||||
|
||||
:attr:`velocity` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.
|
||||
'''
|
||||
|
||||
friction = NumericProperty(0.05)
|
||||
'''Friction to apply on the velocity
|
||||
|
||||
:attr:`friction` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.05.
|
||||
'''
|
||||
|
||||
value = NumericProperty(0)
|
||||
'''Value (during the movement and computed) of the effect.
|
||||
|
||||
:attr:`value` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.
|
||||
'''
|
||||
|
||||
is_manual = BooleanProperty(False)
|
||||
'''Indicate if a movement is in progress (True) or not (False).
|
||||
|
||||
:attr:`is_manual` is a :class:`~kivy.properties.BooleanProperty` and
|
||||
defaults 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.
|
||||
|
||||
:attr:`max_history` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 5.
|
||||
'''
|
||||
|
||||
min_distance = NumericProperty(.1)
|
||||
'''The minimal distance for a movement to have nonzero velocity.
|
||||
|
||||
.. versionadded:: 1.8.0
|
||||
|
||||
:attr:`min_distance` is :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.1.
|
||||
'''
|
||||
|
||||
min_velocity = NumericProperty(.5)
|
||||
'''Velocity below this quantity is normalized to 0. In other words,
|
||||
any motion whose velocity falls below this number is stopped.
|
||||
|
||||
.. versionadded:: 1.8.0
|
||||
|
||||
:attr:`min_velocity` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.5.
|
||||
'''
|
||||
|
||||
std_dt = NumericProperty(0.017)
|
||||
''' std_dt
|
||||
correction update_velocity if dt is not constant
|
||||
|
||||
.. versionadded:: 2.0.0
|
||||
|
||||
:attr:`std_dt` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.017.
|
||||
'''
|
||||
|
||||
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) < self.min_distance:
|
||||
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, defaults 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 :meth:`stop` cannot be
|
||||
called. It will reset :attr:`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 the frametime and
|
||||
friction.
|
||||
'''
|
||||
if abs(self.velocity) <= self.min_velocity:
|
||||
self.velocity = 0
|
||||
return
|
||||
|
||||
self.velocity -= self.velocity * self.friction * dt / self.std_dt
|
||||
self.apply_distance(self.velocity * dt)
|
||||
self.trigger_velocity_update()
|
|
@ -0,0 +1,27 @@
|
|||
'''
|
||||
Opacity scroll effect
|
||||
=====================
|
||||
|
||||
Based on the :class:`~kivy.effects.damped.DampedScrollEffect`, this one will
|
||||
also decrease the opacity of the target widget during the overscroll.
|
||||
|
||||
'''
|
||||
|
||||
__all__ = ('OpacityScrollEffect', )
|
||||
|
||||
|
||||
from kivy.effects.dampedscroll import DampedScrollEffect
|
||||
|
||||
|
||||
class OpacityScrollEffect(DampedScrollEffect):
|
||||
'''OpacityScrollEffect class. Uses the overscroll
|
||||
information to reduce the opacity of the scrollview widget. When the user
|
||||
stops the drag, the opacity is set back to 1.
|
||||
'''
|
||||
|
||||
def on_overscroll(self, *args):
|
||||
if self.target_widget and self.target_widget.height != 0:
|
||||
alpha = (1.0 -
|
||||
abs(self.overscroll / float(self.target_widget.height)))
|
||||
self.target_widget.opacity = min(1, alpha)
|
||||
self.trigger_velocity_update()
|
126
kivy_venv/lib/python3.11/site-packages/kivy/effects/scroll.py
Normal file
126
kivy_venv/lib/python3.11/site-packages/kivy/effects/scroll.py
Normal file
|
@ -0,0 +1,126 @@
|
|||
'''
|
||||
Scroll effect
|
||||
=============
|
||||
|
||||
.. versionadded:: 1.7.0
|
||||
|
||||
Based on the :class:`~kivy.effects.kinetic` effect, the :class:`ScrollEffect`
|
||||
will limit the movement to bounds determined by its :attr:`~ScrollEffect.min`
|
||||
and :attr:`~ScrollEffect.max` properties. If the movement exceeds these
|
||||
bounds, it will calculate the amount of :attr:`~ScrollEffect.overscroll` and
|
||||
try to return to the value of one of the bounds.
|
||||
|
||||
This is very useful for implementing a scrolling list. We actually use this
|
||||
class as a base effect for our :class:`~kivy.uix.scrollview.ScrollView` widget.
|
||||
|
||||
'''
|
||||
|
||||
|
||||
__all__ = ('ScrollEffect', )
|
||||
|
||||
|
||||
from time import time
|
||||
from kivy.effects.kinetic import KineticEffect
|
||||
from kivy.uix.widget import Widget
|
||||
from kivy.properties import NumericProperty, ObjectProperty
|
||||
|
||||
|
||||
class ScrollEffect(KineticEffect):
|
||||
'''ScrollEffect class. See the module documentation for more information.
|
||||
'''
|
||||
|
||||
drag_threshold = NumericProperty('20sp')
|
||||
'''Minimum distance to travel before the movement is considered as a drag.
|
||||
|
||||
:attr:`drag_threshold` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 20sp.
|
||||
'''
|
||||
|
||||
min = NumericProperty(0)
|
||||
'''Minimum boundary to use for scrolling.
|
||||
|
||||
:attr:`min` is a :class:`~kivy.properties.NumericProperty` and defaults to
|
||||
0.
|
||||
'''
|
||||
|
||||
max = NumericProperty(0)
|
||||
'''Maximum boundary to use for scrolling.
|
||||
|
||||
:attr:`max` is a :class:`~kivy.properties.NumericProperty` and defaults to
|
||||
0.
|
||||
'''
|
||||
|
||||
scroll = NumericProperty(0)
|
||||
'''Computed value for scrolling. This value is different from
|
||||
:py:attr:`kivy.effects.kinetic.KineticEffect.value`
|
||||
in that it will return to one of the min/max bounds.
|
||||
|
||||
:attr:`scroll` is a :class:`~kivy.properties.NumericProperty` and defaults
|
||||
to 0.
|
||||
'''
|
||||
|
||||
overscroll = NumericProperty(0)
|
||||
'''Computed value when the user over-scrolls i.e. goes out of the bounds.
|
||||
|
||||
:attr:`overscroll` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.
|
||||
'''
|
||||
|
||||
target_widget = ObjectProperty(None, allownone=True, baseclass=Widget)
|
||||
'''Widget to attach to this effect. Even if this class doesn't make changes
|
||||
to the `target_widget` by default, subclasses can use it to change the
|
||||
graphics or apply custom transformations.
|
||||
|
||||
:attr:`target_widget` is a :class:`~kivy.properties.ObjectProperty` and
|
||||
defaults to None.
|
||||
'''
|
||||
|
||||
displacement = NumericProperty(0)
|
||||
'''Cumulative distance of the movement during the interaction. This is used
|
||||
to determine if the movement is a drag (more than :attr:`drag_threshold`)
|
||||
or not.
|
||||
|
||||
:attr:`displacement` is a :class:`~kivy.properties.NumericProperty` and
|
||||
defaults to 0.
|
||||
'''
|
||||
|
||||
def reset(self, pos):
|
||||
'''(internal) Reset the value and the velocity to the `pos`.
|
||||
Mostly used when the bounds are checked.
|
||||
'''
|
||||
self.value = pos
|
||||
self.velocity = 0
|
||||
if self.history:
|
||||
val = self.history[-1][1]
|
||||
self.history = [(time(), val)]
|
||||
|
||||
def on_value(self, *args):
|
||||
scroll_min = self.min
|
||||
scroll_max = self.max
|
||||
if scroll_min > scroll_max:
|
||||
scroll_min, scroll_max = scroll_max, scroll_min
|
||||
if self.value < scroll_min:
|
||||
self.overscroll = self.value - scroll_min
|
||||
self.reset(scroll_min)
|
||||
elif self.value > scroll_max:
|
||||
self.overscroll = self.value - scroll_max
|
||||
self.reset(scroll_max)
|
||||
else:
|
||||
self.scroll = self.value
|
||||
|
||||
def start(self, val, t=None):
|
||||
self.is_manual = True
|
||||
self.displacement = 0
|
||||
return super(ScrollEffect, self).start(val, t)
|
||||
|
||||
def update(self, val, t=None):
|
||||
self.displacement += abs(val - self.history[-1][1])
|
||||
return super(ScrollEffect, self).update(val, t)
|
||||
|
||||
def stop(self, val, t=None):
|
||||
self.is_manual = False
|
||||
self.displacement += abs(val - self.history[-1][1])
|
||||
if self.displacement <= self.drag_threshold:
|
||||
self.velocity = 0
|
||||
return
|
||||
return super(ScrollEffect, self).stop(val, t)
|
Loading…
Add table
Add a link
Reference in a new issue