Skip to content
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

Input-related FooterKeys sorted differently since Textual 1.0.0 #5412

Open
xavierog opened this issue Dec 19, 2024 · 4 comments
Open

Input-related FooterKeys sorted differently since Textual 1.0.0 #5412

xavierog opened this issue Dec 19, 2024 · 4 comments

Comments

@xavierog
Copy link
Contributor

xavierog commented Dec 19, 2024

This issue affects Textual 1.0.0. It feels close to #4639.

MRE

from textual.app import App
from textual.binding import Binding
from textual.widget import Widget
from textual.widgets import Footer, Input

class Wid(Widget, can_focus=True):
    BINDINGS = [
        ('escape', 'escape', 'Widget Escape'),
        ('up', 'up', 'Widget Up'),
        ('down', 'down', 'Widget Down'),
    ]
    DEFAULT_CSS = "Wid { max-height: 5; }"

class Inp(Input):
    BINDINGS = [
        ('escape', 'escape', 'Input Escape'),
        ('up', 'up', 'Input Up'),
        ('down', 'down', 'Input Down'),
    ]

class MRE(App):
    def compose(self):
        yield Wid()
        yield Inp()
        yield Footer()

if __name__ == '__main__':
    app = MRE()
    app.run()

Expected behaviour

Textual 0.89.1 behaves as expected: focusing either the Wid Widget or the Inp Input leads to the following FooterKeys:

 esc Input Escape  ↑ Input Up  ↓ Input Down
 esc Widget Escape  ↑ Widget Up  ↓ Widget Down

Encountered behaviour

Textual 1.0.0 moves the escape FooterKey. This happens only to the Inp Input, not to the Wid Widget:

 ↑ Input Up  ↓ Input Down  esc Input Escape
 esc Widget Escape  ↑ Widget Up  ↓ Widget Down
Copy link

We found the following entry in the FAQ which you may find helpful:

Feel free to close this issue if you found an answer in the FAQ. Otherwise, please give us a little time to review.

This is an automated reply, generated by FAQtory

@TomJGooding
Copy link
Contributor

I suspect this is because esc is also used to minimize a maximized widget. Presumably this existing 'binding' is further down the chain, so overriding this will cause it to appear last in the footer?

@TomJGooding
Copy link
Contributor

It looks like this was introduced in e1bf6ff, where Input now inherits from ScrollView rather than Widget.

The multilevel inheritance seems to matter, for reasons I don't yet understand!

For example, where a widget simply inherits from Widget, the esc binding will be the first in the footer:

from textual.app import App, ComposeResult
from textual.widget import Widget
from textual.widgets import Footer


class MyWidget(Widget, can_focus=True):
    BINDINGS = [
        ("escape", "escape", "Escape"),
        ("ctrl+a", "screen.maximize", "Maximize"),
    ]

    DEFAULT_CSS = """
    MyWidget {
        width: auto;
        height: auto;
    }
    """


class ExampleApp(App):
    def compose(self) -> ComposeResult:
        yield MyWidget()
        yield Footer()


if __name__ == "__main__":
    app = ExampleApp()
    app.run()

Whereas a widget with multilevel inheritance and a binding for esc binding will display this last in the footer:

from textual.app import App, ComposeResult
from textual.widget import Widget
from textual.widgets import Footer


class MyWidget(Widget, can_focus=True):
    BINDINGS = [
        ("ctrl+a", "screen.maximize", "Maximize"),
    ]

    DEFAULT_CSS = """
    MyWidget {
        width: auto;
        height: auto;
    }
    """


class SubWidget(MyWidget):
    BINDINGS = [
        ("escape", "escape", "Escape"),
    ]


class ExampleApp(App):
    def compose(self) -> ComposeResult:
        yield SubWidget()
        yield Footer()


if __name__ == "__main__":
    app = ExampleApp()
    app.run()

@xavierog
Copy link
Contributor Author

xavierog commented Dec 19, 2024

Possibly a consequence of DOMNode._merge_bindings relying on cls.__mro__?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants