Skip to content

Commit 1feec2e

Browse files
committed
scroll view
1 parent 5ed98ba commit 1feec2e

File tree

2 files changed

+83
-2
lines changed

2 files changed

+83
-2
lines changed

src/textual/animator.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
from .message_pump import MessagePump
5+
from ._timer import Timer
6+
from time import time
7+
from typing import Callable
8+
9+
from dataclasses import dataclass
10+
11+
12+
EasingFunction = Callable[[float], float]
13+
14+
LinearEasing = lambda value: value
15+
16+
17+
def InOutCubitEasing(x: float) -> float:
18+
return 4 * x * x * x if x < 0.5 else 1 - pow(-2 * x + 2, 3) / 2
19+
20+
21+
log = logging.getLogger("rich")
22+
23+
24+
@dataclass
25+
class Animation:
26+
attribute: str
27+
start_time: float
28+
duration: float
29+
start_value: float
30+
end_value: float
31+
easing_function: EasingFunction
32+
33+
def __call__(self, obj: object, time: float) -> bool:
34+
progress = min(1.0, (time - self.start_time) / self.duration)
35+
eased_progress = self.easing_function(progress)
36+
value = self.start_value + (self.end_value - self.start_value) * eased_progress
37+
setattr(obj, self.attribute, value)
38+
return value == self.end_value
39+
40+
41+
class Animator:
42+
def __init__(self, obj: MessagePump) -> None:
43+
self.obj = obj
44+
self._animations: dict[str, Animation] = {}
45+
self._timer: Timer | None = None
46+
47+
def animate(
48+
self,
49+
attribute: str,
50+
value: float,
51+
duration: float = 1,
52+
easing: EasingFunction = InOutCubitEasing,
53+
) -> None:
54+
start_value = getattr(self.obj, attribute)
55+
start_time = time()
56+
57+
animation = Animation(
58+
attribute=attribute,
59+
start_time=start_time,
60+
duration=duration,
61+
start_value=start_value,
62+
end_value=value,
63+
easing_function=easing,
64+
)
65+
self._animations[attribute] = animation
66+
if self._timer is None:
67+
self._timer = self.obj.set_interval(0.02, callback=self)
68+
69+
async def __call__(self) -> None:
70+
log.debug("ANIMATION FRAME")
71+
animation_time = time()
72+
if all(
73+
animation(self.obj, animation_time)
74+
for animation in self._animations.values()
75+
):
76+
if self._timer is not None:
77+
self._timer.stop()
78+
self._timer = None
79+
80+
for _attribute, animation in self._animations.items():
81+
animation(self.obj, animation_time)

src/textual/widgets/scroll_view.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,6 @@ async def on_key(self, event: events.Key) -> None:
6969
elif event.key == "up":
7070
self.y -= 1
7171
elif event.key == "pagedown":
72-
self._animator.animate("y", self.y + self.size.height, duration=0.5)
72+
self._animator.animate("y", self.y + self.size.height, duration=1)
7373
elif event.key == "pageup":
74-
self._animator.animate("y", self.y - self.size.height, duration=0.5)
74+
self._animator.animate("y", self.y - self.size.height, duration=1)

0 commit comments

Comments
 (0)