From b13514e478a634c964735dc2d7744ce9e3209043 Mon Sep 17 00:00:00 2001 From: shuki Date: Thu, 5 Mar 2026 23:49:06 +0200 Subject: [PATCH] Replace main menu buttons with OptionList for arrow key navigation OptionList supports up/down arrow keys and Enter to select, giving a proper menu feel instead of Tab-through buttons. Co-Authored-By: Claude Opus 4.6 --- tui/gniza.tcss | 6 ++--- tui/screens/main_menu.py | 56 ++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/tui/gniza.tcss b/tui/gniza.tcss index d911e93..67caa04 100644 --- a/tui/gniza.tcss +++ b/tui/gniza.tcss @@ -19,10 +19,10 @@ Screen { overflow-y: auto; } -#main-menu Button { +#menu-list { width: 100%; - height: 3; - margin: 0; + height: auto; + max-height: 100%; } #logo { diff --git a/tui/screens/main_menu.py b/tui/screens/main_menu.py index b19cdd6..eb21869 100644 --- a/tui/screens/main_menu.py +++ b/tui/screens/main_menu.py @@ -1,6 +1,7 @@ from textual.app import ComposeResult from textual.screen import Screen -from textual.widgets import Header, Footer, Static, Button +from textual.widgets import Header, Footer, Static, OptionList +from textual.widgets.option_list import Option from textual.containers import Vertical, Center LOGO = """\ @@ -13,6 +14,20 @@ LOGO = """\ gniza - Linux Backup Manager """ +MENU_ITEMS = [ + ("backup", "Backup"), + ("restore", "Restore"), + ("targets", "Targets"), + ("remotes", "Remotes"), + ("snapshots", "Snapshots"), + ("verify", "Verify"), + ("retention", "Retention"), + ("schedule", "Schedules"), + ("logs", "Logs"), + ("settings", "Settings"), + ("quit", "Quit"), +] + class MainMenuScreen(Screen): @@ -23,36 +38,21 @@ class MainMenuScreen(Screen): with Center(): with Vertical(id="main-menu"): yield Static(LOGO, id="logo", markup=True) - yield Button("Backup", id="menu-backup", variant="primary") - yield Button("Restore", id="menu-restore") - yield Button("Targets", id="menu-targets") - yield Button("Remotes", id="menu-remotes") - yield Button("Snapshots", id="menu-snapshots") - yield Button("Verify", id="menu-verify") - yield Button("Retention", id="menu-retention") - yield Button("Schedules", id="menu-schedule") - yield Button("Logs", id="menu-logs") - yield Button("Settings", id="menu-settings") - yield Button("Quit", id="menu-quit", variant="error") + yield OptionList( + *[Option(label, id=mid) for mid, label in MENU_ITEMS], + id="menu-list", + ) yield Footer() - def on_button_pressed(self, event: Button.Pressed) -> None: - button_map = { - "menu-backup": "backup", - "menu-restore": "restore", - "menu-targets": "targets", - "menu-remotes": "remotes", - "menu-snapshots": "snapshots", - "menu-verify": "verify", - "menu-retention": "retention", - "menu-schedule": "schedule", - "menu-logs": "logs", - "menu-settings": "settings", - } - if event.button.id == "menu-quit": + def on_mount(self) -> None: + self.query_one("#menu-list", OptionList).focus() + + def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None: + option_id = event.option.id + if option_id == "quit": self.app.exit() - elif event.button.id in button_map: - self.app.push_screen(button_map[event.button.id]) + elif option_id: + self.app.push_screen(option_id) def action_quit_app(self) -> None: self.app.exit()