From 8565d3cef6be856ee4ab6a4847c9a4f179c713c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Wed, 8 Mar 2023 18:31:24 +0000
Subject: [PATCH 01/16] Renamed 'Vertical' to 'VerticalScroll'.
Related issues: #1957.
---
CHANGELOG.md | 1 +
.../blocking01.py | 6 +++---
.../blocking02.py | 6 +++---
.../nonblocking01.py | 6 +++---
docs/examples/events/dictionary.py | 7 ++++---
docs/examples/guide/layout/combining_layouts.py | 4 ++--
docs/examples/guide/layout/utility_containers.py | 6 +++---
.../guide/layout/utility_containers_using_with.py | 6 +++---
docs/examples/styles/height_comparison.py | 6 +++---
docs/examples/styles/max_width.py | 4 ++--
docs/examples/styles/min_width.css | 5 +++--
docs/examples/styles/min_width.py | 4 ++--
docs/examples/styles/overflow.css | 4 ++--
docs/examples/styles/overflow.py | 6 +++---
docs/examples/styles/scrollbar_size.py | 4 ++--
docs/examples/styles/visibility_containers.py | 4 ++--
docs/examples/widgets/button.css | 2 +-
docs/examples/widgets/button.py | 6 +++---
docs/examples/widgets/checkbox.css | 2 +-
docs/examples/widgets/checkbox.py | 4 ++--
docs/examples/widgets/placeholder.py | 5 ++---
docs/examples/widgets/radio_set_changed.css | 2 +-
docs/examples/widgets/radio_set_changed.py | 4 ++--
docs/guide/layout.md | 6 +++---
docs/styles/height.md | 4 ++--
docs/styles/overflow.md | 2 +-
examples/code_browser.py | 4 ++--
src/textual/_segment_tools.py | 3 +--
src/textual/cli/previews/borders.py | 4 ++--
src/textual/cli/previews/colors.py | 10 +++++-----
src/textual/cli/previews/easing.py | 4 ++--
src/textual/containers.py | 8 ++++----
src/textual/widgets/_list_view.py | 4 ++--
src/textual/widgets/_markdown.py | 14 +++++++-------
.../snapshot_apps/auto_width_input.py | 3 +--
.../snapshot_apps/disable_widgets.py | 7 +++----
.../snapshot_apps/focus_component_class.py | 4 ++--
tests/snapshot_tests/snapshot_apps/fr_units.py | 5 ++---
.../snapshot_apps/layer_order_independence.py | 7 +++----
.../snapshot_apps/line_api_scrollbars.py | 14 +++++++-------
.../snapshot_apps/nested_auto_heights.py | 6 +++---
tests/snapshot_tests/snapshot_apps/offsets.py | 3 +--
tests/snapshot_tests/snapshot_apps/visibility.py | 9 ++++-----
tests/test_disabled.py | 8 ++++----
tests/test_focus.py | 4 ++--
tests/test_overflow_change.py | 7 +++----
tests/test_visibility_change.py | 4 ++--
47 files changed, 121 insertions(+), 127 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a008e826f..f665c00e4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Updated styling to make it clear DataTable grows horizontally https://github.com/Textualize/textual/pull/1946
- Changed the `Checkbox` character due to issues with Windows Terminal and Windows 10 https://github.com/Textualize/textual/issues/1934
- Changed the `RadioButton` character due to issues with Windows Terminal and Windows 10 and 11 https://github.com/Textualize/textual/issues/1934
+- Renamed `Vertical` to `VerticalScroll` https://github.com/Textualize/textual/issues/1957
### Added
diff --git a/docs/blog/snippets/2022-12-07-responsive-app-background-task/blocking01.py b/docs/blog/snippets/2022-12-07-responsive-app-background-task/blocking01.py
index 6e0ab0949..9773da0c9 100644
--- a/docs/blog/snippets/2022-12-07-responsive-app-background-task/blocking01.py
+++ b/docs/blog/snippets/2022-12-07-responsive-app-background-task/blocking01.py
@@ -1,9 +1,9 @@
-from random import randint
import time
+from random import randint
from textual.app import App, ComposeResult
from textual.color import Color
-from textual.containers import Grid, Vertical
+from textual.containers import Grid, VerticalScroll
from textual.widget import Widget
from textual.widgets import Footer, Label
@@ -28,7 +28,7 @@ class MyApp(App[None]):
def compose(self) -> ComposeResult:
yield Grid(
ColourChanger(),
- Vertical(id="log"),
+ VerticalScroll(id="log"),
)
yield Footer()
diff --git a/docs/blog/snippets/2022-12-07-responsive-app-background-task/blocking02.py b/docs/blog/snippets/2022-12-07-responsive-app-background-task/blocking02.py
index 693bde821..0edefbeff 100644
--- a/docs/blog/snippets/2022-12-07-responsive-app-background-task/blocking02.py
+++ b/docs/blog/snippets/2022-12-07-responsive-app-background-task/blocking02.py
@@ -1,10 +1,10 @@
import asyncio
-from random import randint
import time
+from random import randint
from textual.app import App, ComposeResult
from textual.color import Color
-from textual.containers import Grid, Vertical
+from textual.containers import Grid, VerticalScroll
from textual.widget import Widget
from textual.widgets import Footer, Label
@@ -29,7 +29,7 @@ class MyApp(App[None]):
def compose(self) -> ComposeResult:
yield Grid(
ColourChanger(),
- Vertical(id="log"),
+ VerticalScroll(id="log"),
)
yield Footer()
diff --git a/docs/blog/snippets/2022-12-07-responsive-app-background-task/nonblocking01.py b/docs/blog/snippets/2022-12-07-responsive-app-background-task/nonblocking01.py
index 2c96e5ed6..20f2daba8 100644
--- a/docs/blog/snippets/2022-12-07-responsive-app-background-task/nonblocking01.py
+++ b/docs/blog/snippets/2022-12-07-responsive-app-background-task/nonblocking01.py
@@ -1,10 +1,10 @@
import asyncio
-from random import randint
import time
+from random import randint
from textual.app import App, ComposeResult
from textual.color import Color
-from textual.containers import Grid, Vertical
+from textual.containers import Grid, VerticalScroll
from textual.widget import Widget
from textual.widgets import Footer, Label
@@ -29,7 +29,7 @@ class MyApp(App[None]):
def compose(self) -> ComposeResult:
yield Grid(
ColourChanger(),
- Vertical(id="log"),
+ VerticalScroll(id="log"),
)
yield Footer()
diff --git a/docs/examples/events/dictionary.py b/docs/examples/events/dictionary.py
index cf85c2bf6..51421ad39 100644
--- a/docs/examples/events/dictionary.py
+++ b/docs/examples/events/dictionary.py
@@ -6,9 +6,10 @@ except ImportError:
raise ImportError("Please install httpx with 'pip install httpx' ")
from rich.json import JSON
+
from textual.app import App, ComposeResult
-from textual.containers import Vertical
-from textual.widgets import Static, Input
+from textual.containers import VerticalScroll
+from textual.widgets import Input, Static
class DictionaryApp(App):
@@ -18,7 +19,7 @@ class DictionaryApp(App):
def compose(self) -> ComposeResult:
yield Input(placeholder="Search for a word")
- yield Vertical(Static(id="results"), id="results-container")
+ yield VerticalScroll(Static(id="results"), id="results-container")
async def on_input_changed(self, message: Input.Changed) -> None:
"""A coroutine to handle a text changed message."""
diff --git a/docs/examples/guide/layout/combining_layouts.py b/docs/examples/guide/layout/combining_layouts.py
index c52ecce0d..e608152cd 100644
--- a/docs/examples/guide/layout/combining_layouts.py
+++ b/docs/examples/guide/layout/combining_layouts.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Container, Horizontal, Vertical
+from textual.containers import Container, Horizontal, VerticalScroll
from textual.widgets import Header, Static
@@ -9,7 +9,7 @@ class CombiningLayoutsExample(App):
def compose(self) -> ComposeResult:
yield Header()
with Container(id="app-grid"):
- with Vertical(id="left-pane"):
+ with VerticalScroll(id="left-pane"):
for number in range(15):
yield Static(f"Vertical layout, child {number}")
with Horizontal(id="top-right"):
diff --git a/docs/examples/guide/layout/utility_containers.py b/docs/examples/guide/layout/utility_containers.py
index eadf58b4c..80cfada17 100644
--- a/docs/examples/guide/layout/utility_containers.py
+++ b/docs/examples/guide/layout/utility_containers.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Horizontal, Vertical
+from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Static
@@ -8,12 +8,12 @@ class UtilityContainersExample(App):
def compose(self) -> ComposeResult:
yield Horizontal(
- Vertical(
+ VerticalScroll(
Static("One"),
Static("Two"),
classes="column",
),
- Vertical(
+ VerticalScroll(
Static("Three"),
Static("Four"),
classes="column",
diff --git a/docs/examples/guide/layout/utility_containers_using_with.py b/docs/examples/guide/layout/utility_containers_using_with.py
index d09a3481e..4abe3f9f5 100644
--- a/docs/examples/guide/layout/utility_containers_using_with.py
+++ b/docs/examples/guide/layout/utility_containers_using_with.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Horizontal, Vertical
+from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Static
@@ -8,10 +8,10 @@ class UtilityContainersExample(App):
def compose(self) -> ComposeResult:
with Horizontal():
- with Vertical(classes="column"):
+ with VerticalScroll(classes="column"):
yield Static("One")
yield Static("Two")
- with Vertical(classes="column"):
+ with VerticalScroll(classes="column"):
yield Static("Three")
yield Static("Four")
diff --git a/docs/examples/styles/height_comparison.py b/docs/examples/styles/height_comparison.py
index c679a68e6..41d8f0a76 100644
--- a/docs/examples/styles/height_comparison.py
+++ b/docs/examples/styles/height_comparison.py
@@ -1,6 +1,6 @@
from textual.app import App
-from textual.containers import Vertical
-from textual.widgets import Placeholder, Label, Static
+from textual.containers import VerticalScroll
+from textual.widgets import Label, Placeholder, Static
class Ruler(Static):
@@ -11,7 +11,7 @@ class Ruler(Static):
class HeightComparisonApp(App):
def compose(self):
- yield Vertical(
+ yield VerticalScroll(
Placeholder(id="cells"), # (1)!
Placeholder(id="percent"),
Placeholder(id="w"),
diff --git a/docs/examples/styles/max_width.py b/docs/examples/styles/max_width.py
index 0ee440a92..7ea482dc7 100644
--- a/docs/examples/styles/max_width.py
+++ b/docs/examples/styles/max_width.py
@@ -1,11 +1,11 @@
from textual.app import App
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Placeholder
class MaxWidthApp(App):
def compose(self):
- yield Vertical(
+ yield VerticalScroll(
Placeholder("max-width: 50h", id="p1"),
Placeholder("max-width: 999", id="p2"),
Placeholder("max-width: 50%", id="p3"),
diff --git a/docs/examples/styles/min_width.css b/docs/examples/styles/min_width.css
index 43dd8400a..ba2dd81c6 100644
--- a/docs/examples/styles/min_width.css
+++ b/docs/examples/styles/min_width.css
@@ -1,4 +1,4 @@
-Vertical {
+VerticalScroll {
height: 100%;
width: 100%;
overflow-x: auto;
@@ -10,7 +10,8 @@ Placeholder {
}
#p1 {
- min-width: 25%; /* (1)! */
+ min-width: 25%;
+ /* (1)! */
}
#p2 {
diff --git a/docs/examples/styles/min_width.py b/docs/examples/styles/min_width.py
index 25195c61d..b00881266 100644
--- a/docs/examples/styles/min_width.py
+++ b/docs/examples/styles/min_width.py
@@ -1,11 +1,11 @@
from textual.app import App
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Placeholder
class MinWidthApp(App):
def compose(self):
- yield Vertical(
+ yield VerticalScroll(
Placeholder("min-width: 25%", id="p1"),
Placeholder("min-width: 75%", id="p2"),
Placeholder("min-width: 100", id="p3"),
diff --git a/docs/examples/styles/overflow.css b/docs/examples/styles/overflow.css
index 3b68440c7..527429097 100644
--- a/docs/examples/styles/overflow.css
+++ b/docs/examples/styles/overflow.css
@@ -3,7 +3,7 @@ Screen {
color: black;
}
-Vertical {
+VerticalScroll {
width: 1fr;
}
@@ -13,7 +13,7 @@ Static {
border: green wide;
color: white 90%;
height: auto;
-}
+}
#right {
overflow-y: hidden;
diff --git a/docs/examples/styles/overflow.py b/docs/examples/styles/overflow.py
index b9a6c3383..debe0252d 100644
--- a/docs/examples/styles/overflow.py
+++ b/docs/examples/styles/overflow.py
@@ -1,6 +1,6 @@
from textual.app import App
+from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Static
-from textual.containers import Horizontal, Vertical
TEXT = """I must not fear.
Fear is the mind-killer.
@@ -14,8 +14,8 @@ Where the fear has gone there will be nothing. Only I will remain."""
class OverflowApp(App):
def compose(self):
yield Horizontal(
- Vertical(Static(TEXT), Static(TEXT), Static(TEXT), id="left"),
- Vertical(Static(TEXT), Static(TEXT), Static(TEXT), id="right"),
+ VerticalScroll(Static(TEXT), Static(TEXT), Static(TEXT), id="left"),
+ VerticalScroll(Static(TEXT), Static(TEXT), Static(TEXT), id="right"),
)
diff --git a/docs/examples/styles/scrollbar_size.py b/docs/examples/styles/scrollbar_size.py
index 1bbcec572..e949aaaca 100644
--- a/docs/examples/styles/scrollbar_size.py
+++ b/docs/examples/styles/scrollbar_size.py
@@ -1,5 +1,5 @@
from textual.app import App
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Label
TEXT = """I must not fear.
@@ -14,7 +14,7 @@ Where the fear has gone there will be nothing. Only I will remain.
class ScrollbarApp(App):
def compose(self):
- yield Vertical(Label(TEXT * 5), classes="panel")
+ yield VerticalScroll(Label(TEXT * 5), classes="panel")
app = ScrollbarApp(css_path="scrollbar_size.css")
diff --git a/docs/examples/styles/visibility_containers.py b/docs/examples/styles/visibility_containers.py
index 879b916fb..a94de145d 100644
--- a/docs/examples/styles/visibility_containers.py
+++ b/docs/examples/styles/visibility_containers.py
@@ -1,11 +1,11 @@
from textual.app import App
-from textual.containers import Horizontal, Vertical
+from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Placeholder
class VisibilityContainersApp(App):
def compose(self):
- yield Vertical(
+ yield VerticalScroll(
Horizontal(
Placeholder(),
Placeholder(),
diff --git a/docs/examples/widgets/button.css b/docs/examples/widgets/button.css
index 5f1c906da..aee652f68 100644
--- a/docs/examples/widgets/button.css
+++ b/docs/examples/widgets/button.css
@@ -2,7 +2,7 @@ Button {
margin: 1 2;
}
-Horizontal > Vertical {
+Horizontal>VerticalScroll {
width: 24;
}
diff --git a/docs/examples/widgets/button.py b/docs/examples/widgets/button.py
index 4c3509c32..09339ccb0 100644
--- a/docs/examples/widgets/button.py
+++ b/docs/examples/widgets/button.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Horizontal, Vertical
+from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Button, Static
@@ -8,7 +8,7 @@ class ButtonsApp(App[str]):
def compose(self) -> ComposeResult:
yield Horizontal(
- Vertical(
+ VerticalScroll(
Static("Standard Buttons", classes="header"),
Button("Default"),
Button("Primary!", variant="primary"),
@@ -16,7 +16,7 @@ class ButtonsApp(App[str]):
Button.warning("Warning!"),
Button.error("Error!"),
),
- Vertical(
+ VerticalScroll(
Static("Disabled Buttons", classes="header"),
Button("Default", disabled=True),
Button("Primary!", variant="primary", disabled=True),
diff --git a/docs/examples/widgets/checkbox.css b/docs/examples/widgets/checkbox.css
index 4e80b6685..b6e17c093 100644
--- a/docs/examples/widgets/checkbox.css
+++ b/docs/examples/widgets/checkbox.css
@@ -2,7 +2,7 @@ Screen {
align: center middle;
}
-Vertical {
+VerticalScroll {
width: auto;
height: auto;
border: solid $primary;
diff --git a/docs/examples/widgets/checkbox.py b/docs/examples/widgets/checkbox.py
index 5ad6ca1ff..75eadda0c 100644
--- a/docs/examples/widgets/checkbox.py
+++ b/docs/examples/widgets/checkbox.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Checkbox
@@ -7,7 +7,7 @@ class CheckboxApp(App[None]):
CSS_PATH = "checkbox.css"
def compose(self) -> ComposeResult:
- with Vertical():
+ with VerticalScroll():
yield Checkbox("Arrakis :sweat:")
yield Checkbox("Caladan")
yield Checkbox("Chusuk")
diff --git a/docs/examples/widgets/placeholder.py b/docs/examples/widgets/placeholder.py
index c09e9c412..9c7d6eb0e 100644
--- a/docs/examples/widgets/placeholder.py
+++ b/docs/examples/widgets/placeholder.py
@@ -1,14 +1,13 @@
from textual.app import App, ComposeResult
-from textual.containers import Container, Horizontal, Vertical
+from textual.containers import Container, Horizontal, VerticalScroll
from textual.widgets import Placeholder
class PlaceholderApp(App):
-
CSS_PATH = "placeholder.css"
def compose(self) -> ComposeResult:
- yield Vertical(
+ yield VerticalScroll(
Container(
Placeholder("This is a custom label for p1.", id="p1"),
Placeholder("Placeholder p2 here!", id="p2"),
diff --git a/docs/examples/widgets/radio_set_changed.css b/docs/examples/widgets/radio_set_changed.css
index 47583c1d8..fc1299294 100644
--- a/docs/examples/widgets/radio_set_changed.css
+++ b/docs/examples/widgets/radio_set_changed.css
@@ -1,4 +1,4 @@
-Vertical {
+VerticalScroll {
align: center middle;
}
diff --git a/docs/examples/widgets/radio_set_changed.py b/docs/examples/widgets/radio_set_changed.py
index c360cb868..c817b6e6f 100644
--- a/docs/examples/widgets/radio_set_changed.py
+++ b/docs/examples/widgets/radio_set_changed.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Horizontal, Vertical
+from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Label, RadioButton, RadioSet
@@ -7,7 +7,7 @@ class RadioSetChangedApp(App[None]):
CSS_PATH = "radio_set_changed.css"
def compose(self) -> ComposeResult:
- with Vertical():
+ with VerticalScroll():
with Horizontal():
with RadioSet():
yield RadioButton("Battlestar Galactica")
diff --git a/docs/guide/layout.md b/docs/guide/layout.md
index 3fe1184e0..db8d97dfe 100644
--- a/docs/guide/layout.md
+++ b/docs/guide/layout.md
@@ -135,10 +135,10 @@ exceeds the available horizontal space in the parent container.
## Utility containers
Textual comes with several "container" widgets.
-These are [Vertical][textual.containers.Vertical], [Horizontal][textual.containers.Horizontal], and [Grid][textual.containers.Grid] which have the corresponding layout.
+These are [VerticalScroll][textual.containers.VerticalScroll], [Horizontal][textual.containers.Horizontal], and [Grid][textual.containers.Grid] which have the corresponding layout.
The example below shows how we can combine these containers to create a simple 2x2 grid.
-Inside a single `Horizontal` container, we place two `Vertical` containers.
+Inside a single `Horizontal` container, we place two `VerticalScroll` containers.
In other words, we have a single row containing two columns.
=== "Output"
@@ -163,7 +163,7 @@ However, Textual comes with a more powerful mechanism for achieving this known a
## Composing with context managers
-In the previous section we've show how you add children to a container (such as `Horizontal` and `Vertical`) using positional arguments.
+In the previous section we've show how you add children to a container (such as `Horizontal` and `VerticalScroll`) using positional arguments.
It's fine to do it this way, but Textual offers a simplified syntax using [context managers](https://docs.python.org/3/reference/datamodel.html#context-managers) which is generally easier to write and edit.
When composing a widget, you can introduce a container using Python's `with` statement.
diff --git a/docs/styles/height.md b/docs/styles/height.md
index 15d5399a3..bd3fe3512 100644
--- a/docs/styles/height.md
+++ b/docs/styles/height.md
@@ -61,8 +61,8 @@ Open the CSS file tab to see the comments that explain how each height is comput
1. This sets the height to 2 lines.
2. This sets the height to 12.5% of the space made available by the container. The container is 24 lines tall, so 12.5% of 24 is 3.
- 3. This sets the height to 5% of the width of the direct container, which is the `Vertical` container. Because it expands to fit all of the terminal, the width of the `Vertical` is 80 and 5% of 80 is 4.
- 4. This sets the height to 12.5% of the height of the direct container, which is the `Vertical` container. Because it expands to fit all of the terminal, the height of the `Vertical` is 24 and 12.5% of 24 is 3.
+ 3. This sets the height to 5% of the width of the direct container, which is the `VerticalScroll` container. Because it expands to fit all of the terminal, the width of the `VerticalScroll` is 80 and 5% of 80 is 4.
+ 4. This sets the height to 12.5% of the height of the direct container, which is the `VerticalScroll` container. Because it expands to fit all of the terminal, the height of the `VerticalScroll` is 24 and 12.5% of 24 is 3.
5. This sets the height to 6.25% of the viewport width, which is 80. 6.25% of 80 is 5.
6. This sets the height to 12.5% of the viewport height, which is 24. 12.5% of 24 is 3.
7. This sets the height of the placeholder to be the optimal size that fits the content without scrolling.
diff --git a/docs/styles/overflow.md b/docs/styles/overflow.md
index 12edaac15..d3f0ece5f 100644
--- a/docs/styles/overflow.md
+++ b/docs/styles/overflow.md
@@ -25,7 +25,7 @@ The default setting for containers is `overflow: auto auto`.
!!! warning
- Some built-in containers like `Horizontal` and `Vertical` override these defaults.
+ Some built-in containers like `Horizontal` and `VerticalScroll` override these defaults.
## Example
diff --git a/examples/code_browser.py b/examples/code_browser.py
index 4616be4f7..13fdf3c6d 100644
--- a/examples/code_browser.py
+++ b/examples/code_browser.py
@@ -14,7 +14,7 @@ from rich.traceback import Traceback
from textual import events
from textual.app import App, ComposeResult
-from textual.containers import Container, Vertical
+from textual.containers import Container, VerticalScroll
from textual.reactive import var
from textual.widgets import DirectoryTree, Footer, Header, Static
@@ -40,7 +40,7 @@ class CodeBrowser(App):
yield Header()
with Container():
yield DirectoryTree(path, id="tree-view")
- with Vertical(id="code-view"):
+ with VerticalScroll(id="code-view"):
yield Static(id="code", expand=True)
yield Footer()
diff --git a/src/textual/_segment_tools.py b/src/textual/_segment_tools.py
index 5f9df333b..79f3bc077 100644
--- a/src/textual/_segment_tools.py
+++ b/src/textual/_segment_tools.py
@@ -192,11 +192,10 @@ def align_lines(
style: Background style.
size: Size of container.
horizontal: Horizontal alignment.
- vertical: Vertical alignment
+ vertical: Vertical alignment.
Returns:
Aligned lines.
-
"""
width, height = size
diff --git a/src/textual/cli/previews/borders.py b/src/textual/cli/previews/borders.py
index a33320a0a..09dbcaab4 100644
--- a/src/textual/cli/previews/borders.py
+++ b/src/textual/cli/previews/borders.py
@@ -1,6 +1,6 @@
from textual.app import App, ComposeResult
from textual.constants import BORDERS
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Button, Label
TEXT = """I must not fear.
@@ -12,7 +12,7 @@ And when it has gone past, I will turn the inner eye to see its path.
Where the fear has gone there will be nothing. Only I will remain."""
-class BorderButtons(Vertical):
+class BorderButtons(VerticalScroll):
DEFAULT_CSS = """
BorderButtons {
dock: left;
diff --git a/src/textual/cli/previews/colors.py b/src/textual/cli/previews/colors.py
index b9d8da3eb..d8028f7c5 100644
--- a/src/textual/cli/previews/colors.py
+++ b/src/textual/cli/previews/colors.py
@@ -1,11 +1,11 @@
from textual.app import App, ComposeResult
-from textual.containers import Horizontal, Vertical
+from textual.containers import Horizontal, VerticalScroll
from textual.design import ColorSystem
from textual.widget import Widget
from textual.widgets import Button, Footer, Label, Static
-class ColorButtons(Vertical):
+class ColorButtons(VerticalScroll):
def compose(self) -> ComposeResult:
for border in ColorSystem.COLOR_NAMES:
if border:
@@ -20,15 +20,15 @@ class ColorItem(Horizontal):
pass
-class ColorGroup(Vertical):
+class ColorGroup(VerticalScroll):
pass
-class Content(Vertical):
+class Content(VerticalScroll):
pass
-class ColorsView(Vertical):
+class ColorsView(VerticalScroll):
def compose(self) -> ComposeResult:
LEVELS = [
"darken-3",
diff --git a/src/textual/cli/previews/easing.py b/src/textual/cli/previews/easing.py
index 70dc45758..7bca58efa 100644
--- a/src/textual/cli/previews/easing.py
+++ b/src/textual/cli/previews/easing.py
@@ -5,7 +5,7 @@ from rich.console import RenderableType
from textual._easing import EASING
from textual.app import App, ComposeResult
from textual.cli.previews.borders import TEXT
-from textual.containers import Container, Horizontal, Vertical
+from textual.containers import Container, Horizontal, VerticalScroll
from textual.reactive import reactive, var
from textual.scrollbar import ScrollBarRender
from textual.widget import Widget
@@ -73,7 +73,7 @@ class EasingApp(App):
)
yield EasingButtons()
- with Vertical():
+ with VerticalScroll():
with Horizontal(id="inputs"):
yield Label("Animation Duration:", id="label")
yield duration_input
diff --git a/src/textual/containers.py b/src/textual/containers.py
index bbd4c13d7..37e3729e2 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -13,11 +13,11 @@ class Container(Widget):
"""
-class Vertical(Widget):
+class VerticalScroll(Widget):
"""A container widget which aligns children vertically."""
DEFAULT_CSS = """
- Vertical {
+ VerticalScroll {
height: 1fr;
layout: vertical;
overflow-y: auto;
@@ -44,7 +44,7 @@ class Grid(Widget):
Grid {
height: 1fr;
layout: grid;
- }
+ }
"""
@@ -52,7 +52,7 @@ class Content(Widget, can_focus=True, can_focus_children=False):
"""A container for content such as text."""
DEFAULT_CSS = """
- Vertical {
+ VerticalScroll {
height: 1fr;
layout: vertical;
overflow-y: auto;
diff --git a/src/textual/widgets/_list_view.py b/src/textual/widgets/_list_view.py
index 013c51ead..8f95d011d 100644
--- a/src/textual/widgets/_list_view.py
+++ b/src/textual/widgets/_list_view.py
@@ -4,7 +4,7 @@ from typing import ClassVar, Optional
from textual.await_remove import AwaitRemove
from textual.binding import Binding, BindingType
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.geometry import clamp
from textual.message import Message
from textual.reactive import reactive
@@ -12,7 +12,7 @@ from textual.widget import AwaitMount, Widget
from textual.widgets._list_item import ListItem
-class ListView(Vertical, can_focus=True, can_focus_children=False):
+class ListView(VerticalScroll, can_focus=True, can_focus_children=False):
"""A vertical list view widget.
Displays a vertical list of `ListItem`s which can be highlighted and
diff --git a/src/textual/widgets/_markdown.py b/src/textual/widgets/_markdown.py
index f352683f7..c55fe1f94 100644
--- a/src/textual/widgets/_markdown.py
+++ b/src/textual/widgets/_markdown.py
@@ -10,7 +10,7 @@ from rich.text import Text
from typing_extensions import TypeAlias
from ..app import ComposeResult
-from ..containers import Horizontal, Vertical
+from ..containers import Horizontal, VerticalScroll
from ..message import Message
from ..reactive import reactive, var
from ..widget import Widget
@@ -266,7 +266,7 @@ class MarkdownBulletList(MarkdownList):
width: 1fr;
}
- MarkdownBulletList Vertical {
+ MarkdownBulletList VerticalScroll {
height: auto;
width: 1fr;
}
@@ -277,7 +277,7 @@ class MarkdownBulletList(MarkdownList):
if isinstance(block, MarkdownListItem):
bullet = MarkdownBullet()
bullet.symbol = block.bullet
- yield Horizontal(bullet, Vertical(*block._blocks))
+ yield Horizontal(bullet, VerticalScroll(*block._blocks))
self._blocks.clear()
@@ -295,7 +295,7 @@ class MarkdownOrderedList(MarkdownList):
width: 1fr;
}
- MarkdownOrderedList Vertical {
+ MarkdownOrderedList VerticalScroll {
height: auto;
width: 1fr;
}
@@ -311,7 +311,7 @@ class MarkdownOrderedList(MarkdownList):
if isinstance(block, MarkdownListItem):
bullet = MarkdownBullet()
bullet.symbol = block.bullet.rjust(symbol_size + 1)
- yield Horizontal(bullet, Vertical(*block._blocks))
+ yield Horizontal(bullet, VerticalScroll(*block._blocks))
self._blocks.clear()
@@ -410,7 +410,7 @@ class MarkdownListItem(MarkdownBlock):
height: auto;
}
- MarkdownListItem > Vertical {
+ MarkdownListItem > VerticalScroll {
width: 1fr;
height: auto;
}
@@ -761,7 +761,7 @@ class MarkdownTableOfContents(Widget, can_focus_children=True):
)
-class MarkdownViewer(Vertical, can_focus=True, can_focus_children=True):
+class MarkdownViewer(VerticalScroll, can_focus=True, can_focus_children=True):
"""A Markdown viewer widget."""
DEFAULT_CSS = """
diff --git a/tests/snapshot_tests/snapshot_apps/auto_width_input.py b/tests/snapshot_tests/snapshot_apps/auto_width_input.py
index 35cc3b2ec..e312e653e 100644
--- a/tests/snapshot_tests/snapshot_apps/auto_width_input.py
+++ b/tests/snapshot_tests/snapshot_apps/auto_width_input.py
@@ -1,10 +1,9 @@
from textual.app import App, ComposeResult
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Header, Footer, Label, Input
class InputWidthAutoApp(App[None]):
-
CSS = """
Input.auto {
width: auto;
diff --git a/tests/snapshot_tests/snapshot_apps/disable_widgets.py b/tests/snapshot_tests/snapshot_apps/disable_widgets.py
index 7a241e914..fb321b3b6 100644
--- a/tests/snapshot_tests/snapshot_apps/disable_widgets.py
+++ b/tests/snapshot_tests/snapshot_apps/disable_widgets.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Vertical, Horizontal
+from textual.containers import VerticalScroll, Horizontal
from textual.widgets import (
Header,
Footer,
@@ -17,7 +17,6 @@ from textual.widgets import (
class WidgetDisableTestApp(App[None]):
-
CSS = """
Horizontal {
height: auto;
@@ -54,7 +53,7 @@ class WidgetDisableTestApp(App[None]):
def compose(self) -> ComposeResult:
yield Header()
- yield Vertical(
+ yield VerticalScroll(
Horizontal(
Button(),
Button(variant="primary"),
@@ -77,7 +76,7 @@ class WidgetDisableTestApp(App[None]):
def on_mount(self) -> None:
self.query_one(TextLog).write("Hello, World!")
- self.query_one("#test-container", Vertical).disabled = True
+ self.query_one("#test-container", VerticalScroll).disabled = True
if __name__ == "__main__":
diff --git a/tests/snapshot_tests/snapshot_apps/focus_component_class.py b/tests/snapshot_tests/snapshot_apps/focus_component_class.py
index 85becd79b..77ac46212 100644
--- a/tests/snapshot_tests/snapshot_apps/focus_component_class.py
+++ b/tests/snapshot_tests/snapshot_apps/focus_component_class.py
@@ -1,7 +1,7 @@
from rich.text import Text
from textual.app import App, ComposeResult, RenderResult
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Header, Footer
from textual.widget import Widget
@@ -32,7 +32,7 @@ class Tester(Widget, can_focus=True):
class StyleBugApp(App[None]):
def compose(self) -> ComposeResult:
yield Header()
- with Vertical():
+ with VerticalScroll():
for n in range(40):
yield Tester(n)
yield Footer()
diff --git a/tests/snapshot_tests/snapshot_apps/fr_units.py b/tests/snapshot_tests/snapshot_apps/fr_units.py
index d9bcddeb9..1ece79ebc 100644
--- a/tests/snapshot_tests/snapshot_apps/fr_units.py
+++ b/tests/snapshot_tests/snapshot_apps/fr_units.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Horizontal, Vertical
+from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Static
@@ -8,7 +8,6 @@ class StaticText(Static):
class FRApp(App):
-
CSS = """
StaticText {
height: 1fr;
@@ -39,7 +38,7 @@ class FRApp(App):
"""
def compose(self) -> ComposeResult:
- yield Vertical(
+ yield VerticalScroll(
StaticText("HEADER", id="header"),
Horizontal(
StaticText("foo", id="foo"),
diff --git a/tests/snapshot_tests/snapshot_apps/layer_order_independence.py b/tests/snapshot_tests/snapshot_apps/layer_order_independence.py
index 2ad43e931..a3deec8ba 100644
--- a/tests/snapshot_tests/snapshot_apps/layer_order_independence.py
+++ b/tests/snapshot_tests/snapshot_apps/layer_order_independence.py
@@ -1,7 +1,7 @@
from textual.app import App, ComposeResult
from textual.screen import Screen
from textual.widgets import Header, Footer, Label
-from textual.containers import Vertical, Container
+from textual.containers import VerticalScroll, Container
class Overlay(Container):
@@ -9,12 +9,12 @@ class Overlay(Container):
yield Label("This should float over the top")
-class Body1(Vertical):
+class Body1(VerticalScroll):
def compose(self) -> ComposeResult:
yield Label("My God! It's full of stars! " * 300)
-class Body2(Vertical):
+class Body2(VerticalScroll):
def compose(self) -> ComposeResult:
yield Label("My God! It's full of stars! " * 300)
@@ -36,7 +36,6 @@ class Bad(Screen):
class Layers(App[None]):
-
CSS = """
Screen {
layers: base higher;
diff --git a/tests/snapshot_tests/snapshot_apps/line_api_scrollbars.py b/tests/snapshot_tests/snapshot_apps/line_api_scrollbars.py
index 68a16a099..26ab2c985 100644
--- a/tests/snapshot_tests/snapshot_apps/line_api_scrollbars.py
+++ b/tests/snapshot_tests/snapshot_apps/line_api_scrollbars.py
@@ -1,7 +1,7 @@
from rich.text import Text
from textual.app import App, ComposeResult
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widget import Widget
from textual.widgets import TextLog
@@ -21,32 +21,32 @@ class ScrollViewApp(App):
Screen {
align: center middle;
}
-
+
TextLog {
width:13;
- height:10;
+ height:10;
}
- Vertical{
+ VerticalScroll {
width:13;
height: 10;
overflow: scroll;
overflow-x: auto;
}
+
MyWidget {
width:13;
height:auto;
}
-
"""
def compose(self) -> ComposeResult:
yield TextLog()
- yield Vertical(MyWidget())
+ yield VerticalScroll(MyWidget())
def on_ready(self) -> None:
self.query_one(TextLog).write("\n".join(f"{n} 0123456789" for n in range(20)))
- self.query_one(Vertical).scroll_end(animate=False)
+ self.query_one(VerticalScroll).scroll_end(animate=False)
if __name__ == "__main__":
diff --git a/tests/snapshot_tests/snapshot_apps/nested_auto_heights.py b/tests/snapshot_tests/snapshot_apps/nested_auto_heights.py
index 5df6c2960..4ed40f10e 100644
--- a/tests/snapshot_tests/snapshot_apps/nested_auto_heights.py
+++ b/tests/snapshot_tests/snapshot_apps/nested_auto_heights.py
@@ -3,7 +3,7 @@
from __future__ import annotations
from textual.app import App, ComposeResult
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Static
@@ -42,8 +42,8 @@ class NestedAutoApp(App[None]):
def compose(self) -> ComposeResult:
self._static = Static("", id="my-static")
- yield Vertical(
- Vertical(
+ yield VerticalScroll(
+ VerticalScroll(
self._static,
id="my-static-wrapper",
),
diff --git a/tests/snapshot_tests/snapshot_apps/offsets.py b/tests/snapshot_tests/snapshot_apps/offsets.py
index 12099b126..23d21bb38 100644
--- a/tests/snapshot_tests/snapshot_apps/offsets.py
+++ b/tests/snapshot_tests/snapshot_apps/offsets.py
@@ -1,5 +1,5 @@
from textual.app import App, ComposeResult
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Label, Static
@@ -18,7 +18,6 @@ class Box(Static):
class OffsetsApp(App):
-
CSS = """
#box1 {
diff --git a/tests/snapshot_tests/snapshot_apps/visibility.py b/tests/snapshot_tests/snapshot_apps/visibility.py
index a5ccccb7e..7dbfcf7b4 100644
--- a/tests/snapshot_tests/snapshot_apps/visibility.py
+++ b/tests/snapshot_tests/snapshot_apps/visibility.py
@@ -1,5 +1,5 @@
from textual.app import App
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import Static
@@ -10,7 +10,7 @@ class Visibility(App):
Screen {
layout: horizontal;
}
- Vertical {
+ VerticalScroll {
width: 1fr;
border: solid red;
}
@@ -30,13 +30,12 @@ class Visibility(App):
"""
def compose(self):
-
- yield Vertical(
+ yield VerticalScroll(
Static("foo"),
Static("float", classes="float"),
id="container1",
)
- yield Vertical(
+ yield VerticalScroll(
Static("bar"),
Static("float", classes="float"),
id="container2",
diff --git a/tests/test_disabled.py b/tests/test_disabled.py
index 850fcf7c7..bc0692ad0 100644
--- a/tests/test_disabled.py
+++ b/tests/test_disabled.py
@@ -1,7 +1,7 @@
"""Test Widget.disabled."""
from textual.app import App, ComposeResult
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widgets import (
Button,
DataTable,
@@ -21,7 +21,7 @@ class DisableApp(App[None]):
def compose(self) -> ComposeResult:
"""Compose the child widgets."""
- yield Vertical(
+ yield VerticalScroll(
Button(),
DataTable(),
DirectoryTree("."),
@@ -56,7 +56,7 @@ async def test_enabled_widgets_have_enabled_pseudo_class() -> None:
async def test_all_individually_disabled() -> None:
"""Post-disable all widgets should report being disabled."""
async with DisableApp().run_test() as pilot:
- for node in pilot.app.screen.query("Vertical > *"):
+ for node in pilot.app.screen.query("VerticalScroll > *"):
node.disabled = True
assert all(
node.disabled for node in pilot.app.screen.query("#test-container > *")
@@ -77,7 +77,7 @@ async def test_disabled_widgets_have_disabled_pseudo_class() -> None:
async def test_disable_via_container() -> None:
"""All child widgets should appear (to CSS) as disabled by a container being disabled."""
async with DisableApp().run_test() as pilot:
- pilot.app.screen.query_one("#test-container", Vertical).disabled = True
+ pilot.app.screen.query_one("#test-container", VerticalScroll).disabled = True
assert all(
node.has_pseudo_class("disabled") and not node.has_pseudo_class("enabled")
for node in pilot.app.screen.query("#test-container > *")
diff --git a/tests/test_focus.py b/tests/test_focus.py
index b4d9ce8c5..a03b9b53c 100644
--- a/tests/test_focus.py
+++ b/tests/test_focus.py
@@ -151,11 +151,11 @@ def test_focus_next_and_previous_with_type_selector_without_self():
screen = app.screen
- from textual.containers import Horizontal, Vertical
+ from textual.containers import Horizontal, VerticalScroll
from textual.widgets import Button, Input, Switch
screen._add_children(
- Vertical(
+ VerticalScroll(
Horizontal(
Input(id="w3"),
Switch(id="w4"),
diff --git a/tests/test_overflow_change.py b/tests/test_overflow_change.py
index 236a15f8c..7f5d7eb46 100644
--- a/tests/test_overflow_change.py
+++ b/tests/test_overflow_change.py
@@ -1,19 +1,18 @@
"""Regression test for #1616 https://github.com/Textualize/textual/issues/1616"""
-import pytest
from textual.app import App
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
async def test_overflow_change_updates_virtual_size_appropriately():
class MyApp(App):
def compose(self):
- yield Vertical()
+ yield VerticalScroll()
app = MyApp()
async with app.run_test() as pilot:
- vertical = app.query_one(Vertical)
+ vertical = app.query_one(VerticalScroll)
height = vertical.virtual_size.height
diff --git a/tests/test_visibility_change.py b/tests/test_visibility_change.py
index f79f18a6f..7006827ee 100644
--- a/tests/test_visibility_change.py
+++ b/tests/test_visibility_change.py
@@ -1,7 +1,7 @@
"""See https://github.com/Textualize/textual/issues/1355 as the motivation for these tests."""
from textual.app import App, ComposeResult
-from textual.containers import Vertical
+from textual.containers import VerticalScroll
from textual.widget import Widget
@@ -18,7 +18,7 @@ class VisibleTester(App[None]):
"""
def compose(self) -> ComposeResult:
- yield Vertical(
+ yield VerticalScroll(
Widget(id="keep"), Widget(id="hide-via-code"), Widget(id="hide-via-css")
)
From 4ca62eee6097136b06472a91c83bbe4b3e72f123 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 12:21:53 +0000
Subject: [PATCH 02/16] Update docstring.
---
src/textual/containers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/textual/containers.py b/src/textual/containers.py
index 37e3729e2..0d45e8cda 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -14,7 +14,7 @@ class Container(Widget):
class VerticalScroll(Widget):
- """A container widget which aligns children vertically."""
+ """A container widget which aligns children vertically and overflows if needed."""
DEFAULT_CSS = """
VerticalScroll {
From 90dce06eaef107f0b7b274784da50af2faee7c51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 14:35:49 +0000
Subject: [PATCH 03/16] Add 'HorizontalScroll'.
Related issues: #1957.
---
CHANGELOG.md | 1 +
src/textual/containers.py | 12 ++++++++++++
tests/test_containers.py | 34 ++++++++++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
create mode 100644 tests/test_containers.py
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f665c00e4..b403661c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Breaking change: Added `toggle_button` attribute to RadioButton and Checkbox events, replaces `input` https://github.com/Textualize/textual/pull/1940
- A percentage alpha can now be applied to a border https://github.com/Textualize/textual/issues/1863
- Added `Color.multiply_alpha`.
+- Added `HorizontalScroll` https://github.com/Textualize/textual/issues/1957
### Fixed
diff --git a/src/textual/containers.py b/src/textual/containers.py
index 0d45e8cda..946ab52e1 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -37,6 +37,18 @@ class Horizontal(Widget):
"""
+class HorizontalScroll(Widget):
+ """A container widget which aligns children horizontally and overflows if needed."""
+
+ DEFAULT_CSS = """
+ HorizontalScroll {
+ height: 1fr;
+ layout: horizontal;
+ overflow-x: auto;
+ }
+ """
+
+
class Grid(Widget):
"""A container widget with grid alignment."""
diff --git a/tests/test_containers.py b/tests/test_containers.py
new file mode 100644
index 000000000..d84941082
--- /dev/null
+++ b/tests/test_containers.py
@@ -0,0 +1,34 @@
+"""Test basic functioning of some containers."""
+
+from textual.app import App, ComposeResult
+from textual.containers import Horizontal, HorizontalScroll
+from textual.widgets import Label
+
+
+async def test_horizontal_vs_horizontalscroll_scrolling():
+ """Check the default scrollbar behaviours for Horizontal and HorizontalScroll."""
+
+ class HorizontalsApp(App[None]):
+ CSS = """
+ Screen {
+ layout: vertical;
+ }
+ """
+
+ def compose(self) -> ComposeResult:
+ with Horizontal():
+ for _ in range(10):
+ yield Label("How is life going? " * 3 + " | ")
+ with HorizontalScroll():
+ for _ in range(10):
+ yield Label("How is life going? " * 3 + " | ")
+
+ WIDTH = 80
+ HEIGHT = 24
+ app = HorizontalsApp()
+ async with app.run_test(size=(WIDTH, HEIGHT)):
+ horizontal = app.query_one(Horizontal)
+ horizontal_scroll = app.query_one(HorizontalScroll)
+ assert horizontal.size.height == horizontal_scroll.size.height
+ assert horizontal.scrollbars_enabled == (False, False)
+ assert horizontal_scroll.scrollbars_enabled == (False, True)
From f91750ed3d45c416a6da42ddb4c2f63242c53d6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 15:20:36 +0000
Subject: [PATCH 04/16] Add container 'Center'.
This container will centre children horizontally.
Related issues: #1957.
---
CHANGELOG.md | 1 +
src/textual/containers.py | 12 ++++++++++++
tests/test_containers.py | 19 +++++++++++++++++--
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce0bf2b8a..59e064974 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Added `HorizontalScroll` https://github.com/Textualize/textual/issues/1957
+- Added `Center` https://github.com/Textualize/textual/issues/1957
## [0.14.0] - 2023-03-09
diff --git a/src/textual/containers.py b/src/textual/containers.py
index 946ab52e1..a1836aa85 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -49,6 +49,18 @@ class HorizontalScroll(Widget):
"""
+class Center(Widget):
+ """A container widget which centers children horizontally."""
+
+ DEFAULT_CSS = """
+ Center {
+ align-horizontal: center;
+ width: 100%;
+ height: auto;
+ }
+ """
+
+
class Grid(Widget):
"""A container widget with grid alignment."""
diff --git a/tests/test_containers.py b/tests/test_containers.py
index d84941082..7dde9446e 100644
--- a/tests/test_containers.py
+++ b/tests/test_containers.py
@@ -1,12 +1,12 @@
"""Test basic functioning of some containers."""
from textual.app import App, ComposeResult
-from textual.containers import Horizontal, HorizontalScroll
+from textual.containers import Center, Horizontal, HorizontalScroll
from textual.widgets import Label
async def test_horizontal_vs_horizontalscroll_scrolling():
- """Check the default scrollbar behaviours for Horizontal and HorizontalScroll."""
+ """Check the default scrollbar behaviours for `Horizontal` and `HorizontalScroll`."""
class HorizontalsApp(App[None]):
CSS = """
@@ -32,3 +32,18 @@ async def test_horizontal_vs_horizontalscroll_scrolling():
assert horizontal.size.height == horizontal_scroll.size.height
assert horizontal.scrollbars_enabled == (False, False)
assert horizontal_scroll.scrollbars_enabled == (False, True)
+
+
+async def test_center_container():
+ """Check the size of the container `Center`."""
+
+ class CenterApp(App[None]):
+ def compose(self) -> ComposeResult:
+ with Center():
+ yield Label("<>\n<>\n<>")
+
+ app = CenterApp()
+ async with app.run_test():
+ center = app.query_one(Center)
+ assert center.size.width == app.size.width
+ assert center.size.height == 3
From e111449856da0006d7b53051bad029c959da9201 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 15:24:13 +0000
Subject: [PATCH 05/16] Add container 'Middle'.
Related issues: #1957.
---
CHANGELOG.md | 1 +
src/textual/containers.py | 12 ++++++++++++
tests/test_containers.py | 17 ++++++++++++++++-
3 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 59e064974..2670f3f32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `HorizontalScroll` https://github.com/Textualize/textual/issues/1957
- Added `Center` https://github.com/Textualize/textual/issues/1957
+- Added `Middle` https://github.com/Textualize/textual/issues/1957
## [0.14.0] - 2023-03-09
diff --git a/src/textual/containers.py b/src/textual/containers.py
index a1836aa85..156965ff2 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -61,6 +61,18 @@ class Center(Widget):
"""
+class Middle(Widget):
+ """A container widget which aligns children vertically in the middle."""
+
+ DEFAULT_CSS = """
+ Middle {
+ align-vertical: middle;
+ height: 100%;
+ width: auto;
+ }
+ """
+
+
class Grid(Widget):
"""A container widget with grid alignment."""
diff --git a/tests/test_containers.py b/tests/test_containers.py
index 7dde9446e..866e62800 100644
--- a/tests/test_containers.py
+++ b/tests/test_containers.py
@@ -1,7 +1,7 @@
"""Test basic functioning of some containers."""
from textual.app import App, ComposeResult
-from textual.containers import Center, Horizontal, HorizontalScroll
+from textual.containers import Center, Horizontal, HorizontalScroll, Middle
from textual.widgets import Label
@@ -47,3 +47,18 @@ async def test_center_container():
center = app.query_one(Center)
assert center.size.width == app.size.width
assert center.size.height == 3
+
+
+async def test_middle_container():
+ """Check the size of the container `Middle`."""
+
+ class MiddleApp(App[None]):
+ def compose(self) -> ComposeResult:
+ with Middle():
+ yield Label("1234")
+
+ app = MiddleApp()
+ async with app.run_test():
+ middle = app.query_one(Middle)
+ assert middle.size.width == 4
+ assert middle.size.height == app.size.height
From 58ad5dfdd947de78785fe4ff6868ba2ab0026b76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 15:26:16 +0000
Subject: [PATCH 06/16] Tweak docstrings.
---
src/textual/containers.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/textual/containers.py b/src/textual/containers.py
index 156965ff2..25633d1df 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -14,7 +14,7 @@ class Container(Widget):
class VerticalScroll(Widget):
- """A container widget which aligns children vertically and overflows if needed."""
+ """A container which aligns children vertically and overflows automatically."""
DEFAULT_CSS = """
VerticalScroll {
@@ -26,7 +26,7 @@ class VerticalScroll(Widget):
class Horizontal(Widget):
- """A container widget which aligns children horizontally."""
+ """A container which lays children horizontally."""
DEFAULT_CSS = """
Horizontal {
@@ -38,7 +38,7 @@ class Horizontal(Widget):
class HorizontalScroll(Widget):
- """A container widget which aligns children horizontally and overflows if needed."""
+ """A container which lays children horizontally and overflows automatically."""
DEFAULT_CSS = """
HorizontalScroll {
@@ -50,7 +50,7 @@ class HorizontalScroll(Widget):
class Center(Widget):
- """A container widget which centers children horizontally."""
+ """A container which centers children horizontally."""
DEFAULT_CSS = """
Center {
@@ -62,7 +62,7 @@ class Center(Widget):
class Middle(Widget):
- """A container widget which aligns children vertically in the middle."""
+ """A container which aligns children vertically in the middle."""
DEFAULT_CSS = """
Middle {
@@ -74,7 +74,7 @@ class Middle(Widget):
class Grid(Widget):
- """A container widget with grid alignment."""
+ """A container with grid alignment."""
DEFAULT_CSS = """
Grid {
From 639d8f0250bd76b38113ed0b7c81503a0c577498 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 15:30:44 +0000
Subject: [PATCH 07/16] Change default 'overflow' style for 'Horizontal'.
Related issues: #1957.
---
CHANGELOG.md | 1 +
src/textual/containers.py | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2670f3f32..12cd78bd7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Changed
- Renamed `Vertical` to `VerticalScroll` https://github.com/Textualize/textual/issues/1957
+- Default `overflow` style for `Horizontal` changed to `hidden hidden` https://github.com/Textualize/textual/issues/1957
### Added
diff --git a/src/textual/containers.py b/src/textual/containers.py
index 25633d1df..894912cf4 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -32,7 +32,7 @@ class Horizontal(Widget):
Horizontal {
height: 1fr;
layout: horizontal;
- overflow-x: hidden;
+ overflow: hidden hidden;
}
"""
From 38c7cc1849d4856ca0e6cc7d25b3ccdeaacf0dd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 15:36:38 +0000
Subject: [PATCH 08/16] Fix default CSS for 'VerticalScroll'.
---
src/textual/containers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/textual/containers.py b/src/textual/containers.py
index 894912cf4..59a07fef4 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -18,7 +18,7 @@ class VerticalScroll(Widget):
DEFAULT_CSS = """
VerticalScroll {
- height: 1fr;
+ width: 1fr;
layout: vertical;
overflow-y: auto;
}
From 5674b4b62802043b2e171327ed9e20b414b6af51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 15:38:31 +0000
Subject: [PATCH 09/16] Add 'Vertical'.
Related issues: #1957.
---
CHANGELOG.md | 5 +++--
src/textual/containers.py | 12 ++++++++++++
tests/test_containers.py | 38 +++++++++++++++++++++++++++++++++++++-
3 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 12cd78bd7..a6ece47c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,14 +9,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Changed
-- Renamed `Vertical` to `VerticalScroll` https://github.com/Textualize/textual/issues/1957
-- Default `overflow` style for `Horizontal` changed to `hidden hidden` https://github.com/Textualize/textual/issues/1957
+- Breaking change: changed default behaviour of `Vertical` (see `VerticalScroll`) https://github.com/Textualize/textual/issues/1957
+- The default `overflow` style for `Horizontal` was changed to `hidden hidden` https://github.com/Textualize/textual/issues/1957
### Added
- Added `HorizontalScroll` https://github.com/Textualize/textual/issues/1957
- Added `Center` https://github.com/Textualize/textual/issues/1957
- Added `Middle` https://github.com/Textualize/textual/issues/1957
+- Added `VerticalScroll` (mimicking the old behaviour of `Vertical`) https://github.com/Textualize/textual/issues/1957
## [0.14.0] - 2023-03-09
diff --git a/src/textual/containers.py b/src/textual/containers.py
index 59a07fef4..e94cb19fa 100644
--- a/src/textual/containers.py
+++ b/src/textual/containers.py
@@ -13,6 +13,18 @@ class Container(Widget):
"""
+class Vertical(Widget):
+ """A container which lays children vertically."""
+
+ DEFAULT_CSS = """
+ Vertical {
+ width: 1fr;
+ layout: vertical;
+ overflow: hidden hidden;
+ }
+ """
+
+
class VerticalScroll(Widget):
"""A container which aligns children vertically and overflows automatically."""
diff --git a/tests/test_containers.py b/tests/test_containers.py
index 866e62800..22a4ad0ec 100644
--- a/tests/test_containers.py
+++ b/tests/test_containers.py
@@ -1,7 +1,14 @@
"""Test basic functioning of some containers."""
from textual.app import App, ComposeResult
-from textual.containers import Center, Horizontal, HorizontalScroll, Middle
+from textual.containers import (
+ Center,
+ Horizontal,
+ HorizontalScroll,
+ Middle,
+ Vertical,
+ VerticalScroll,
+)
from textual.widgets import Label
@@ -34,6 +41,35 @@ async def test_horizontal_vs_horizontalscroll_scrolling():
assert horizontal_scroll.scrollbars_enabled == (False, True)
+async def test_vertical_vs_verticalscroll_scrolling():
+ """Check the default scrollbar behaviours for `Vertical` and `VerticalScroll`."""
+
+ class VerticalsApp(App[None]):
+ CSS = """
+ Screen {
+ layout: horizontal;
+ }
+ """
+
+ def compose(self) -> ComposeResult:
+ with Vertical():
+ for _ in range(10):
+ yield Label("How is life going?\n" * 3 + "\n\n")
+ with VerticalScroll():
+ for _ in range(10):
+ yield Label("How is life going?\n" * 3 + "\n\n")
+
+ WIDTH = 80
+ HEIGHT = 24
+ app = VerticalsApp()
+ async with app.run_test(size=(WIDTH, HEIGHT)):
+ vertical = app.query_one(Vertical)
+ vertical_scroll = app.query_one(VerticalScroll)
+ assert vertical.size.width == vertical_scroll.size.width
+ assert vertical.scrollbars_enabled == (False, False)
+ assert vertical_scroll.scrollbars_enabled == (True, False)
+
+
async def test_center_container():
"""Check the size of the container `Center`."""
From c13308a360c59a8682d9bbb1a2afae5f00062b87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?=
<5621605+rodrigogiraoserrao@users.noreply.github.com>
Date: Thu, 9 Mar 2023 17:39:05 +0000
Subject: [PATCH 10/16] Add tests for Horizontal/Vertical(Scroll) containers.
---
.../__snapshots__/test_snapshots.ambr | 166 ++++++++++++++++++
.../snapshot_apps/layout_containers.py | 56 ++++++
tests/snapshot_tests/test_snapshots.py | 13 +-
3 files changed, 232 insertions(+), 3 deletions(-)
create mode 100644 tests/snapshot_tests/snapshot_apps/layout_containers.py
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
index b69597054..4f4413e48 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr
@@ -14805,6 +14805,172 @@
'''
# ---
+# name: test_layout_containers
+ '''
+
+
+ '''
+# ---
# name: test_line_api_scrollbars
'''