From 49422932c7b48e44c0d16969240ca18bc99382ef Mon Sep 17 00:00:00 2001 From: Dave Pearson Date: Thu, 20 Apr 2023 09:15:05 +0100 Subject: [PATCH] Move scroll navigation key bindings out of widget and into own container The idea here is that not every widget will scroll, and as such not every widget needs to have default bindings for calling the scrolling methods. Generally scrolling is something done in a container. These days we have *Scroll containers. As such it makes sense to introduce the bindings in a common parent class for those containers. This commit moves the binding from widget and creates that common parent class, and then has HorizontalScroll and VerticalScroll inherit from it. This is, it should be noted, a breaking change. Any code that creates a scrolling widget that assumes that the bindings are just there, where that widget doesn't inherit either from HorizontalScroll or VerticalScroll, will suddenly find that scrolling with the keyboard is no longer possible. See #2332. --- src/textual/containers.py | 36 ++++++++++++++++++++++++++++++++++-- src/textual/widget.py | 12 ------------ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/textual/containers.py b/src/textual/containers.py index 9d6c35b7f..0623ef0b3 100644 --- a/src/textual/containers.py +++ b/src/textual/containers.py @@ -3,7 +3,11 @@ Container widgets for quick styling. """ +from __future__ import annotations +from typing import ClassVar + +from .binding import Binding, BindingType from .widget import Widget @@ -19,6 +23,34 @@ class Container(Widget): """ +class ScrollableContainer(Widget): + """Base container widget that binds navigation keys for scrolling.""" + + BINDINGS: ClassVar[list[BindingType]] = [ + Binding("up", "scroll_up", "Scroll Up", show=False), + Binding("down", "scroll_down", "Scroll Down", show=False), + Binding("left", "scroll_left", "Scroll Up", show=False), + Binding("right", "scroll_right", "Scroll Right", show=False), + Binding("home", "scroll_home", "Scroll Home", show=False), + Binding("end", "scroll_end", "Scroll End", show=False), + Binding("pageup", "page_up", "Page Up", show=False), + Binding("pagedown", "page_down", "Page Down", show=False), + ] + """Keyboard bindings for scrollable containers. + + | Key(s) | Description | + | :- | :- | + | up | Scroll up, if vertical scrolling is available. | + | down | Scroll down, if vertical scrolling is available. | + | left | Scroll left, if horizontal scrolling is available. | + | right | Scroll right, if horizontal scrolling is available. | + | home | Scroll to the home position, if scrolling is available. | + | end | Scroll to the end position, if scrolling is available. | + | pageup | Scroll up one page, if vertical scrolling is available. | + | pagedown | Scroll down one page, if vertical scrolling is available. | + """ + + class Vertical(Widget): """A container which arranges children vertically.""" @@ -31,7 +63,7 @@ class Vertical(Widget): """ -class VerticalScroll(Widget, can_focus=True): +class VerticalScroll(ScrollableContainer, can_focus=True): """A container which arranges children vertically, with an automatic vertical scrollbar.""" DEFAULT_CSS = """ @@ -55,7 +87,7 @@ class Horizontal(Widget): """ -class HorizontalScroll(Widget, can_focus=True): +class HorizontalScroll(ScrollableContainer, can_focus=True): """A container which arranges children horizontally, with an automatic horizontal scrollbar.""" DEFAULT_CSS = """ diff --git a/src/textual/widget.py b/src/textual/widget.py index b0cf8af97..441e23e08 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -55,7 +55,6 @@ from ._segment_tools import align_lines from ._styles_cache import StylesCache from .actions import SkipAction from .await_remove import AwaitRemove -from .binding import Binding from .box_model import BoxModel from .css.query import NoMatches, WrongType from .css.scalar import ScalarOffset @@ -238,17 +237,6 @@ class Widget(DOMNode): """ - BINDINGS = [ - Binding("up", "scroll_up", "Scroll Up", show=False), - Binding("down", "scroll_down", "Scroll Down", show=False), - Binding("left", "scroll_left", "Scroll Up", show=False), - Binding("right", "scroll_right", "Scroll Right", show=False), - Binding("home", "scroll_home", "Scroll Home", show=False), - Binding("end", "scroll_end", "Scroll End", show=False), - Binding("pageup", "page_up", "Page Up", show=False), - Binding("pagedown", "page_down", "Page Down", show=False), - ] - DEFAULT_CSS = """ Widget{ scrollbar-background: $panel-darken-1;