From 142ca7485c0c7098e50aad8a289b0bf9adc4696c Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 22 Aug 2024 13:29:50 +0100 Subject: [PATCH 1/2] Remove classic footer --- CHANGELOG.md | 1 + docs/examples/widgets/classic_footer.py | 25 --- docs/widget_gallery.md | 14 -- docs/widgets/classic_footer.md | 64 ------- docs/widgets/footer.md | 3 - mkdocs-nav.yml | 1 - src/textual/widgets/__init__.py | 2 - src/textual/widgets/_classic_footer.py | 161 ------------------ src/textual/widgets/_footer.py | 2 - .../snapshot_apps/auto_width_input.py | 2 +- .../snapshot_apps/footer_classic_styling.py | 5 - 11 files changed, 2 insertions(+), 278 deletions(-) delete mode 100644 docs/examples/widgets/classic_footer.py delete mode 100644 docs/widgets/classic_footer.md delete mode 100644 src/textual/widgets/_classic_footer.py diff --git a/CHANGELOG.md b/CHANGELOG.md index ebdd65ff34..78474b3e42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Keys such as escape and space are now displayed in lower case in footer https://github.com/Textualize/textual/pull/4876 - Changed default command palette binding to `ctrl+p` https://github.com/Textualize/textual/pull/4867 - Removed `ctrl_to_caret` and `upper_case_keys` from Footer. These can be implemented in `App.get_key_display`. +- Breaking change: Removed ClassicFooter (please use Footer widget) ### Fixed diff --git a/docs/examples/widgets/classic_footer.py b/docs/examples/widgets/classic_footer.py deleted file mode 100644 index 104b4fc93e..0000000000 --- a/docs/examples/widgets/classic_footer.py +++ /dev/null @@ -1,25 +0,0 @@ -from textual.app import App, ComposeResult -from textual.binding import Binding -from textual.widgets import ClassicFooter - - -class FooterApp(App): - BINDINGS = [ - Binding(key="q", action="quit", description="Quit the app"), - Binding( - key="question_mark", - action="help", - description="Show help screen", - key_display="?", - ), - Binding(key="delete", action="delete", description="Delete the thing"), - Binding(key="j", action="down", description="Scroll down", show=False), - ] - - def compose(self) -> ComposeResult: - yield ClassicFooter() - - -if __name__ == "__main__": - app = FooterApp() - app.run() diff --git a/docs/widget_gallery.md b/docs/widget_gallery.md index 1d5ef708cb..0ff0cf5a70 100644 --- a/docs/widget_gallery.md +++ b/docs/widget_gallery.md @@ -34,20 +34,6 @@ A classic checkbox control. ```{.textual path="docs/examples/widgets/checkbox.py"} ``` -## ClassicFooter - -The original Footer widget. - -!!! warning - - This has been replaced by [`Footer`](#footer), and will be removed in Textual v1.0 - -[ClassicFooter reference](./widgets/classic_footer.md){ .md-button .md-button--primary } - -```{.textual path="docs/examples/widgets/classic_footer.py" columns="70" lines="12"} -``` - - ## Collapsible diff --git a/docs/widgets/classic_footer.md b/docs/widgets/classic_footer.md deleted file mode 100644 index 0917ded739..0000000000 --- a/docs/widgets/classic_footer.md +++ /dev/null @@ -1,64 +0,0 @@ -# ClassicFooter - -!!! warning "Deprecated widget" - - This is an older version of the Textual Footer, and will be replaced with [Footer](./footer.md) in Textual v1.0 - - -A simple footer widget which is docked to the bottom of its parent container. Displays -available keybindings for the currently focused widget. - -- [ ] Focusable -- [ ] Container - -## Example - -The example below shows an app with a single keybinding that contains only a `ClassicFooter` -widget. Notice how the `ClassicFooter` automatically displays the keybinding. - -=== "Output" - - ```{.textual path="docs/examples/widgets/classic_footer.py"} - ``` - -=== "footer.py" - - ```python - --8<-- "docs/examples/widgets/classic_footer.py" - ``` - -## Reactive Attributes - -| Name | Type | Default | Description | -| --------------- | ----- | ------- | --------------------------------------------------------------------------------------------------------- | -| `highlight_key` | `str` | `None` | Stores the currently highlighted key. This is typically the key the cursor is hovered over in the footer. | - -## Messages - -This widget posts no messages. - -## Bindings - -This widget has no bindings. - -## Component Classes - -The footer widget provides the following component classes: - -::: textual.widgets.ClassicFooter.COMPONENT_CLASSES - options: - show_root_heading: false - show_root_toc_entry: false - -## Additional Notes - -* You can prevent keybindings from appearing in the footer by setting the `show` argument of the `Binding` to `False`. -* You can customize the text that appears for the key itself in the footer using the `key_display` argument of `Binding`. - - ---- - - -::: textual.widgets.ClassicFooter - options: - heading_level: 2 diff --git a/docs/widgets/footer.md b/docs/widgets/footer.md index 3d9b0b47de..2435b6eb34 100644 --- a/docs/widgets/footer.md +++ b/docs/widgets/footer.md @@ -2,9 +2,6 @@ !!! tip "Added in version 0.63.0" - This is a second iteration of the Footer. - The version prior to 0.63.0 is available as [ClassicFooter](./classic_footer.md) to help with backwards compatibility, but will be removed in v1.0. - A simple footer widget which is docked to the bottom of its parent container. Displays available keybindings for the currently focused widget. diff --git a/mkdocs-nav.yml b/mkdocs-nav.yml index f52cb4df78..514c5ca346 100644 --- a/mkdocs-nav.yml +++ b/mkdocs-nav.yml @@ -141,7 +141,6 @@ nav: - Widgets: - "widgets/button.md" - "widgets/checkbox.md" - - "widgets/classic_footer.md" - "widgets/collapsible.md" - "widgets/content_switcher.md" - "widgets/data_table.md" diff --git a/src/textual/widgets/__init__.py b/src/textual/widgets/__init__.py index 8361aad00c..0329e3c269 100644 --- a/src/textual/widgets/__init__.py +++ b/src/textual/widgets/__init__.py @@ -12,7 +12,6 @@ from ..widget import Widget from ._button import Button from ._checkbox import Checkbox - from ._classic_footer import ClassicFooter from ._collapsible import Collapsible from ._content_switcher import ContentSwitcher from ._data_table import DataTable @@ -52,7 +51,6 @@ __all__ = [ "Button", "Checkbox", - "ClassicFooter", "Collapsible", "ContentSwitcher", "DataTable", diff --git a/src/textual/widgets/_classic_footer.py b/src/textual/widgets/_classic_footer.py deleted file mode 100644 index 5b1b5cffae..0000000000 --- a/src/textual/widgets/_classic_footer.py +++ /dev/null @@ -1,161 +0,0 @@ -from __future__ import annotations - -from collections import defaultdict -from typing import TYPE_CHECKING, ClassVar, Optional - -import rich.repr -from rich.text import Text - -from .. import events -from ..binding import Binding -from ..reactive import reactive -from ..widget import Widget - -if TYPE_CHECKING: - from ..app import RenderResult - from ..screen import Screen - - -@rich.repr.auto -class ClassicFooter(Widget): - """A simple footer widget which docks itself to the bottom of the parent container.""" - - COMPONENT_CLASSES: ClassVar[set[str]] = { - "footer--description", - "footer--key", - "footer--highlight", - "footer--highlight-key", - } - """ - | Class | Description | - | :- | :- | - | `classic-footer--description` | Targets the descriptions of the key bindings. | - | `classic-footer--highlight` | Targets the highlighted key binding. | - | `classic-footer--highlight-key` | Targets the key portion of the highlighted key binding. | - | `classic-footer--key` | Targets the key portions of the key bindings. | - """ - - __name__ = "Footer" - - DEFAULT_CSS = """ - ClassicFooter { - background: $accent; - color: $text; - dock: bottom; - height: 1; - } - ClassicFooter > .footer--highlight { - background: $accent-darken-1; - } - - ClassicFooter > .footer--highlight-key { - background: $secondary; - text-style: bold; - } - - ClassicFooter > .footer--key { - text-style: bold; - background: $accent-darken-2; - } - """ - - highlight_key: reactive[str | None] = reactive[Optional[str]](None) - - def __init__(self) -> None: - super().__init__() - self._key_text: Text | None = None - self.auto_links = False - - async def watch_highlight_key(self) -> None: - """If highlight key changes we need to regenerate the text.""" - self._key_text = None - self.refresh() - - def _on_mount(self, _: events.Mount) -> None: - self.screen.bindings_updated_signal.subscribe(self, self._bindings_changed) - self.log.warning( - "ClassicFooter is deprecated and will be removed in Textual 1.0" - ) - - def _bindings_changed(self, _screen: Screen) -> None: - self._key_text = None - self.refresh() - - def _on_mouse_move(self, event: events.MouseMove) -> None: - """Store any key we are moving over.""" - self.highlight_key = event.style.meta.get("key") - - def _on_leave(self, _: events.Leave) -> None: - """Clear any highlight when the mouse leaves the widget""" - self.highlight_key = None - - def __rich_repr__(self) -> rich.repr.Result: - yield from super().__rich_repr__() - - def _make_key_text(self) -> Text: - """Create text containing all the keys.""" - base_style = self.rich_style - text = Text( - style=self.rich_style, - no_wrap=True, - overflow="ellipsis", - justify="left", - end="", - ) - highlight_style = self.get_component_rich_style("footer--highlight") - highlight_key_style = self.get_component_rich_style("footer--highlight-key") - key_style = self.get_component_rich_style("footer--key") - description_style = self.get_component_rich_style("footer--description") - - bindings = [ - (binding, enabled, tooltip) - for (_, binding, enabled, tooltip) in self.screen.active_bindings.values() - if binding.show - ] - - action_to_bindings: defaultdict[str, list[tuple[Binding, bool]]] = defaultdict( - list - ) - for binding, enabled, _ in bindings: - action_to_bindings[binding.action].append((binding, enabled)) - - app_focus = self.app.app_focus - for _, _bindings in action_to_bindings.items(): - binding, enabled = _bindings[0] - if binding.key_display is None: - key_display = self.app.get_key_display(binding.key) - if key_display is None: - key_display = binding.key.upper() - else: - key_display = binding.key_display - hovered = self.highlight_key == binding.key - key_text = Text.assemble( - (f" {key_display} ", highlight_key_style if hovered else key_style), - ( - f" {binding.description} ", - highlight_style if hovered else base_style + description_style, - ), - meta=( - { - "@click": f"app.simulate_key('{binding.key}')", - "key": binding.key, - } - if enabled and app_focus - else {} - ), - ) - if not enabled or not app_focus: - key_text.stylize("dim") - text.append_text(key_text) - return text - - def notify_style_update(self) -> None: - self._key_text = None - - def post_render(self, renderable): - return renderable - - def render(self) -> RenderResult: - if self._key_text is None: - self._key_text = self._make_key_text() - return self._key_text diff --git a/src/textual/widgets/_footer.py b/src/textual/widgets/_footer.py index a6eedcb3b6..0d51f9f76e 100644 --- a/src/textual/widgets/_footer.py +++ b/src/textual/widgets/_footer.py @@ -176,8 +176,6 @@ def __init__( id: The ID of the widget in the DOM. classes: The CSS classes for the widget. disabled: Whether the widget is disabled or not. - upper_case_keys: Show the keys in upper case. - ctrl_to_caret: Show `ctrl+` as `^`. show_command_palette: Show key binding to command palette, on the right of the footer. """ super().__init__( diff --git a/tests/snapshot_tests/snapshot_apps/auto_width_input.py b/tests/snapshot_tests/snapshot_apps/auto_width_input.py index ab6457b5ad..9c6199eadc 100644 --- a/tests/snapshot_tests/snapshot_apps/auto_width_input.py +++ b/tests/snapshot_tests/snapshot_apps/auto_width_input.py @@ -1,5 +1,5 @@ from textual.app import App, ComposeResult -from textual.widgets import Header, Footer, Input, ClassicFooter +from textual.widgets import Header, Footer, Input class InputWidthAutoApp(App[None]): diff --git a/tests/snapshot_tests/snapshot_apps/footer_classic_styling.py b/tests/snapshot_tests/snapshot_apps/footer_classic_styling.py index 7f43027d49..1e4386572a 100644 --- a/tests/snapshot_tests/snapshot_apps/footer_classic_styling.py +++ b/tests/snapshot_tests/snapshot_apps/footer_classic_styling.py @@ -39,11 +39,6 @@ class ClassicFooterStylingApp(App): def compose(self) -> ComposeResult: yield Footer() - def on_mount(self) -> None: - footer = self.query_one(Footer) - footer.upper_case_keys = True - footer.ctrl_to_caret = False - if __name__ == "__main__": app = ClassicFooterStylingApp() From 8f3788628a449ff7c6e82afb628f2d179f2e42e7 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Thu, 22 Aug 2024 13:31:39 +0100 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78474b3e42..d51fca7671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Keys such as escape and space are now displayed in lower case in footer https://github.com/Textualize/textual/pull/4876 - Changed default command palette binding to `ctrl+p` https://github.com/Textualize/textual/pull/4867 - Removed `ctrl_to_caret` and `upper_case_keys` from Footer. These can be implemented in `App.get_key_display`. -- Breaking change: Removed ClassicFooter (please use Footer widget) +- Breaking change: Removed ClassicFooter (please use new Footer widget) https://github.com/Textualize/textual/pull/4921 ### Fixed