first commit
This commit is contained in:
commit
417e54da96
5696 changed files with 900003 additions and 0 deletions
|
@ -0,0 +1 @@
|
|||
from .stiffscroll import StiffScrollEffect
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,215 @@
|
|||
"""
|
||||
Effects/StiffScrollEffect
|
||||
=========================
|
||||
|
||||
An Effect to be used with ScrollView to prevent scrolling beyond
|
||||
the bounds, but politely.
|
||||
|
||||
A ScrollView constructed with StiffScrollEffect,
|
||||
eg. ScrollView(effect_cls=StiffScrollEffect), will get harder to
|
||||
scroll as you get nearer to its edges. You can scroll all the way to
|
||||
the edge if you want to, but it will take more finger-movement than
|
||||
usual.
|
||||
|
||||
Unlike DampedScrollEffect, it is impossible to overscroll with
|
||||
StiffScrollEffect. That means you cannot push the contents of the
|
||||
ScrollView far enough to see what's beneath them. This is appropriate
|
||||
if the ScrollView contains, eg., a background image, like a desktop
|
||||
wallpaper. Overscrolling may give the impression that there is some
|
||||
reason to overscroll, even if just to take a peek beneath, and that
|
||||
impression may be misleading.
|
||||
|
||||
StiffScrollEffect was written by Zachary Spector. His other stuff is at:
|
||||
https://github.com/LogicalDash/
|
||||
He can be reached, and possibly hired, at:
|
||||
zacharyspector@gmail.com
|
||||
|
||||
"""
|
||||
|
||||
from time import time
|
||||
|
||||
from kivy.animation import AnimationTransition
|
||||
from kivy.effects.kinetic import KineticEffect
|
||||
from kivy.properties import NumericProperty, ObjectProperty
|
||||
from kivy.uix.widget import Widget
|
||||
|
||||
|
||||
class StiffScrollEffect(KineticEffect):
|
||||
drag_threshold = NumericProperty("20sp")
|
||||
"""Minimum distance to travel before the movement is considered as a
|
||||
drag.
|
||||
|
||||
:attr:`drag_threshold` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `'20sp'`.
|
||||
"""
|
||||
|
||||
min = NumericProperty(0)
|
||||
"""Minimum boundary to stop the scrolling at.
|
||||
|
||||
:attr:`min` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0`.
|
||||
"""
|
||||
|
||||
max = NumericProperty(0)
|
||||
"""Maximum boundary to stop the scrolling at.
|
||||
|
||||
:attr:`max` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0`.
|
||||
"""
|
||||
|
||||
max_friction = NumericProperty(1)
|
||||
"""How hard should it be to scroll, at the worst?
|
||||
|
||||
:attr:`max_friction` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `1`.
|
||||
"""
|
||||
|
||||
body = NumericProperty(0.7)
|
||||
"""Proportion of the range in which you can scroll unimpeded.
|
||||
|
||||
:attr:`body` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0.7`.
|
||||
"""
|
||||
|
||||
scroll = NumericProperty(0.0)
|
||||
"""Computed value for scrolling
|
||||
|
||||
:attr:`scroll` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0.0`.
|
||||
"""
|
||||
|
||||
transition_min = ObjectProperty(AnimationTransition.in_cubic)
|
||||
"""The AnimationTransition function to use when adjusting the friction
|
||||
near the minimum end of the effect.
|
||||
|
||||
:attr:`transition_min` is an :class:`~kivy.properties.ObjectProperty`
|
||||
and defaults to :class:`kivy.animation.AnimationTransition`.
|
||||
"""
|
||||
|
||||
transition_max = ObjectProperty(AnimationTransition.in_cubic)
|
||||
"""The AnimationTransition function to use when adjusting the friction
|
||||
near the maximum end of the effect.
|
||||
|
||||
:attr:`transition_max` is an :class:`~kivy.properties.ObjectProperty`
|
||||
and defaults to :class:`kivy.animation.AnimationTransition`.
|
||||
"""
|
||||
|
||||
target_widget = ObjectProperty(None, allownone=True, baseclass=Widget)
|
||||
"""The widget to apply the effect to.
|
||||
|
||||
:attr:`target_widget` is an :class:`~kivy.properties.ObjectProperty`
|
||||
and defaults to ``None``.
|
||||
"""
|
||||
|
||||
displacement = NumericProperty(0)
|
||||
"""The absolute distance moved in either direction.
|
||||
|
||||
:attr:`displacement` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0`.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Set ``self.base_friction`` to the value of ``self.friction`` just
|
||||
after instantiation, so that I can reset to that value later.
|
||||
"""
|
||||
|
||||
super().__init__(**kwargs)
|
||||
self.base_friction = self.friction
|
||||
|
||||
def update_velocity(self, dt):
|
||||
"""Before actually updating my velocity, meddle with ``self.friction``
|
||||
to make it appropriate to where I'm at, currently.
|
||||
"""
|
||||
|
||||
hard_min = self.min
|
||||
hard_max = self.max
|
||||
if hard_min > hard_max:
|
||||
hard_min, hard_max = hard_max, hard_min
|
||||
|
||||
margin = (1.0 - self.body) * (hard_max - hard_min)
|
||||
soft_min = hard_min + margin
|
||||
soft_max = hard_max - margin
|
||||
|
||||
if self.value < soft_min:
|
||||
try:
|
||||
prop = (soft_min - self.value) / (soft_min - hard_min)
|
||||
self.friction = self.base_friction + abs(
|
||||
self.max_friction - self.base_friction
|
||||
) * self.transition_min(prop)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
elif self.value > soft_max:
|
||||
try:
|
||||
# normalize how far past soft_max I've gone as a
|
||||
# proportion of the distance between soft_max and hard_max
|
||||
prop = (self.value - soft_max) / (hard_max - soft_max)
|
||||
self.friction = self.base_friction + abs(
|
||||
self.max_friction - self.base_friction
|
||||
) * self.transition_min(prop)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
self.friction = self.base_friction
|
||||
|
||||
return super().update_velocity(dt)
|
||||
|
||||
def on_value(self, *args):
|
||||
"""Prevent moving beyond my bounds, and update ``self.scroll``"""
|
||||
|
||||
if self.value > self.min:
|
||||
self.velocity = 0
|
||||
self.scroll = self.min
|
||||
elif self.value < self.max:
|
||||
self.velocity = 0
|
||||
self.scroll = self.max
|
||||
else:
|
||||
self.scroll = self.value
|
||||
|
||||
def start(self, val, t=None):
|
||||
"""Start movement with ``self.friction`` = ``self.base_friction``"""
|
||||
|
||||
self.is_manual = True
|
||||
t = t or time()
|
||||
self.velocity = self.displacement = 0
|
||||
self.friction = self.base_friction
|
||||
self.history = [(t, val)]
|
||||
|
||||
def update(self, val, t=None):
|
||||
"""Reduce the impact of whatever change has been made to me, in
|
||||
proportion with my current friction.
|
||||
"""
|
||||
|
||||
t = t or time()
|
||||
hard_min = self.min
|
||||
hard_max = self.max
|
||||
if hard_min > hard_max:
|
||||
hard_min, hard_max = hard_max, hard_min
|
||||
|
||||
gamut = hard_max - hard_min
|
||||
margin = (1.0 - self.body) * gamut
|
||||
soft_min = hard_min + margin
|
||||
soft_max = hard_max - margin
|
||||
distance = val - self.history[-1][1]
|
||||
reach = distance + self.value
|
||||
|
||||
if (distance < 0 and reach < soft_min) or (
|
||||
distance > 0 and soft_max < reach
|
||||
):
|
||||
distance -= distance * self.friction
|
||||
self.apply_distance(distance)
|
||||
self.history.append((t, val))
|
||||
|
||||
if len(self.history) > self.max_history:
|
||||
self.history.pop(0)
|
||||
self.displacement += abs(distance)
|
||||
self.trigger_velocity_update()
|
||||
|
||||
def stop(self, val, t=None):
|
||||
"""Work out whether I've been flung."""
|
||||
|
||||
self.is_manual = False
|
||||
self.displacement += abs(val - self.history[-1][1])
|
||||
if self.displacement <= self.drag_threshold:
|
||||
self.velocity = 0
|
||||
|
||||
return super().stop(val, t)
|
Loading…
Add table
Add a link
Reference in a new issue