mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Allow scrollbar size of zero (scrollable containers without scrollbars) (#3488)
* Remove the guard code which protects against `scrollbar-size-*:0`, update error messages indicating its supported now. * Fix scrollbar region calculation to support zero-thickness scrollbars * Add test ensuring zero-width scrollbars dont blow up * Updating CHANGELOG regarding zero-thickness scrollbars * Add note to scrollbar_size.md about zero width scrollbar
This commit is contained in:
@@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Added `Input.clear` method https://github.com/Textualize/textual/pull/3430
|
||||
- Added `TextArea.SelectionChanged` and `TextArea.Changed` messages https://github.com/Textualize/textual/pull/3442
|
||||
- Added `wait_for_dismiss` parameter to `App.push_screen` https://github.com/Textualize/textual/pull/3477
|
||||
- Allow scrollbar-size to be set to 0 to achieve scrollable containers with no visible scrollbars https://github.com/Textualize/textual/pull/3488
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@ In this example we modify the size of the widget's scrollbar to be _much_ larger
|
||||
|
||||
In the next example we show three containers with differently sized scrollbars.
|
||||
|
||||
!!! tip
|
||||
|
||||
If you want to hide the scrollbar but still allow the container to scroll
|
||||
using the mousewheel or keyboard, you can set the scrollbar size to `0`.
|
||||
|
||||
=== "Output"
|
||||
|
||||
```{.textual path="docs/examples/styles/scrollbar_size2.py"}
|
||||
|
||||
@@ -587,9 +587,7 @@ def scrollbar_size_property_help_text(context: StylingContext) -> HelpText:
|
||||
),
|
||||
],
|
||||
).get_by_context(context),
|
||||
Bullet(
|
||||
"<horizontal> and <vertical> must be positive integers, greater than zero"
|
||||
),
|
||||
Bullet("<horizontal> and <vertical> must be non-negative integers."),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -876,11 +876,7 @@ class StylesBuilder:
|
||||
scrollbar_size_error(name, token2)
|
||||
|
||||
horizontal = int(token1.value)
|
||||
if horizontal == 0:
|
||||
scrollbar_size_error(name, token1)
|
||||
vertical = int(token2.value)
|
||||
if vertical == 0:
|
||||
scrollbar_size_error(name, token2)
|
||||
self.styles._rules["scrollbar_size_horizontal"] = horizontal
|
||||
self.styles._rules["scrollbar_size_vertical"] = vertical
|
||||
self._distribute_importance("scrollbar_size", ("horizontal", "vertical"))
|
||||
@@ -895,8 +891,6 @@ class StylesBuilder:
|
||||
if token.name != "number" or not token.value.isdigit():
|
||||
self.error(name, token, scrollbar_size_single_axis_help_text(name))
|
||||
value = int(token.value)
|
||||
if value == 0:
|
||||
self.error(name, token, scrollbar_size_single_axis_help_text(name))
|
||||
self.styles._rules["scrollbar_size_vertical"] = value
|
||||
|
||||
def process_scrollbar_size_horizontal(self, name: str, tokens: list[Token]) -> None:
|
||||
@@ -909,8 +903,6 @@ class StylesBuilder:
|
||||
if token.name != "number" or not token.value.isdigit():
|
||||
self.error(name, token, scrollbar_size_single_axis_help_text(name))
|
||||
value = int(token.value)
|
||||
if value == 0:
|
||||
self.error(name, token, scrollbar_size_single_axis_help_text(name))
|
||||
self.styles._rules["scrollbar_size_horizontal"] = value
|
||||
|
||||
def _process_grid_rows_or_columns(self, name: str, tokens: list[Token]) -> None:
|
||||
|
||||
@@ -1220,7 +1220,7 @@ class Widget(DOMNode):
|
||||
|
||||
@property
|
||||
def horizontal_scrollbar(self) -> ScrollBar:
|
||||
"""The a horizontal scrollbar.
|
||||
"""The horizontal scrollbar.
|
||||
|
||||
Note:
|
||||
This will *create* a scrollbar if one doesn't exist.
|
||||
@@ -2701,8 +2701,8 @@ class Widget(DOMNode):
|
||||
horizontal_scrollbar_region,
|
||||
scrollbar_corner_gap,
|
||||
) = region.split(
|
||||
-scrollbar_size_vertical,
|
||||
-scrollbar_size_horizontal,
|
||||
region.width - scrollbar_size_vertical,
|
||||
region.height - scrollbar_size_horizontal,
|
||||
)
|
||||
if scrollbar_corner_gap:
|
||||
yield self.scrollbar_corner, scrollbar_corner_gap
|
||||
@@ -2719,7 +2719,7 @@ class Widget(DOMNode):
|
||||
|
||||
elif show_vertical_scrollbar:
|
||||
window_region, scrollbar_region = region.split_vertical(
|
||||
-scrollbar_size_vertical
|
||||
region.width - scrollbar_size_vertical
|
||||
)
|
||||
if scrollbar_region:
|
||||
scrollbar = self.vertical_scrollbar
|
||||
@@ -2728,7 +2728,7 @@ class Widget(DOMNode):
|
||||
yield scrollbar, scrollbar_region
|
||||
elif show_horizontal_scrollbar:
|
||||
window_region, scrollbar_region = region.split_horizontal(
|
||||
-scrollbar_size_horizontal
|
||||
region.height - scrollbar_size_horizontal
|
||||
)
|
||||
if scrollbar_region:
|
||||
scrollbar = self.horizontal_scrollbar
|
||||
|
||||
@@ -98,3 +98,24 @@ async def test_middle_container():
|
||||
middle = app.query_one(Middle)
|
||||
assert middle.size.width == 4
|
||||
assert middle.size.height == app.size.height
|
||||
|
||||
|
||||
async def test_scrollbar_zero_thickness():
|
||||
"""Ensuring that scrollbars can be set to zero thickness."""
|
||||
|
||||
class ScrollbarZero(App):
|
||||
CSS = """* {
|
||||
scrollbar-size: 0 0;
|
||||
scrollbar-size-vertical: 0; /* just exercising the parser */
|
||||
scrollbar-size-horizontal: 0; /* exercise the parser */
|
||||
}
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Vertical():
|
||||
for _ in range(10):
|
||||
yield Label("Hello, world!")
|
||||
|
||||
app = ScrollbarZero()
|
||||
async with app.run_test(size=(8, 6)):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user