Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Have Container *not* show scrollbars by default #2365

Merged
merged 7 commits into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- `textual run` execs apps in a new context.
- Textual console no longer parses console markup.
- Breaking change: `Container` no longer shows required scrollbars by default https://github.com/Textualize/textual/issues/2361
- Breaking change: `VerticalScroll` no longer shows a required horizontal scrollbar by default
- Breaking change: `HorizontalScroll` no longer shows a required vertical scrollbar by default

### Added

Expand Down
4 changes: 2 additions & 2 deletions docs/examples/styles/scrollbar_size.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from textual.app import App
from textual.containers import Container
from textual.containers import ScrollableContainer
from textual.widgets import Label

TEXT = """I must not fear.
Expand All @@ -14,7 +14,7 @@

class ScrollbarApp(App):
def compose(self):
yield Container(Label(TEXT * 5), classes="panel")
yield ScrollableContainer(Label(TEXT * 5), classes="panel")


app = ScrollbarApp(css_path="scrollbar_size.css")
2 changes: 1 addition & 1 deletion docs/examples/styles/scrollbar_size2.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Container {
ScrollableContainer {
width: 1fr;
}

Expand Down
10 changes: 6 additions & 4 deletions docs/examples/styles/scrollbar_size2.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from textual.app import App
from textual.containers import Horizontal, Container
from textual.containers import Horizontal, ScrollableContainer
from textual.widgets import Label

TEXT = """I must not fear.
Expand All @@ -15,10 +15,12 @@
class ScrollbarApp(App):
def compose(self):
yield Horizontal(
Container(Label(TEXT * 5), id="v1"),
Container(Label(TEXT * 5), id="v2"),
Container(Label(TEXT * 5), id="v3"),
ScrollableContainer(Label(TEXT * 5), id="v1"),
ScrollableContainer(Label(TEXT * 5), id="v2"),
ScrollableContainer(Label(TEXT * 5), id="v3"),
)


app = ScrollbarApp(css_path="scrollbar_size2.css")
if __name__ == "__main__":
app.run()
2 changes: 1 addition & 1 deletion docs/examples/styles/scrollbars.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ Label {
scrollbar-corner-color: blue;
}

