diff options
| author | historia <historiavg@proton.me> | 2026-08-26 19:58:45 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-26 19:58:45 -0400 |
| commit | 975bd960fd07e75799b8e3adc4c0033046b34792 (patch) | |
| tree | 6d5a13c0ad6eb3a6afeb5659bd9e9e21e8c215bc /app/ui/tui.py | |
| parent | 5af37bbd575eec89c6ac2fecf2d8c2eda4c1728d (diff) | |
| download | tts-audiobook-generator-975bd960fd07e75799b8e3adc4c0033046b34792.tar.gz | |
feat: language and option fields in tui, context-sensitive voice label
Diffstat (limited to 'app/ui/tui.py')
| -rw-r--r-- | app/ui/tui.py | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/app/ui/tui.py b/app/ui/tui.py index 56aa79e..f1c5419 100644 --- a/app/ui/tui.py +++ b/app/ui/tui.py @@ -891,7 +891,11 @@ def form(scr, title: str, fields: Sequence[dict], "kind": "dir", "value": Path("./voices")} Fields render as a two-column table: each label is padded to the - widest label so every value starts in the same column. KINDS: + widest label so every value starts in the same column. A field's + ``label`` may be a callable of the field list (like ``visible`` and + ``choices``); it is re-resolved on every redraw, so a label can track + other fields' values, and sub-dialogs (choice menu, line editor, + directory browser) are titled with the resolved label. KINDS: ``choice`` opens a single choice menu (its ``choices`` may be a callable of the field list, resolved when the menu opens); ``text`` opens a line editor (reusing its VALIDATE); ``bool`` shows Yes/No and @@ -942,7 +946,11 @@ def form(scr, title: str, fields: Sequence[dict], on_buttons = start_on_buttons btn_index = 0 edit_cancel = object() # sentinel: backed out of a field editor - label_w = max(len(field["label"]) for field in fields) + + def field_label(field: dict) -> str: + """Resolve FIELD's label (a string, or a callable of FIELDS).""" + label = field["label"] + return str(label(fields)) if callable(label) else str(label) def shown_fields() -> List[dict]: result: List[dict] = [] @@ -992,13 +1000,17 @@ def form(scr, title: str, fields: Sequence[dict], if help_lines: frame.mark("") field_rows: List[int] = [] # visible field index -> row index + # Labels can be callables, so the pad width is recomputed from the + # visible fields on every redraw (a dynamic label's length may vary). + label_w = max((len(field_label(field)) for field in shown), + default=0) for field in shown: if field.get("note"): frame.mark("") frame.mark(field["note"], frame.theme["dim"], align="left") frame.mark("") field_rows.append(len(frame.rows)) - name = f"{field['label']}:".ljust(label_w + 1) + name = f"{field_label(field)}:".ljust(label_w + 1) frame.mark_segments( [(name, frame.theme["body"]), (" " + display_value(field), frame.theme["input"])], @@ -1089,7 +1101,7 @@ def form(scr, title: str, fields: Sequence[dict], values = [value for _, value in pairs] default = values.index(field["value"]) \ if field["value"] in values else 0 - chosen = menu(scr, field["label"], pairs, + chosen = menu(scr, field_label(field), pairs, default_index=default, back_value=edit_cancel) if chosen is not edit_cancel: @@ -1099,7 +1111,7 @@ def form(scr, title: str, fields: Sequence[dict], start = field["value"] start = Path(start) if start else Path.cwd() picked = browse_directory( - scr, field["label"], start=start, + scr, field_label(field), start=start, validate=field.get("validate"), back_value=edit_cancel) if picked is not edit_cancel: @@ -1111,7 +1123,7 @@ def form(scr, title: str, fields: Sequence[dict], on_buttons = True btn_index = 0 else: - edited = line_edit(scr, field["label"], + edited = line_edit(scr, field_label(field), field["value"], validate=field.get("validate"), back_value=edit_cancel) |
