from textual.app import ComposeResult from textual.screen import ModalScreen from textual.containers import Container, ScrollableContainer from textual.widgets import Static, Button, Label from typing import List, Callable class SelectionModal(ModalScreen[str]): """A modal for selecting a type from a list of strings.""" CSS = """ SelectionModal { align: center middle; background: rgba(0, 0, 0, 0.5); } #selection-container { width: 40%; height: 60%; background: $panel; border: thick $primary; padding: 1; } .selection-title { background: $accent; color: $text; padding: 0 1; margin-bottom: 1; text-align: center; text-style: bold; height: 3; content-align: center middle; } .selection-button { width: 100%; margin-bottom: 1; } #selection-cancel { width: 100%; margin-top: 1; background: $error; } """ def __init__(self, title: str, options: List[str]) -> None: super().__init__() self.selection_title = title self.options = sorted(options) def compose(self) -> ComposeResult: with Container(id="selection-container"): yield Static(self.selection_title, classes="selection-title") with ScrollableContainer(): for opt in self.options: yield Button(opt, id=f"opt-{opt}", classes="selection-button") yield Button("Cancel", id="selection-cancel") def on_button_pressed(self, event: Button.Pressed) -> None: if event.button.id == "selection-cancel": self.dismiss("") elif event.button.id and event.button.id.startswith("opt-"): selection = event.button.id.replace("opt-", "") self.dismiss(selection)