summaryrefslogtreecommitdiff
path: root/clients/tui.h
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-19 21:58:58 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-19 21:58:58 +0200
commit4329ffb98d7eeffe2b3874d2b31cb0857d33d944 (patch)
tree16e777dc90fa334ce3f436a3b5d3a7a9efdbd8b9 /clients/tui.h
parent34fc2b1dce788fbb093e70c2124630167e7980ef (diff)
downloadbokf-4329ffb98d7eeffe2b3874d2b31cb0857d33d944.tar.gz
bokf-4329ffb98d7eeffe2b3874d2b31cb0857d33d944.zip
tui: shared widget layer (fields, prompts, lists, forms, pager) + testsv0.1.36
Diffstat (limited to 'clients/tui.h')
-rw-r--r--clients/tui.h131
1 files changed, 131 insertions, 0 deletions
diff --git a/clients/tui.h b/clients/tui.h
new file mode 100644
index 0000000..0bda359
--- /dev/null
+++ b/clients/tui.h
@@ -0,0 +1,131 @@
+#ifndef BOKF_TUI_H
+#define BOKF_TUI_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <ncursesw/ncurses.h>
+
+/* Shared TUI widgets: the only place that touches ncurses (screens compose
+ these; see docs/TUI-GUIDELINES.md). Everything with logic of its own is
+ unit-tested in tests/test_tui.c, which links only the pure parts. */
+
+/* Universal keys that have no control code or need a stable name. */
+#define TUI_KEY_CTRL_N 0x0e
+#define TUI_KEY_CTRL_ENTER (KEY_MAX + 1)
+
+/* The application supplies input, frame/hints drawing and a quit hook so
+ this module stays free of app state (and testable). */
+void tui_set_input(int (*fn)(void));
+void tui_set_screen(void (*frame)(const char *), void (*hints)(const char *));
+void tui_set_quit(void (*fn)(void));
+void tui_keys_setup(void);
+
+/* --- text measure and formatting --- */
+int tui_disp_width(const char *s);
+int tui_disp_width_n(const char *s, size_t n);
+void tui_pad_field(char *buf, size_t cap, int width);
+void tui_pad_label(char *buf, size_t n, const char *text, int width);
+void tui_pad_hdr(char *buf, size_t n, int width, const char *text);
+void tui_amt_col(char *buf, size_t n, int width, int64_t ore);
+void tui_kr_format(int64_t ore, char *buf, size_t n);
+void tui_kr0_format(int64_t ore, char *buf, size_t n);
+int tui_parse_kr(const char *s, int64_t *out);
+
+/* --- line editor (pure) --- */
+struct tui_ledit {
+ char *buf;
+ size_t cap;
+ size_t len;
+ size_t pos; /* caret in bytes */
+};
+
+void tui_le_init(struct tui_ledit *e, char *buf, size_t cap);
+void tui_le_clear(struct tui_ledit *e);
+int tui_le_key(struct tui_ledit *e, int ch);
+
+/* Applies one key to a form field. *pos is the caret ((size_t)-1 = end);
+ *fresh replaces the content on the first editing key. Returns whether
+ the key was consumed. */
+int tui_field_edit(char *buf, size_t cap, size_t *pos, int ch, int *fresh);
+
+/* Date field: digits only, dashes inserted ("20260215" -> "2026-02-15"),
+ caret tracked in digit space. */
+int tui_date_field_edit(char *buf, size_t cap, size_t *pos, int ch,
+ int *fresh);
+
+/* Line editor at (y,x) with the label already drawn. Returns 1 on Enter,
+ 2 on Tab, 3 on Shift-Tab, 0 on Esc. */
+int tui_edit_field(int y, int x, char *buf, size_t cap, int mask);
+
+/* --- modal dialogs --- */
+void tui_message(const char *title, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+int tui_confirm(const char *title, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+
+/* --- prompts: write into the caller's buffer, return 0 on Esc --- */
+int tui_prompt_into(char *buf, size_t cap, const char *label,
+ const char *def, int mask);
+int tui_date_prompt_into(char *buf, size_t cap, const char *label,
+ const char *def);
+int tui_amount_prompt_into(int64_t *out, const char *label, int64_t def_ore);
+int tui_choice_prompt(const char *label, const char *const *opts, int n,
+ int cur);
+
+/* --- lists --- */
+#define TUI_NAV_NONE (-3)
+
+struct tui_list_nav {
+ int n, sel, top, view, numw;
+ char gotobuf[12];
+ char gotolabel[32];
+ int goto_active;
+};
+
+/* Returns the selected index, or -1 back, -2 refresh, -4 new, -6 remove,
+ -7 toggle, TUI_NAV_NONE when nothing happened. */
+int tui_nav_key(struct tui_list_nav *v, int ch, int allow_new,
+ int allow_remove, int allow_toggle, int menu_mode);
+
+int tui_select_list(const char *title, char **items, int n, int start,
+ int allow_refresh, int *cursor, int allow_new,
+ const char *archive_action, int allow_toggle);
+int tui_menu(const char *title, const char *const *items, int n,
+ int allow_new, int *cursor);
+
+/* --- frame, status, hints, pager --- */
+void tui_set_status(const char *status, const char *right);
+void tui_frame(const char *title);
+void tui_hints(const char *s);
+int tui_pager(const char *title, const char *text, const char *action_hint);
+
+/* --- forms --- */
+enum {
+ TUI_F_TEXT = 0,
+ TUI_F_DATE,
+ TUI_F_AMOUNT,
+ TUI_F_CHOICE,
+ TUI_F_ACTION,
+};
+
+#define TUI_FORM_BACK (-1)
+#define TUI_FORM_REFRESH (-2)
+#define TUI_FORM_SUBMIT (-3)
+
+struct tui_form_field {
+ const char *label;
+ char *value; /* text storage for TEXT/DATE (also CHOICE labels) */
+ size_t cap;
+ int kind;
+ int64_t *ore; /* TUI_F_AMOUNT */
+ const char *const *choices; /* TUI_F_CHOICE */
+ int nchoices;
+ int *choice; /* TUI_F_CHOICE: current index */
+};
+
+int tui_form_next(int sel, int n, int ch);
+int tui_form_run(const char *title, struct tui_form_field *f, int n,
+ int can_edit);
+
+#endif