Skip to content

Commit 12c553d

Browse files
committed
shutdown scrollbas
1 parent 2afb00f commit 12c553d

File tree

7 files changed

+91
-6
lines changed

7 files changed

+91
-6
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [0.2.2] - Unreleased
99

10+
### Fixed
11+
12+
- Fixed issue where scrollbars weren't being unmounted
13+
1014
### Changed
1115

1216
- DOMQuery now raises InvalidQueryFormat in response to invalid query strings, rather than cryptic CSS error
@@ -19,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1923
- Added App.run_async method
2024
- Added App.run_test context manager
2125
- Added auto_pilot to App.run and App.run_async
26+
- Added Widget._get_virtual_dom to get scrollbars
2227

2328
## [0.2.1] - 2022-10-23
2429

sandbox/will/scroll_remove.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from textual.app import App, ComposeResult
2+
3+
from textual.containers import Container
4+
5+
6+
class ScrollApp(App):
7+
8+
def compose(self) -> ComposeResult:
9+
yield Container(
10+
Container(), Container(),
11+
id="top")
12+
13+
def key_r(self) -> None:
14+
self.query_one("#top").remove()
15+
16+
if __name__ == "__main__":
17+
app = ScrollApp()
18+
app.run()

src/textual/app.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,9 +1605,6 @@ async def _on_remove(self, event: events.Remove) -> None:
16051605

16061606
await self._prune_node(widget)
16071607

1608-
# for child in remove_widgets:
1609-
# await child._close_messages()
1610-
# self._unregister(child)
16111608
if parent is not None:
16121609
parent.refresh(layout=True)
16131610

@@ -1625,7 +1622,7 @@ def _walk_children(self, root: Widget) -> Iterable[list[Widget]]:
16251622
while stack:
16261623
widget = pop()
16271624
if widget.children:
1628-
yield list(widget.children)
1625+
yield [*widget.children, *widget._get_virtual_dom()]
16291626
for child in widget.children:
16301627
push(child)
16311628

src/textual/cli/cli.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import click
55
from importlib_metadata import version
66

7+
from textual.pilot import Pilot
78
from textual._import_app import import_app, AppFail
89

910

@@ -84,7 +85,12 @@ def run_app(import_name: str, dev: bool, press: str) -> None:
8485
sys.exit(1)
8586

8687
press_keys = press.split(",") if press else None
87-
result = app.run(press=press_keys)
88+
89+
async def run_press_keys(pilot: Pilot) -> None:
90+
if press_keys is not None:
91+
await pilot.press(*press_keys)
92+
93+
result = app.run(auto_pilot=run_press_keys)
8894

8995
if result is not None:
9096
from rich.console import Console

src/textual/widget.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,20 @@ def _clear_arrangement_cache(self) -> None:
359359
"""Clear arrangement cache, forcing a new arrange operation."""
360360
self._arrangement = None
361361

362+
def _get_virtual_dom(self) -> Iterable[Widget]:
363+
"""Get widgets not part of the DOM.
364+
365+
Returns:
366+
Iterable[Widget]: An iterable of Widgets.
367+
368+
"""
369+
if self._horizontal_scrollbar is not None:
370+
yield self._horizontal_scrollbar
371+
if self._vertical_scrollbar is not None:
372+
yield self._vertical_scrollbar
373+
if self._scrollbar_corner is not None:
374+
yield self._scrollbar_corner
375+
362376
def mount(self, *anon_widgets: Widget, **widgets: Widget) -> AwaitMount:
363377
"""Mount child widgets (making this widget a container).
364378
@@ -587,6 +601,7 @@ def horizontal_scrollbar(self) -> ScrollBar:
587601
Returns:
588602
ScrollBar: ScrollBar Widget.
589603
"""
604+
590605
from .scrollbar import ScrollBar
591606

592607
if self._horizontal_scrollbar is not None:
@@ -600,7 +615,7 @@ def horizontal_scrollbar(self) -> ScrollBar:
600615

601616
def _refresh_scrollbars(self) -> None:
602617
"""Refresh scrollbar visibility."""
603-
if not self.is_scrollable:
618+
if not self.is_scrollable or not self.container_size:
604619
return
605620

606621
styles = self.styles

tests/test_auto_pilot.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from textual.app import App
2+
from textual.pilot import Pilot
3+
from textual import events
4+
5+
6+
def test_auto_pilot() -> None:
7+
8+
keys_pressed: list[str] = []
9+
10+
class TestApp(App):
11+
def on_key(self, event: events.Key) -> None:
12+
keys_pressed.append(event.key)
13+
14+
async def auto_pilot(pilot: Pilot) -> None:
15+
16+
await pilot.press("tab", *"foo")
17+
await pilot.pause(1 / 100)
18+
await pilot.exit("bar")
19+
20+
app = TestApp()
21+
result = app.run(headless=True, auto_pilot=auto_pilot)
22+
assert result == "bar"
23+
assert keys_pressed == ["tab", "f", "o", "o"]

tests/test_test_runner.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from textual.app import App
2+
from textual import events
3+
4+
5+
async def test_run_test() -> None:
6+
"""Test the run_test context manager."""
7+
keys_pressed: list[str] = []
8+
9+
class TestApp(App[str]):
10+
def on_key(self, event: events.Key) -> None:
11+
keys_pressed.append(event.key)
12+
13+
app = TestApp()
14+
async with app.run_test() as pilot:
15+
assert str(pilot) == "<Pilot app=TestApp(title='TestApp')>"
16+
await pilot.press("tab", *"foo")
17+
await pilot.pause(1 / 100)
18+
await pilot.exit("bar")
19+
20+
assert app.return_value == "bar"
21+
assert keys_pressed == ["tab", "f", "o", "o"]

0 commit comments

Comments
 (0)