From 9c55adb88e235f2b1e965ac6ed46618cd6dc3607 Mon Sep 17 00:00:00 2001 From: jpt Date: Thu, 10 Apr 2025 20:30:31 -0500 Subject: [PATCH] mostly working modal --- src/tt/tui/editor.py | 21 ++++++++++++----- src/tt/tui/modals.py | 54 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 src/tt/tui/modals.py diff --git a/src/tt/tui/editor.py b/src/tt/tui/editor.py index cf4cba6..90cd8e8 100644 --- a/src/tt/tui/editor.py +++ b/src/tt/tui/editor.py @@ -14,6 +14,7 @@ from ..utils import ( get_text_from_editor, ) from .keymodal import KeyModal +from .modals import ChoiceModal #DateModal ELLIPSIS = "…" @@ -31,9 +32,11 @@ def _enum_preprocessor(enumCls): return val except ValueError: raise NotifyValidationError( - f"Invalid value. Use: {[s.value for s in enumCls]}" + f"Invalid value {val}. Use: {[s.value for s in enumCls]}" ) + return preprocessor + class TableColumnConfig: def __init__( @@ -333,15 +336,21 @@ class TableEditor(App): if cconf.read_only: return + # save cursor before callback, so correct position updates self._save_cursor() current_value = self.table.get_cell_at( (self.table.cursor_row, self.table.cursor_column) ) - if current_value.endswith(ELLIPSIS): - self.notify("multi-line text, use (e)dit") - return - current_value = remove_rich_tag(current_value) - self._show_input("edit", current_value) + + if cconf.enum: + self.push_screen(ChoiceModal(cconf.enum, current_value), + self.apply_change) + elif current_value.endswith(ELLIPSIS): + self.action_start_edit() + else: + # default edit mode + current_value = remove_rich_tag(current_value) + self._show_input("edit", current_value) def action_start_edit(self): cconf = self._active_column_config() diff --git a/src/tt/tui/modals.py b/src/tt/tui/modals.py new file mode 100644 index 0000000..d212165 --- /dev/null +++ b/src/tt/tui/modals.py @@ -0,0 +1,54 @@ +from textual.screen import ModalScreen +from textual.containers import Grid +from textual.binding import Binding + +from textual.widgets import RadioSet, RadioButton, Label + +class ChoiceModal(ModalScreen): + + CSS = """ + ChoiceModal { + align: center middle; + background: $primary 30%; + } + ChoiceModal Label { + height: 1; + } + """ + + BINDINGS = [ + ("j", "cursor_down", "Down"), + ("k", "cursor_up", "Up"), + # TODO: get this to work as override + Binding("enter", "select", "Select", priority=True), + ("c", "select", "Select"), + ("escape", "cancel", "cancel") + ] + + def __init__(self, enum, selected): + self._enum = enum + self.selected = selected + super().__init__() + + def compose(self): + yield Label(f"{self._enum.__name__}") + yield RadioSet( + *[ + RadioButton(str(e.value), value=self.selected==str(e.value)) for e in self._enum + ] + ) + + def action_cursor_down(self): + self.query_one(RadioSet).action_next_button() + + def action_cursor_up(self): + self.query_one(RadioSet).action_previous_button() + + def action_select(self): + rs = self.query_one(RadioSet) + rs.action_toggle_button() + pressed = rs.pressed_button + self.dismiss(str(pressed.label)) + + def action_cancel(self): + self.app.pop_screen()