aboutsummaryrefslogtreecommitdiff
path: root/app/ui
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-24 05:04:09 -0400
committerhistoria <historiavg@proton.me>2026-08-24 05:04:09 -0400
commit4f3d16e9d532efd6a6bda283925efeb8c93b51c7 (patch)
treebd05c90a6fa47ee17bc521fde5519d19bab6a3d0 /app/ui
parent0512a932bbf3b87619b6a250f87eb7904d22d1f7 (diff)
downloadtts-audiobook-generator-4f3d16e9d532efd6a6bda283925efeb8c93b51c7.tar.gz
feat: q behavior mirrors esc, port settings reordered
Diffstat (limited to 'app/ui')
-rw-r--r--app/ui/hub.py20
-rw-r--r--app/ui/tui.py29
2 files changed, 27 insertions, 22 deletions
diff --git a/app/ui/hub.py b/app/ui/hub.py
index 5f3d039..ef396e5 100644
--- a/app/ui/hub.py
+++ b/app/ui/hub.py
@@ -8,8 +8,8 @@ Each backend's setup wizard runs in its own curses session, so the hub
collects a "command" inside its own wrapper, returns to the plain terminal,
and then dispatches — no nested curses sessions.
-Esc on the main menu quits the hub. Esc inside a sub-menu falls back to the
-main menu.
+Esc on the main menu quits the hub ('q' mirrors Esc on every screen).
+Esc inside a sub-menu falls back to the main menu.
"""
import json
@@ -426,23 +426,23 @@ def _settings_menu(stdscr) -> None:
"value": config.LANGUAGE, "validate": _validate_language},
{"key": "chunk_size", "label": "Chunk size (words)", "kind": "text",
"value": str(config.CHUNK_SIZE), "validate": _validate_chunk_size},
- {"key": "qwen_custom_port", "label": "qwen-tts CustomVoice port",
+ {"key": "audiocpp_port", "label": "audio.cpp port",
"kind": "text",
- "value": str(_port_from_url(config.QWEN_API_URL, 7860)),
+ "value": str(_port_from_url(config.AUDIOCPP_API_URL, 8080)),
"validate": _validate_port,
"note": "Ports apply to servers this tool starts and detecting "
"local servers"},
- {"key": "qwen_clone_port", "label": "qwen-tts Base port",
- "kind": "text",
- "value": str(_port_from_url(config.CLONE_API_URL, 7861)),
- "validate": _validate_port},
{"key": "faster_port", "label": "faster-qwen3-tts port",
"kind": "text",
"value": str(_port_from_url(config.FASTER_API_URL, 8000)),
"validate": _validate_port},
- {"key": "audiocpp_port", "label": "audio.cpp port",
+ {"key": "qwen_custom_port", "label": "qwen-tts CustomVoice port",
"kind": "text",
- "value": str(_port_from_url(config.AUDIOCPP_API_URL, 8080)),
+ "value": str(_port_from_url(config.QWEN_API_URL, 7860)),
+ "validate": _validate_port},
+ {"key": "qwen_clone_port", "label": "qwen-tts Base port",
+ "kind": "text",
+ "value": str(_port_from_url(config.CLONE_API_URL, 7861)),
"validate": _validate_port},
]
result = tui.form(stdscr, "Settings", fields, back_value=_GO_BACK)
diff --git a/app/ui/tui.py b/app/ui/tui.py
index bf17f7d..6d768dd 100644
--- a/app/ui/tui.py
+++ b/app/ui/tui.py
@@ -24,9 +24,10 @@ Common key bindings:
instead, so the caller can fall back a screen
(confirm() historically names this cancel_value)
-On screens without typed text (menus, confirm, tree, browser) 'q' also
-aborts — even when a back_value is set, so Esc means "back" while 'q'
-still means "quit". Inside text editors 'q' is an ordinary character.
+On screens without typed text (menus, confirm, tree, browser) 'q'
+behaves exactly like Esc: it goes back when a back/cancel value is set,
+otherwise it aborts the wizard. Inside text editors 'q' is an ordinary
+character.
When the terminal has no color support the theme degrades to
bold/reverse/dim.
"""
@@ -93,7 +94,8 @@ def flash(scr, text: str, kind: str = "warn") -> None:
raise WizardCancelled()
-# Esc and 'q' both abort on screens without typed text ('q' is an
+# On screens without typed text, Esc and 'q' mean the same thing: go
+# back when a back/cancel value is set, abort otherwise ('q' is an
# ordinary character inside text editors).
_CANCEL_KEYS = (27, ord("q"))
@@ -637,7 +639,8 @@ def menu(scr, title: str, options: Sequence[tuple], default_index: int = 0,
status table.
Esc (or 'q') aborts the wizard unless BACK_VALUE is given (not None),
- in which case Esc returns it so the caller can fall back a screen.
+ in which case either key returns it so the caller can fall back a
+ screen.
"""
if not options:
raise ValueError("menu() needs at least one option")
@@ -676,7 +679,7 @@ def menu(scr, title: str, options: Sequence[tuple], default_index: int = 0,
frame.cursor = base + cursor
frame.draw()
key = frame.get_key(cancel_keys=())
- if key == 27 and back_value is not None:
+ if key in _CANCEL_KEYS and back_value is not None:
return back_value
if key in _CANCEL_KEYS:
raise WizardCancelled()
@@ -720,6 +723,7 @@ def line_edit(scr, title: str, default: str,
frame.draw()
curses = frame.curses
key = frame.get_key(cancel_keys=()) # handle Esc manually below
+ # 'q' is an ordinary character in a text editor; only Esc cancels.
if key == 27 and back_value is not None:
return back_value
if key == 27:
@@ -807,7 +811,7 @@ def form(scr, title: str, fields: Sequence[dict],
frame.draw()
curses = frame.curses
key = frame.get_key(cancel_keys=())
- if key == 27 and back_value is not None:
+ if key in _CANCEL_KEYS and back_value is not None:
return back_value
if key in _CANCEL_KEYS:
raise WizardCancelled()
@@ -921,8 +925,8 @@ def browse_directory(scr, title: str,
lets a subdirectory that already looks like the target (e.g. an
'audio.cpp' checkout containing 'model_specs/') be picked in one
keystroke. Esc (or 'q') aborts the wizard unless BACK_VALUE is given
- (not None), in which case Esc returns it so the caller can fall back
- a screen.
+ (not None), in which case either key returns it so the caller can
+ fall back a screen.
"""
footer = ("Up/Down = move Enter = open/use Left = parent "
"e = type path Esc = cancel")
@@ -993,7 +997,7 @@ def browse_directory(scr, title: str,
frame.draw()
curses = frame.curses
key = frame.get_key(cancel_keys=())
- if key == 27 and back_value is not None:
+ if key in _CANCEL_KEYS and back_value is not None:
return back_value
if key in _CANCEL_KEYS:
raise WizardCancelled()
@@ -1072,7 +1076,8 @@ def checkbox_tree(scr, title: str, families: List[dict],
family has more than one option — a single option needs no tag.
Family and option rows are left-justified like a DOS list. Esc (or
'q') aborts the wizard unless BACK_VALUE is given (not None), in
- which case Esc returns it so the caller can fall back a screen.
+ which case either key returns it so the caller can fall back a
+ screen.
"""
if not families:
raise ValueError("checkbox_tree() needs at least one family")
@@ -1141,7 +1146,7 @@ def checkbox_tree(scr, title: str, families: List[dict],
frame.draw()
curses = frame.curses
key = frame.get_key(cancel_keys=())
- if key == 27 and back_value is not None:
+ if key in _CANCEL_KEYS and back_value is not None:
return back_value
if key in _CANCEL_KEYS:
raise WizardCancelled()