Files
gniza4linux/tui/widgets/folder_picker.py
shuki 587149f062 Add Python Textual TUI replacing gum-based bash TUI
New tui/ package with 14 screens (main menu, backup, restore, targets,
remotes, snapshots, verify, retention, schedule, logs, settings, wizard),
3 custom widgets (folder picker, confirm dialog, operation log), async
backend wrapper, pure-Python config parser, and TCSS theme.

bin/gniza now launches Textual TUI when available, falls back to gum.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 23:39:48 +02:00

43 lines
1.4 KiB
Python

from textual.app import ComposeResult
from textual.screen import ModalScreen
from textual.widgets import DirectoryTree, Header, Footer, Static, Button
from textual.containers import Horizontal, Vertical
from pathlib import Path
class _DirOnly(DirectoryTree):
def filter_paths(self, paths):
return [p for p in paths if p.is_dir()]
class FolderPicker(ModalScreen[str | None]):
BINDINGS = [("escape", "cancel", "Cancel")]
def __init__(self, title: str = "Select folder", start: str = "/"):
super().__init__()
self._title = title
self._start = start
def compose(self) -> ComposeResult:
with Vertical(id="folder-picker"):
yield Static(self._title, id="fp-title")
yield _DirOnly(self._start, id="fp-tree")
with Horizontal(id="fp-buttons"):
yield Button("Select", variant="primary", id="fp-select")
yield Button("Cancel", variant="default", id="fp-cancel")
def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "fp-select":
tree = self.query_one("#fp-tree", DirectoryTree)
node = tree.cursor_node
if node and node.data and node.data.path:
self.dismiss(str(node.data.path))
else:
self.dismiss(None)
else:
self.dismiss(None)
def action_cancel(self) -> None:
self.dismiss(None)