Tabbed content activated message (#2260)

* Add a message for the tabbed content activated

* Add a docstring

* Testing tabbed content activated message

* Update changelog

* Add reference to the docs about TabbedContent.TabActivated
This commit is contained in:
darrenburns
2023-04-12 10:55:14 +01:00
committed by GitHub
parent 6352ceb61b
commit f95e30870b
5 changed files with 63 additions and 4 deletions

View File

@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `DataTable.remove_row` method https://github.com/Textualize/textual/pull/2253 - Added `DataTable.remove_row` method https://github.com/Textualize/textual/pull/2253
- `Widget.scroll_to_center` now scrolls the widget to the center of the screen https://github.com/Textualize/textual/pull/2255 - `Widget.scroll_to_center` now scrolls the widget to the center of the screen https://github.com/Textualize/textual/pull/2255
- Added `TabActivated` message to `TabbedContent` https://github.com/Textualize/textual/pull/2260
## [0.19.1] - 2023-04-10 ## [0.19.1] - 2023-04-10

View File

@@ -101,6 +101,10 @@ The following example contains a `TabbedContent` with three tabs.
| `active` | `str` | `""` | The `id` attribute of the active tab. Set this to switch tabs. | | `active` | `str` | `""` | The `id` attribute of the active tab. Set this to switch tabs. |
## Messages
- [TabbedContent.TabActivated][textual.widgets.TabbedContent.TabActivated]
## See also ## See also

View File

@@ -61,7 +61,7 @@ The following example adds a `Tabs` widget above a text label. Press ++a++ to ad
## Messages ## Messages
- [Tabs.TabActivate][textual.widgets.Tabs.TabActivated] - [Tabs.TabActivated][textual.widgets.Tabs.TabActivated]
- [Tabs.Cleared][textual.widgets.Tabs.Cleared] - [Tabs.Cleared][textual.widgets.Tabs.Cleared]
## Bindings ## Bindings

View File

@@ -2,9 +2,11 @@ from __future__ import annotations
from itertools import zip_longest from itertools import zip_longest
from rich.repr import Result
from rich.text import Text, TextType from rich.text import Text, TextType
from ..app import ComposeResult from ..app import ComposeResult
from ..message import Message
from ..reactive import reactive from ..reactive import reactive
from ..widget import Widget from ..widget import Widget
from ._content_switcher import ContentSwitcher from ._content_switcher import ContentSwitcher
@@ -84,6 +86,24 @@ class TabbedContent(Widget):
active: reactive[str] = reactive("", init=False) active: reactive[str] = reactive("", init=False)
"""The ID of the active tab, or empty string if none are active.""" """The ID of the active tab, or empty string if none are active."""
class TabActivated(Message):
"""Posted when the active tab changes."""
def __init__(self, tabbed_content: TabbedContent, tab: Tab) -> None:
"""Initialize message.
Args:
tabbed_content: The TabbedContent widget.
tab: The Tab widget that was selected (contains the tab label).
"""
self.tabbed_content = tabbed_content
self.tab = tab
super().__init__()
def __rich_repr__(self) -> Result:
yield self.tabbed_content
yield self.tab
def __init__(self, *titles: TextType, initial: str = "") -> None: def __init__(self, *titles: TextType, initial: str = "") -> None:
"""Initialize a TabbedContent widgets. """Initialize a TabbedContent widgets.
@@ -167,6 +187,12 @@ class TabbedContent(Widget):
assert isinstance(event.tab, ContentTab) assert isinstance(event.tab, ContentTab)
switcher.current = event.tab.id switcher.current = event.tab.id
self.active = event.tab.id self.active = event.tab.id
self.post_message(
TabbedContent.TabActivated(
tabbed_content=self,
tab=event.tab,
)
)
def _on_tabs_cleared(self, event: Tabs.Cleared) -> None: def _on_tabs_cleared(self, event: Tabs.Cleared) -> None:
"""All tabs were removed.""" """All tabs were removed."""

View File

@@ -14,7 +14,7 @@ async def test_tabbed_content_switch():
yield Label("Foo", id="foo-label") yield Label("Foo", id="foo-label")
with TabPane("bar", id="bar"): with TabPane("bar", id="bar"):
yield Label("Bar", id="bar-label") yield Label("Bar", id="bar-label")
with TabPane("baz`", id="baz"): with TabPane("baz", id="baz"):
yield Label("Baz", id="baz-label") yield Label("Baz", id="baz-label")
app = TabbedApp() app = TabbedApp()
@@ -73,11 +73,11 @@ async def test_tabbed_content_initial():
yield Label("Foo", id="foo-label") yield Label("Foo", id="foo-label")
with TabPane("bar", id="bar"): with TabPane("bar", id="bar"):
yield Label("Bar", id="bar-label") yield Label("Bar", id="bar-label")
with TabPane("baz`", id="baz"): with TabPane("baz", id="baz"):
yield Label("Baz", id="baz-label") yield Label("Baz", id="baz-label")
app = TabbedApp() app = TabbedApp()
async with app.run_test() as pilot: async with app.run_test():
tabbed_content = app.query_one(TabbedContent) tabbed_content = app.query_one(TabbedContent)
assert tabbed_content.active == "bar" assert tabbed_content.active == "bar"
@@ -85,3 +85,31 @@ async def test_tabbed_content_initial():
assert not app.query_one("#foo-label").region assert not app.query_one("#foo-label").region
assert app.query_one("#bar-label").region assert app.query_one("#bar-label").region
assert not app.query_one("#baz-label").region assert not app.query_one("#baz-label").region
async def test_tabbed_content_messages():
class TabbedApp(App):
message = None
def compose(self) -> ComposeResult:
with TabbedContent(initial="bar"):
with TabPane("foo", id="foo"):
yield Label("Foo", id="foo-label")
with TabPane("bar", id="bar"):
yield Label("Bar", id="bar-label")
with TabPane("baz", id="baz"):
yield Label("Baz", id="baz-label")
def on_tabbed_content_tab_activated(
self, event: TabbedContent.TabActivated
) -> None:
self.message = event
app = TabbedApp()
async with app.run_test() as pilot:
tabbed_content = app.query_one(TabbedContent)
tabbed_content.active = "bar"
await pilot.pause()
assert isinstance(app.message, TabbedContent.TabActivated)
assert app.message.tab.label.plain == "bar"