I'm trying to create an enditor where the Footer contains the usual bindings on the left and some status information on the right, for example the line number. The Footer in textual is very simple so I thought to extend it, but I'm unable to see both my label and the binding of the base Footer. This is my code:
class MyFooter(Footer):
DEFAULT_CSS = """
MyFooter {
.right-label {
text-align: right;
}
}
"""
def compose(self) -> ComposeResult:
for widget in super().compose():
yield widget
yield Label("This is the right side label", id="right-label")
To test it, you can use the first example of the tutorial:
from textual.app import App, ComposeResult
from textual.widgets import Header, Footer,Label
class MyFooter(Footer):
DEFAULT_CSS = """
MyFooter {
.right-label {
text-align: right;
}
}
"""
def compose(self) -> ComposeResult:
"""Create child widgets for the footer."""
for widget in super().compose():
yield widget
yield Label("This is the right side label", id="right-label")
class StopwatchApp(App):
"""A Textual app to manage stopwatches."""
BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]
def compose(self) -> ComposeResult:
"""Create child widgets for the app."""
yield Header()
yield MyFooter()
def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
self.dark = not self.dark
if __name__ == "__main__":
app = StopwatchApp()
app.run()
I'd recommend solving this by laying out multiple widgets, instead of overriding the Footer class.
The Footer widget uses dock: bottom; layout: grid; grid-columns: auto
, which makes this a little tricky. But you can wrap the Footer in a fixed-sized container, and lay out your label next to that.
from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, Label
from textual.containers import Horizontal
class StopwatchApp(App):
"""A Textual app to manage stopwatches."""
BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]
CSS = """
Horizontal#footer-outer {
height: 1;
dock: bottom;
}
Horizonal#footer-inner {
width: 75%;
}
Label#right-label {
width: 25%;
text-align: right;
}
"""
def compose(self) -> ComposeResult:
"""Create child widgets for the app."""
yield Header()
with Horizontal(id="footer-outer"):
with Horizontal(id="footer-inner"):
yield Footer()
yield Label("This is the right side label", id="right-label")
def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
self.dark = not self.dark
if __name__ == "__main__":
app = StopwatchApp()
app.run()