aboutsummaryrefslogtreecommitdiff
path: root/app/ui/tui.py
diff options
context:
space:
mode:
Diffstat (limited to 'app/ui/tui.py')
-rw-r--r--app/ui/tui.py43
1 files changed, 30 insertions, 13 deletions
diff --git a/app/ui/tui.py b/app/ui/tui.py
index e2118eb..56aa79e 100644
--- a/app/ui/tui.py
+++ b/app/ui/tui.py
@@ -909,6 +909,10 @@ def form(scr, title: str, fields: Sequence[dict],
keep their value across hide/show. A field may set ``on_change`` to
a callable of the field list, invoked whenever its value changes so
dependent fields (choices, visibility, defaults) can be recomputed.
+ A choice field whose resolved list is empty cannot be opened: Enter
+ is a no-op, or flashes the field's optional ``on_empty_choices``
+ message (string or callable of the field list) — an explanation the
+ submit-time ``validate`` can echo when an empty pick must be refused.
An optional ``note`` string on a field renders as a dim,
non-selectable line in a blank-line frame above that field's row — a
@@ -1064,20 +1068,33 @@ def form(scr, title: str, fields: Sequence[dict],
if callable(choices):
choices = choices(fields)
choices = list(choices)
- if choices and isinstance(choices[0], (tuple, list)) \
- and len(choices[0]) == 2:
- pairs = [(label, value) for label, value in choices]
+ if not choices:
+ # A dynamic choice list can legitimately come
+ # back empty (e.g. an audio.cpp model whose
+ # server hosts no clone voices). menu() would
+ # raise; explain instead when the field says
+ # how to fill the list.
+ message = field.get("on_empty_choices")
+ if callable(message):
+ message = message(fields)
+ if message:
+ frame.flash(str(message), "err")
else:
- pairs = [(c, c) for c in choices]
- values = [value for _, value in pairs]
- default = values.index(field["value"]) \
- if field["value"] in values else 0
- chosen = menu(scr, field["label"], pairs,
- default_index=default,
- back_value=edit_cancel)
- if chosen is not edit_cancel:
- field["value"] = chosen
- run_on_change(field)
+ if isinstance(choices[0], (tuple, list)) \
+ and len(choices[0]) == 2:
+ pairs = [(label, value)
+ for label, value in choices]
+ else:
+ pairs = [(c, c) for c in choices]
+ values = [value for _, value in pairs]
+ default = values.index(field["value"]) \
+ if field["value"] in values else 0
+ chosen = menu(scr, field["label"], pairs,
+ default_index=default,
+ back_value=edit_cancel)
+ if chosen is not edit_cancel:
+ field["value"] = chosen
+ run_on_change(field)
elif field.get("kind") == "dir":
start = field["value"]
start = Path(start) if start else Path.cwd()