Horizontal > Container {
Horizontal > ScrollableContainer {
width: 50%;
}
8 changes: 5 additions & 3 deletions docs/examples/styles/scrollbars.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from textual.app import App
from textual.containers import Horizontal, Container
from textual.containers import Horizontal, ScrollableContainer
from textual.widgets import Label

TEXT = """I must not fear.
Expand All @@ -15,9 +15,11 @@
class ScrollbarApp(App):
def compose(self):
yield Horizontal(
Container(Label(TEXT * 10)),
Container(Label(TEXT * 10), classes="right"),
ScrollableContainer(Label(TEXT * 10)),
ScrollableContainer(Label(TEXT * 10), classes="right"),
)


app = ScrollbarApp(css_path="scrollbars.css")
if __name__ == "__main__":
app.run()
6 changes: 3 additions & 3 deletions docs/examples/tutorial/stopwatch.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from time import monotonic

from textual.app import App, ComposeResult
from textual.containers import Container
from textual.containers import ScrollableContainer
from textual.reactive import reactive
from textual.widgets import Button, Header, Footer, Static
from textual.widgets import Button, Footer, Header, Static


class TimeDisplay(Static):
Expand Down Expand Up @@ -83,7 +83,7 @@ def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Header()
yield Footer()
yield Container(Stopwatch(), Stopwatch(), Stopwatch(), id="timers")
yield ScrollableContainer(Stopwatch(), Stopwatch(), Stopwatch(), id="timers")

def action_add_stopwatch(self) -> None:
"""An action to add a timer."""
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/tutorial/stopwatch02.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from textual.app import App, ComposeResult
from textual.containers import Container
from textual.widgets import Button, Header, Footer, Static
from textual.containers import ScrollableContainer
from textual.widgets import Button, Footer, Header, Static


class TimeDisplay(Static):
Expand All @@ -27,7 +27,7 @@ def compose(self) -> ComposeResult:
"""Create child widgets for the app."""
yield Header()
yield Footer()
yield Container(Stopwatch(), Stopwatch(), Stopwatch())
yield ScrollableContainer(Stopwatch(), Stopwatch(), Stopwatch())

def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/tutorial/stopwatch03.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from textual.app import App, ComposeResult
from textual.containers import Container
from textual.widgets import Button, Header, Footer, Static
from textual.containers import ScrollableContainer
from textual.widgets import Button, Footer, Header, Static


class TimeDisplay(Static):
Expand Down Expand Up @@ -28,7 +28,7 @@ def compose(self) -> ComposeResult:
"""Create child widgets for the app."""
yield Header()
yield Footer()
yield Container(Stopwatch(), Stopwatch(), Stopwatch())
yield ScrollableContainer(Stopwatch(), Stopwatch(), Stopwatch())

def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/tutorial/stopwatch04.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from textual.app import App, ComposeResult
from textual.containers import Container
from textual.widgets import Button, Header, Footer, Static
from textual.containers import ScrollableContainer
from textual.widgets import Button, Footer, Header, Static


class TimeDisplay(Static):
Expand Down Expand Up @@ -35,7 +35,7 @@ def compose(self) -> ComposeResult:
"""Create child widgets for the app."""
yield Header()
yield Footer()
yield Container(Stopwatch(), Stopwatch(), Stopwatch())
yield ScrollableContainer(Stopwatch(), Stopwatch(), Stopwatch())

def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/tutorial/stopwatch05.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from time import monotonic

from textual.app import App, ComposeResult
from textual.containers import Container
from textual.containers import ScrollableContainer
from textual.reactive import reactive
from textual.widgets import Button, Header, Footer, Static
from textual.widgets import Button, Footer, Header, Static


class TimeDisplay(Static):
Expand Down Expand Up @@ -55,7 +55,7 @@ def compose(self) -> ComposeResult:
"""Create child widgets for the app."""
yield Header()
yield Footer()
yield Container(Stopwatch(), Stopwatch(), Stopwatch())
yield ScrollableContainer(Stopwatch(), Stopwatch(), Stopwatch())

def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/tutorial/stopwatch06.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from time import monotonic

from textual.app import App, ComposeResult
from textual.containers import Container
from textual.containers import ScrollableContainer
from textual.reactive import reactive
from textual.widgets import Button, Header, Footer, Static
from textual.widgets import Button, Footer, Header, Static


class TimeDisplay(Static):
Expand Down Expand Up @@ -78,7 +78,7 @@ def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Header()
yield Footer()
yield Container(Stopwatch(), Stopwatch(), Stopwatch())
yield ScrollableContainer(Stopwatch(), Stopwatch(), Stopwatch())

def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
Expand Down
7 changes: 5 additions & 2 deletions docs/examples/widgets/content_switcher.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from rich.align import VerticalCenter

from textual.app import App, ComposeResult
from textual.containers import Horizontal
from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Button, ContentSwitcher, DataTable, Markdown

MARKDOWN_EXAMPLE = """# Three Flavours Cornetto
Expand Down Expand Up @@ -37,7 +39,8 @@ def compose(self) -> ComposeResult:

with ContentSwitcher(initial="data-table"): # (4)!
yield DataTable(id="data-table")
yield Markdown(MARKDOWN_EXAMPLE, id="markdown")
with VerticalScroll(id="markdown"):
yield Markdown(MARKDOWN_EXAMPLE)

def on_button_pressed(self, event: Button.Pressed) -> None:
self.query_one(ContentSwitcher).current = event.button.id # (5)!
Expand Down
6 changes: 3 additions & 3 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ Let's add those to the app. Just a skeleton for now, we will add the rest of the
--8<-- "docs/examples/tutorial/stopwatch02.py"
```

We've imported two new widgets in this code: `Button`, which creates a clickable button, and `Static` which is a base class for a simple control. We've also imported `Container` from `textual.containers` which (as the name suggests) is a `Widget` which contains other widgets.
We've imported two new widgets in this code: `Button`, which creates a clickable button, and `Static` which is a base class for a simple control. We've also imported `ScrollableContainer` from `textual.containers` which (as the name suggests) is a `Widget` which contains other widgets.

We've defined an empty `TimeDisplay` widget by extending `Static`. We will flesh this out later.

Expand All @@ -174,7 +174,7 @@ The Button constructor takes a label to be displayed in the button (`"Start"`, `

To add widgets to our application we first need to yield them from the app's `compose()` method:

The new line in `StopwatchApp.compose()` yields a single `Container` object which will create a scrolling list of stopwatches. When classes contain other widgets (like `Container`) they will typically accept their child widgets as positional arguments. We want to start the app with three stopwatches, so we construct three `Stopwatch` instances and pass them to the container's constructor.
The new line in `StopwatchApp.compose()` yields a single `ScrollableContainer` object which will create a scrolling list of stopwatches. When classes contain other widgets (like `ScrollableContainer`) they will typically accept their child widgets as positional arguments. We want to start the app with three stopwatches, so we construct three `Stopwatch` instances and pass them to the container's constructor.


### The unstyled app
Expand Down Expand Up @@ -438,7 +438,7 @@ Let's use these methods to implement adding and removing stopwatches to our app.

Here's a summary of the changes:

- The `Container` object in `StopWatchApp` grew a `"timers"` ID.
- The `ScrollableContainer` object in `StopWatchApp` grew a `"timers"` ID.
- Added `action_add_stopwatch` to add a new stopwatch.
- Added `action_remove_stopwatch` to remove a stopwatch.
- Added keybindings for the actions.
Expand Down
2 changes: 1 addition & 1 deletion src/textual/cli/previews/easing.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def compose(self) -> ComposeResult:
yield duration_input
with Horizontal():
yield self.animated_bar
yield Container(self.opacity_widget, id="other")
yield VerticalScroll(self.opacity_widget, id="other")
yield Footer()

def on_button_pressed(self, event: Button.Pressed) -> None:
Expand Down
11 changes: 10 additions & 1 deletion src/textual/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,21 @@ class Container(Widget):
Container {
height: 1fr;
layout: vertical;
overflow: auto;
overflow: hidden hidden;
}
"""


class ScrollableContainer(Widget, inherit_bindings=False):
"""Base container widget that binds navigation keys for scrolling."""

DEFAULT_CSS = """
ScrollableContainer {
layout: vertical;
overflow: auto auto;
}
"""

BINDINGS: ClassVar[list[BindingType]] = [
Binding("up", "scroll_up", "Scroll Up", show=False),
Binding("down", "scroll_down", "Scroll Down", show=False),
Expand Down Expand Up @@ -69,6 +76,7 @@ class VerticalScroll(ScrollableContainer, can_focus=True):
VerticalScroll {
width: 1fr;
layout: vertical;
overflow-x: hidden;
overflow-y: auto;
}
"""
Expand All @@ -93,6 +101,7 @@ class HorizontalScroll(ScrollableContainer, can_focus=True):
HorizontalScroll {
height: 1fr;
layout: horizontal;
overflow-y: hidden;
overflow-x: auto;
}
"""
Expand Down
4 changes: 2 additions & 2 deletions tests/snapshot_tests/snapshot_apps/auto-table.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from random import randrange

from textual.app import App
from textual.containers import Container, Horizontal, Vertical
from textual.containers import Container, Horizontal, ScrollableContainer, Vertical
from textual.screen import Screen
from textual.widgets import DataTable, Header, Label

Expand Down Expand Up @@ -109,7 +109,7 @@ def __init__(self):

super().__init__(
"",
Container(
ScrollableContainer(
Horizontal(self.__info, id="issue-info"),
Horizontal(*[Status(str(i)) for i in range(4)], id="statuses-box"),
id="issues-box",
Expand Down