#ifndef BOKF_TUI_H #define BOKF_TUI_H #include #include #include /* 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_X 0x18 #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); /* --- row table --- */ enum { TUI_RT_EDIT = 0, TUI_RT_INFO, TUI_RT_DATE }; struct tui_rt_col { const char *header; int x; int width; int kind; }; struct tui_rt { int nrows, maxrows, ncols, neditable; const struct tui_rt_col *cols; int y; int row, col; int fresh; size_t pos; void (*cell)(void *, int, int, char **, size_t *); void (*info)(void *, int, char *, size_t); void *ud; }; void tui_rt_init(struct tui_rt *t, int nrows, int maxrows, int ncols, const struct tui_rt_col *cols, int y, void (*cell)(void *, int, int, char **, size_t *), void (*info)(void *, int, char *, size_t), void *ud); int tui_rt_blank_row(struct tui_rt *t, int row); int tui_rt_normalize(struct tui_rt *t); int tui_rt_move(struct tui_rt *t, int dr, int dc); int tui_rt_clear(struct tui_rt *t); int tui_rt_run(const char *title, struct tui_rt *t, const char *hint); #endif