diff --git a/CHANGELOG.md b/CHANGELOG.md index 0470267580..251d306abe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [0.5.0] - Unreleased + +### Added + +- Add easing parameter to Widget.scroll_* methods https://github.com/Textualize/textual/pull/1144 + ### Changed - Watchers are now called immediately when setting the attribute if they are synchronous. https://github.com/Textualize/textual/pull/1145 + ## [0.4.0] - 2022-11-08 https://textual.textualize.io/blog/2022/11/08/version-040/#version-040 diff --git a/src/textual/_easing.py b/src/textual/_easing.py index 994188ec5f..007b643b21 100644 --- a/src/textual/_easing.py +++ b/src/textual/_easing.py @@ -128,3 +128,4 @@ def _in_out_bounce(x: float) -> float: } DEFAULT_EASING = "in_out_cubic" +DEFAULT_SCROLL_EASING = "out_cubic" diff --git a/src/textual/widget.py b/src/textual/widget.py index b4723487c9..15164cc08c 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -34,6 +34,7 @@ from ._animator import BoundAnimator, DEFAULT_EASING, Animatable, EasingFunction from ._arrange import DockArrangeResult, arrange from ._context import active_app +from ._easing import DEFAULT_SCROLL_EASING from ._layout import Layout from ._segment_tools import align_lines from ._styles_cache import StylesCache @@ -1136,6 +1137,7 @@ def scroll_to( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll to a given (absolute) coordinate, optionally animating. @@ -1145,6 +1147,8 @@ def scroll_to( animate (bool, optional): Animate to new scroll position. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the default scrolling easing function. Returns: bool: True if the scroll position changed, otherwise False. @@ -1154,6 +1158,10 @@ def scroll_to( # TODO: configure animation speed if duration is None and speed is None: speed = 50 + + if easing is None: + easing = DEFAULT_SCROLL_EASING + if x is not None: self.scroll_target_x = x if x != self.scroll_x: @@ -1162,7 +1170,7 @@ def scroll_to( self.scroll_target_x, speed=speed, duration=duration, - easing="out_cubic", + easing=easing, ) scrolled_x = True if y is not None: @@ -1173,7 +1181,7 @@ def scroll_to( self.scroll_target_y, speed=speed, duration=duration, - easing="out_cubic", + easing=easing, ) scrolled_y = True @@ -1197,6 +1205,7 @@ def scroll_relative( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll relative to current position. @@ -1206,6 +1215,8 @@ def scroll_relative( animate (bool, optional): Animate to new scroll position. Defaults to False. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if the scroll position changed, otherwise False. @@ -1216,6 +1227,7 @@ def scroll_relative( animate=animate, speed=speed, duration=duration, + easing=easing, ) def scroll_home( @@ -1224,6 +1236,7 @@ def scroll_home( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll to home position. @@ -1231,13 +1244,17 @@ def scroll_home( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. """ if speed is None and duration is None: duration = 1.0 - return self.scroll_to(0, 0, animate=animate, speed=speed, duration=duration) + return self.scroll_to( + 0, 0, animate=animate, speed=speed, duration=duration, easing=easing + ) def scroll_end( self, @@ -1245,6 +1262,7 @@ def scroll_end( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll to the end of the container. @@ -1252,6 +1270,8 @@ def scroll_end( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. @@ -1260,7 +1280,12 @@ def scroll_end( if speed is None and duration is None: duration = 1.0 return self.scroll_to( - 0, self.max_scroll_y, animate=animate, speed=speed, duration=duration + 0, + self.max_scroll_y, + animate=animate, + speed=speed, + duration=duration, + easing=easing, ) def scroll_left( @@ -1269,6 +1294,7 @@ def scroll_left( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll one cell left. @@ -1276,13 +1302,19 @@ def scroll_left( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. """ return self.scroll_to( - x=self.scroll_target_x - 1, animate=animate, speed=speed, duration=duration + x=self.scroll_target_x - 1, + animate=animate, + speed=speed, + duration=duration, + easing=easing, ) def scroll_right( @@ -1291,6 +1323,7 @@ def scroll_right( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll on cell right. @@ -1298,13 +1331,19 @@ def scroll_right( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. """ return self.scroll_to( - x=self.scroll_target_x + 1, animate=animate, speed=speed, duration=duration + x=self.scroll_target_x + 1, + animate=animate, + speed=speed, + duration=duration, + easing=easing, ) def scroll_down( @@ -1313,6 +1352,7 @@ def scroll_down( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll one line down. @@ -1320,13 +1360,19 @@ def scroll_down( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. """ return self.scroll_to( - y=self.scroll_target_y + 1, animate=animate, speed=speed, duration=duration + y=self.scroll_target_y + 1, + animate=animate, + speed=speed, + duration=duration, + easing=easing, ) def scroll_up( @@ -1335,6 +1381,7 @@ def scroll_up( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll one line up. @@ -1342,13 +1389,19 @@ def scroll_up( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. """ return self.scroll_to( - y=self.scroll_target_y - 1, animate=animate, speed=speed, duration=duration + y=self.scroll_target_y - 1, + animate=animate, + speed=speed, + duration=duration, + easing=easing, ) def scroll_page_up( @@ -1357,6 +1410,7 @@ def scroll_page_up( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll one page up. @@ -1364,6 +1418,8 @@ def scroll_page_up( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. @@ -1374,6 +1430,7 @@ def scroll_page_up( animate=animate, speed=speed, duration=duration, + easing=easing, ) def scroll_page_down( @@ -1382,6 +1439,7 @@ def scroll_page_down( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll one page down. @@ -1389,6 +1447,8 @@ def scroll_page_down( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. @@ -1399,6 +1459,7 @@ def scroll_page_down( animate=animate, speed=speed, duration=duration, + easing=easing, ) def scroll_page_left( @@ -1407,6 +1468,7 @@ def scroll_page_left( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll one page left. @@ -1414,6 +1476,8 @@ def scroll_page_left( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. @@ -1426,6 +1490,7 @@ def scroll_page_left( animate=animate, speed=speed, duration=duration, + easing=easing, ) def scroll_page_right( @@ -1434,6 +1499,7 @@ def scroll_page_right( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, ) -> bool: """Scroll one page right. @@ -1441,6 +1507,8 @@ def scroll_page_right( animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. Returns: bool: True if any scrolling was done. @@ -1453,6 +1521,7 @@ def scroll_page_right( animate=animate, speed=speed, duration=duration, + easing=easing, ) def scroll_to_widget( @@ -1462,6 +1531,7 @@ def scroll_to_widget( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, top: bool = False, ) -> bool: """Scroll scrolling to bring a widget in to view. @@ -1471,6 +1541,9 @@ def scroll_to_widget( animate (bool, optional): True to animate, or False to jump. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. + top (bool, optional): Scroll widget to top of container. Defaults to False. Returns: bool: True if any scrolling has occurred in any descendant, otherwise False. @@ -1489,6 +1562,7 @@ def scroll_to_widget( speed=speed, duration=duration, top=top, + easing=easing, ) if scroll_offset: scrolled = True @@ -1515,6 +1589,7 @@ def scroll_to_region( animate: bool = True, speed: float | None = None, duration: float | None = None, + easing: EasingFunction | str | None = None, top: bool = False, ) -> Offset: """Scrolls a given region in to view, if required. @@ -1528,6 +1603,8 @@ def scroll_to_region( animate (bool, optional): True to animate, or False to jump. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. duration (float | None, optional): Duration of animation, if animate is True and speed is None. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. top (bool, optional): Scroll region to top of container. Defaults to False. Returns: @@ -1555,6 +1632,7 @@ def scroll_to_region( animate=animate if (abs(delta_y) > 1 or delta_x) else False, speed=speed, duration=duration, + easing=easing, ) return delta @@ -1565,6 +1643,7 @@ def scroll_visible( speed: float | None = None, duration: float | None = None, top: bool = False, + easing: EasingFunction | str | None = None, ) -> None: """Scroll the container to make this widget visible. @@ -1573,6 +1652,8 @@ def scroll_visible( speed (float | None, optional): _description_. Defaults to None. duration (float | None, optional): _description_. Defaults to None. top (bool, optional): Scroll to top of container. Defaults to False. + easing (EasingFunction | str | None, optional): An easing method for the scrolling animation. Defaults to "None", + which will result in Textual choosing the configured default scrolling easing function. """ parent = self.parent if isinstance(parent, Widget): @@ -1583,6 +1664,7 @@ def scroll_visible( speed=speed, duration=duration, top=top, + easing=easing, ) def __init_subclass__(