From 2ca284619125af0d5c12e9210ff1bfc8f9122739 Mon Sep 17 00:00:00 2001 From: Anders Betts Date: Wed, 23 Sep 2026 08:56:49 +0200 Subject: tui: one shared field editor, in-place form editing, value-only focus Forms edit fields in place in the value column instead of a bottom prompt, highlight only the focused value and scroll when taller than the screen; long text scrolls horizontally instead of wrapping. Fixes: typing after Backspace/Del no longer wipes the field, 'q' is text in row tables, the caret resets between cells, dialogs decode arrow keys, full buffers never take half a UTF-8 character, an invalid amount stays editable. Co-Authored-By: Claude Opus 5.5 --- docs/TUI-GUIDELINES.md | 56 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 14 deletions(-) (limited to 'docs/TUI-GUIDELINES.md') diff --git a/docs/TUI-GUIDELINES.md b/docs/TUI-GUIDELINES.md index 1c201aa..c791f25 100644 --- a/docs/TUI-GUIDELINES.md +++ b/docs/TUI-GUIDELINES.md @@ -136,7 +136,7 @@ there. |---|---| | `Ctrl+N` | Add: new verifikat (dashboard, voucher list/detail), new mall (Mallar), new fiscal year (year picker), open editor (IB), upload file (Underlag) | | `F5` | Refresh the view | -| `Esc` / `q` | Back one level. At the dashboard it does nothing — Esc never exits the app | +| `Esc` / `q` | Back one level. At the dashboard it does nothing — Esc never exits the app. In a row table (`tui_rt_run`) and while a field is being edited `q` is text; only `Esc` goes back there | | `Ctrl+C` | Quit the application (closes the session). The only key that exits | | `Ctrl+R` | Reload the client in place: re-execs the installed binary and restores session, org, fiscal year and the current view (for after a rebuild) | | `Ctrl+A` | Close or reopen the highlighted räkenskapsår (Räkenskapsår screen; asks for confirmation) | @@ -193,14 +193,32 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width. chosen action, an edited field) the row is written back, so a re-run after a save or a round-trip through another screen lands on the same row. `NULL` starts at the first focusable row and stores nothing. -- The active field is drawn reverse-video and holds the hardware cursor at the - caret. The caret is a real position: ←/→/Home/End/Del work inside the field, - `Ctrl+U` clears it (see `field_edit`). +- Focus marks the **value, not the row**: the focused field's label is + accent/bold and only its value is reverse video, in a box at least 24 + columns wide so an empty field is visible. Action rows (`Spara`, …) are + buttons and highlight their whole label. +- Fields are **edited in place**, in the value column (never in a prompt at + the bottom): `Enter` opens the editor on the focused field, which widens + to the right border and shows the caret. One editor (`field_loop` in + `tui.c`) serves forms, row-table header fields and the bottom-line + prompts. The caret is a real position: ←/→/Home/End/Del work inside the + field, `Ctrl+U` clears it. Text longer than the field scrolls + horizontally (`tui_field_scroll`) so the caret is always visible; it + never wraps onto the lines below. +- In the editor `Enter` commits and stays on the field, `Tab`/`Shift-Tab` + commit and move to the next/previous row, `Esc` restores the old value + (the editor works on a scratch copy). A choice field shows `< value >` + in place (←/→ or space cycle). An amount that does not parse is reported + and stays in the field for correction. - First keystroke in a freshly focused field replaces its content (`field_fresh`), so prefilled values like dates can be typed over. - Backspace/Del/`^U` still delete normally instead of replacing. -- A prompt edits a scratch copy: only `Enter` commits it to the field; - `Esc` leaves the field exactly as it was. + Backspace/Del/`^U`/caret moves edit what is there and end that state: the + next printable key is inserted, it never wipes the field. +- Byte input is UTF-8 safe: a character that does not fit in the buffer is + dropped whole, never half-inserted. +- Forms taller than the screen scroll with the focus; dim `↑ fler` / + `↓ fler` markers show that rows are hidden above/below + (`tui_form_scroll`). - Date fields (`date_field_edit`, `date_prompt`) accept digits only and insert the dashes themselves: type `20260315` and the field shows `2026-03-15`. Backspace deletes a digit (with its separator), ←/→/Home/End move by digit, @@ -222,11 +240,16 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width. the fields above the table on the same screen. Focus starts on the first field; `Tab`/`Shift-Tab` walk fields, then the cells row by row, and wrap back to the first field. `Up`/`Down` move between fields (in the table - they change row). `Enter` opens the field's editor (text/date/amount/ - choice) and advances to the next field; `Esc` cancels the editor without - changing anything. Typing a printable character hands the focus to the - first table cell and inserts it there, so rows can be entered without - touching the header. `F5`/`Ctrl+Enter`/`Esc` work the same from both. + they change row). `Enter` opens the field's in-place editor (text/date/ + amount/choice) and advances to the next field on commit; `Esc` cancels + the editor without changing anything. Typing a printable character on a + focused text/date/amount field starts editing that field with the key + (replacing the value, like any fresh field); on a choice/action field it + does nothing. The hardware cursor only shows in a table cell. `q` is text + here — only `Esc` leaves the table. Moving to another cell (arrows, + `Enter`, `Tab`) resets the caret to the end of the new cell. A focused + cell scrolls horizontally like a form field. `F5`/`Ctrl+Enter`/`Esc` + work the same from both. - A form may carry an action list under its fields (`tui_form_run_actions`): fields first, then action rows, one focus ring (`Tab`/`Shift-Tab`/ up/down, `Home`/`End`; the ring wraps and heading rows are skipped). @@ -265,6 +288,9 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width. ## Messages - Info/confirmation: `message(title, ...)` box, dismissed with Enter. + Dialogs read keys through the application's input hook like every other + widget, so arrow keys are decoded (never leak `[A` into the next view) + and `^C`/`^R` work inside them. - Quitting: only `Ctrl+C` (from anywhere) or "Logga ut / avsluta" ends the app; `Esc`/`q` only navigate. After `Ctrl+C` every screen unwinds, the session is closed and the terminal restored. @@ -358,8 +384,10 @@ only place that touches ncurses. Rules: hints; return `Esc`/`q` to the parent. 3. Use `tui_menu`/`tui_select_list` instead of writing a new loop; pass `allow_new`/`allow_refresh` so the universal keys apply. -4. Forms use the shared editor (`tui_edit_field`, `tui_prompt_into`, - `tui_date_prompt_into`, `tui_amount_prompt_into`) and the row helpers. +4. Forms use `tui_form_run*`/`tui_rt_run`, which edit fields in place; + one-off questions use the prompts (`tui_prompt_into`, + `tui_date_prompt_into`, `tui_amount_prompt_into`, `tui_choice_prompt`). + All of them share one field editor. 5. Support `F5` if the data can change elsewhere. 6. Update `PROTOCOL.md` §8 and this file if you add a new key or interaction. 7. Declare the screen's actions in one `tui_action` list (once the -- cgit v1.3