-
Notifications
You must be signed in to change notification settings - Fork 814
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
Fix content width #1910
Fix content width #1910
Changes from 24 commits
29bc5de
3a92cec
440bcbf
4b21a22
7eea84e
62e3f2e
44241bf
3cc2988
10c388b
6a0e665
4038ed5
6563a39
8a3d785
61cc7b0
61e5335
2b9db6f
9ba94e5
174b229
3fc6313
81dc5de
cddda7d
33ebc0f
a6a0d81
4d9ec32
dde7564
bceffa5
8bfad7f
74be89e
695c4a7
fd148f3
a5fac4a
955181b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ ColorButtons { | |
} | ||
|
||
ColorButtons > Button { | ||
width: 30; | ||
width: 100%; | ||
} | ||
|
||
ColorsView { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ | |
""" | ||
|
||
|
||
import os | ||
|
||
from typing_extensions import Final | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,6 +102,7 @@ Column { | |
height: auto; | ||
min-height: 100vh; | ||
align: center top; | ||
overflow: hidden; | ||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -515,6 +515,8 @@ def _arrange(self, size: Size) -> DockArrangeResult: | |
def _clear_arrangement_cache(self) -> None: | ||
"""Clear arrangement cache, forcing a new arrange operation.""" | ||
self._arrangement_cache.clear() | ||
self._stabilized_scrollbar_size = None | ||
self._scrollbar_stabilizer = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding docstrings to these two attributes. |
||
|
||
def _get_virtual_dom(self) -> Iterable[Widget]: | ||
"""Get widgets not part of the DOM. | ||
|
@@ -848,14 +850,11 @@ def get_content_height(self, container: Size, viewport: Size, width: int) -> int | |
""" | ||
if self.is_container: | ||
assert self._layout is not None | ||
height = ( | ||
self._layout.get_content_height( | ||
self, | ||
container, | ||
viewport, | ||
width, | ||
) | ||
+ self.scrollbar_size_horizontal | ||
height = self._layout.get_content_height( | ||
self, | ||
container, | ||
viewport, | ||
width, | ||
) | ||
else: | ||
cache_key = width | ||
|
@@ -978,34 +977,36 @@ def _refresh_scrollbars(self) -> None: | |
styles = self.styles | ||
overflow_x = styles.overflow_x | ||
overflow_y = styles.overflow_y | ||
width, height = self.container_size | ||
width, height = self._container_size | ||
|
||
show_horizontal = self.show_horizontal_scrollbar | ||
show_horizontal = False | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you help me understand why the default behaviour is to turn off There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous value shouldn't come in to consideration. It should make the same calculation, no matter the current state of the scrollbars. |
||
if overflow_x == "hidden": | ||
show_horizontal = False | ||
elif overflow_x == "scroll": | ||
show_horizontal = True | ||
elif overflow_x == "auto": | ||
show_horizontal = self.virtual_size.width > width | ||
|
||
show_vertical = self.show_vertical_scrollbar | ||
show_vertical = False | ||
if overflow_y == "hidden": | ||
show_vertical = False | ||
elif overflow_y == "scroll": | ||
show_vertical = True | ||
elif overflow_y == "auto": | ||
show_vertical = self.virtual_size.height > height | ||
|
||
if ( | ||
overflow_x == "auto" | ||
and show_vertical | ||
and not show_horizontal | ||
and self._stabilized_scrollbar_size != self.container_size | ||
): | ||
show_horizontal = ( | ||
self.virtual_size.width + styles.scrollbar_size_vertical > width | ||
) | ||
self._stabilized_scrollbar_size = self.container_size | ||
if self._stabilized_scrollbar_size != self.container_size: | ||
# When a single scrollbar is shown, the other dimension changes, so we need to recalculate. | ||
if show_vertical and not show_horizontal: | ||
show_horizontal = self.virtual_size.width > ( | ||
width - styles.scrollbar_size_vertical | ||
) | ||
if show_horizontal and not show_vertical: | ||
show_vertical = self.virtual_size.height > ( | ||
height - styles.scrollbar_size_horizontal | ||
) | ||
|
||
self._stabilized_scrollbar_size = self._container_size | ||
|
||
self.show_horizontal_scrollbar = show_horizontal | ||
self.show_vertical_scrollbar = show_vertical | ||
|
@@ -2098,7 +2099,7 @@ def _arrange_scrollbars(self, region: Region) -> Iterable[tuple[Widget, Region]] | |
|
||
if show_horizontal_scrollbar and show_vertical_scrollbar: | ||
( | ||
_, | ||
window_region, | ||
vertical_scrollbar_region, | ||
horizontal_scrollbar_region, | ||
scrollbar_corner_gap, | ||
|
@@ -2109,18 +2110,34 @@ def _arrange_scrollbars(self, region: Region) -> Iterable[tuple[Widget, Region]] | |
if scrollbar_corner_gap: | ||
yield self.scrollbar_corner, scrollbar_corner_gap | ||
if vertical_scrollbar_region: | ||
yield self.vertical_scrollbar, vertical_scrollbar_region | ||
scrollbar = self.vertical_scrollbar | ||
scrollbar.window_virtual_size = self.virtual_size.height | ||
scrollbar.window_size = window_region.height | ||
yield scrollbar, vertical_scrollbar_region | ||
if horizontal_scrollbar_region: | ||
yield self.horizontal_scrollbar, horizontal_scrollbar_region | ||
scrollbar = self.horizontal_scrollbar | ||
scrollbar.window_virtual_size = self.virtual_size.width | ||
scrollbar.window_size = window_region.width | ||
yield scrollbar, horizontal_scrollbar_region | ||
|
||
elif show_vertical_scrollbar: | ||
_, scrollbar_region = region.split_vertical(-scrollbar_size_vertical) | ||
window_region, scrollbar_region = region.split_vertical( | ||
-scrollbar_size_vertical | ||
) | ||
if scrollbar_region: | ||
yield self.vertical_scrollbar, scrollbar_region | ||
scrollbar = self.vertical_scrollbar | ||
scrollbar.window_virtual_size = self.virtual_size.height | ||
scrollbar.window_size = window_region.height | ||
yield scrollbar, scrollbar_region | ||
elif show_horizontal_scrollbar: | ||
_, scrollbar_region = region.split_horizontal(-scrollbar_size_horizontal) | ||
window_region, scrollbar_region = region.split_horizontal( | ||
-scrollbar_size_horizontal | ||
) | ||
if scrollbar_region: | ||
yield self.horizontal_scrollbar, scrollbar_region | ||
scrollbar = self.horizontal_scrollbar | ||
scrollbar.window_virtual_size = self.virtual_size.width | ||
scrollbar.window_size = window_region.width | ||
yield scrollbar, scrollbar_region | ||
|
||
def get_pseudo_classes(self) -> Iterable[str]: | ||
"""Pseudo classes for a widget. | ||
|
@@ -2239,9 +2256,13 @@ def _scroll_update(self, virtual_size: Size) -> None: | |
self.vertical_scrollbar.window_size = ( | ||
height - self.scrollbar_size_horizontal | ||
) | ||
if self.vertical_scrollbar._repaint_required: | ||
self.call_next(self.vertical_scrollbar.refresh) | ||
if self.show_horizontal_scrollbar: | ||
self.horizontal_scrollbar.window_virtual_size = virtual_size.width | ||
self.horizontal_scrollbar.window_size = width - self.scrollbar_size_vertical | ||
if self.horizontal_scrollbar._repaint_required: | ||
self.call_next(self.horizontal_scrollbar.refresh) | ||
|
||
self.scroll_x = self.validate_scroll_x(self.scroll_x) | ||
self.scroll_y = self.validate_scroll_y(self.scroll_y) | ||
|
@@ -2363,6 +2384,7 @@ def refresh( | |
""" | ||
if layout and not self._layout_required: | ||
self._layout_required = True | ||
self._stabilized_scrollbar_size = None | ||
for ancestor in self.ancestors: | ||
if not isinstance(ancestor, Widget): | ||
break | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
from rich.text import Text | ||
|
||
from textual.app import App, ComposeResult | ||
from textual.containers import Vertical | ||
from textual.widget import Widget | ||
from textual.widgets import TextLog | ||
|
||
|
||
class MyWidget(Widget): | ||
def render(self): | ||
return Text( | ||
"\n".join(f"{n} 0123456789" for n in range(20)), | ||
no_wrap=True, | ||
overflow="hidden", | ||
justify="left", | ||
) | ||
|
||
|
||
class ScrollViewApp(App): | ||
CSS = """ | ||
Screen { | ||
align: center middle; | ||
} | ||
|
||
TextLog { | ||
width:13; | ||
height:10; | ||
} | ||
|
||
Vertical{ | ||
width:13; | ||
height: 10; | ||
overflow: scroll; | ||
overflow-x: auto; | ||
} | ||
MyWidget { | ||
width:13; | ||
height:auto; | ||
} | ||
|
||
""" | ||
|
||
def compose(self) -> ComposeResult: | ||
yield TextLog() | ||
yield Vertical(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) | ||
|
||
|
||
if __name__ == "__main__": | ||
app = ScrollViewApp() | ||
app.run() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -256,3 +256,7 @@ def test_disabled_widgets(snap_compare): | |
|
||
def test_focus_component_class(snap_compare): | ||
assert snap_compare(SNAPSHOT_APPS_DIR / "focus_component_class.py", press=["tab"]) | ||
|
||
|
||
def test_line_api_scrollbars(snap_compare): | ||
assert snap_compare(SNAPSHOT_APPS_DIR / "test_line_api_scrollbars.py", press=["_"]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The app examples in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.