aboutsummaryrefslogtreecommitdiff
path: root/clients/tui.c
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-20 10:24:18 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-20 10:24:18 +0200
commitae60b7d2c87cc9ed6878faa57cd4233f77f6f7c3 (patch)
tree918e717a5d226dcd54890901682a980c41d7e1d0 /clients/tui.c
parent5097941fa96ce0c309e5f1af034993781a70fc66 (diff)
downloadbokf-ae60b7d2c87cc9ed6878faa57cd4233f77f6f7c3.tar.gz
bokf-ae60b7d2c87cc9ed6878faa57cd4233f77f6f7c3.zip
tui: pinned report headers, voucher detail headers, clamped pagingv0.1.48
Diffstat (limited to 'clients/tui.c')
-rw-r--r--clients/tui.c116
1 files changed, 87 insertions, 29 deletions
diff --git a/clients/tui.c b/clients/tui.c
index 06740d3..031fad0 100644
--- a/clients/tui.c
+++ b/clients/tui.c
@@ -126,6 +126,8 @@ const char *tui_markup(const char *line, int *style)
{
const char *p = line ? line : "";
int st = -1;
+ if (*p == TUI_MARK_STICKY)
+ p++;
if (*p == TUI_MARK_HEADING) {
st = TUI_HEADING;
p++;
@@ -141,6 +143,20 @@ const char *tui_markup(const char *line, int *style)
return p;
}
+int tui_sticky_split(char **lines, int n, char **head, int *nhead)
+{
+ int h = 0, b = 0;
+ for (int i = 0; i < n; i++) {
+ if (lines[i][0] == TUI_MARK_STICKY)
+ head[h++] = lines[i];
+ else
+ lines[b++] = lines[i];
+ }
+ if (nhead)
+ *nhead = h;
+ return b;
+}
+
void tui_keys_setup(void)
{
/* ^Enter has no control code; enable xterm modifyOtherKeys and bind the
@@ -1210,6 +1226,28 @@ int tui_pager(const char *title, const char *text, const char *action_hint)
action_hint ? TUI_PAGER_SAVE : 0, NULL, NULL);
}
+static void pager_line(int row, const char *line)
+{
+ move(row, 2);
+ clrtoeol();
+ if (!line)
+ return;
+ int st = -1;
+ const char *s = tui_markup(line, &st);
+ if (st == TUI_RULE) {
+ attrset(tui_style_attrs(TUI_RULE, g_colours, 0));
+ for (int x = 2; x < COLS - 1; x++)
+ mvaddch(row, x, ACS_HLINE);
+ attrset(A_NORMAL);
+ } else if (st >= 0) {
+ attrset(tui_style_attrs((enum tui_style)st, g_colours, 0));
+ mvaddnstr(row, 2, s, COLS - 4);
+ attrset(A_NORMAL);
+ } else {
+ mvaddnstr(row, 2, s, COLS - 4);
+ }
+}
+
int tui_pager_hook(const char *title, const char *text,
const char *extra_hint, unsigned flags,
int (*key)(void *ud, int ch), void *ud)
@@ -1232,29 +1270,24 @@ int tui_pager_hook(const char *title, const char *text,
break;
p = nl + 1;
}
+ char **head = xcalloc(nlines ? nlines : 1, sizeof(char *));
+ int nhead = 0;
+ int nb = tui_sticky_split(lines, n, head, &nhead);
int top = 0;
int view = LINES - 4;
+ int vbody = view - nhead;
+ if (vbody < 1)
+ vbody = 1;
for (;;) {
tui_frame(title);
- for (int i = 0; i < view; i++) {
- move(2 + i, 2);
- clrtoeol();
- if (top + i >= n)
- continue;
- int st = -1;
- const char *s = tui_markup(lines[top + i], &st);
- if (st == TUI_RULE) {
- attrset(tui_style_attrs(TUI_RULE, g_colours, 0));
- for (int x = 2; x < COLS - 1; x++)
- mvaddch(2 + i, x, ACS_HLINE);
- attrset(A_NORMAL);
- } else if (st >= 0) {
- attrset(tui_style_attrs((enum tui_style)st, g_colours, 0));
- mvaddnstr(2 + i, 2, s, COLS - 4);
- attrset(A_NORMAL);
- } else {
- mvaddnstr(2 + i, 2, s, COLS - 4);
- }
+ int row = 0;
+ for (int i = 0; i < nhead && row < view; i++, row++)
+ pager_line(2 + row, head[i]);
+ for (int i = 0; i < vbody && row < view; i++, row++) {
+ if (top + i < nb)
+ pager_line(2 + row, lines[top + i]);
+ else
+ pager_line(2 + row, NULL);
}
char hint[512];
if (extra_hint && *extra_hint)
@@ -1290,23 +1323,24 @@ int tui_pager_hook(const char *title, const char *text,
if (h == TUI_HOOK_STAY)
continue;
}
- if (ch == KEY_DOWN && top + view < n)
+ if (ch == KEY_DOWN && top + vbody < nb)
top++;
else if (ch == KEY_UP && top > 0)
top--;
else if (ch == KEY_NPAGE)
- top += view;
+ top += vbody;
else if (ch == KEY_PPAGE)
- top -= view;
+ top -= vbody;
else if (ch == KEY_HOME)
top = 0;
else if (ch == KEY_END)
- top = n > view ? n - view : 0;
- if (top + view > n)
- top = n > view ? n - view : 0;
+ top = nb > vbody ? nb - vbody : 0;
+ if (top + vbody > nb)
+ top = nb > vbody ? nb - vbody : 0;
if (top < 0)
top = 0;
}
+ free(head);
free(copy);
free(lines);
return ret;
@@ -1410,6 +1444,33 @@ int tui_form_act_first(int nf, const struct tui_form_action *acts, int na)
return -1;
}
+int tui_form_act_page(int focus, int nf, const struct tui_form_action *acts,
+ int na, int dir)
+{
+ if (nf < 0)
+ nf = 0;
+ if (na < 0)
+ na = 0;
+ int n = nf + na;
+ if (n <= 0)
+ return -1;
+ int pos = focus >= 0 && focus < n ? focus : 0;
+ for (int i = 0; i < TUI_FORM_PAGE; i++) {
+ int next = -1;
+ for (int p = pos + (dir >= 0 ? 1 : -1); p >= 0 && p < n;
+ p += (dir >= 0 ? 1 : -1)) {
+ if (p < nf || act_selectable(acts, p - nf, na)) {
+ next = p;
+ break;
+ }
+ }
+ if (next < 0)
+ break;
+ pos = next;
+ }
+ return pos;
+}
+
int tui_form_act_key(int sel, int nf, const struct tui_form_action *acts,
int na, int ch)
{
@@ -1429,10 +1490,7 @@ int tui_form_act_key(int sel, int nf, const struct tui_form_action *acts,
}
if (ch == KEY_NPAGE || ch == KEY_PPAGE) {
int dir = ch == KEY_NPAGE ? 1 : -1;
- int pos = sel;
- for (int i = 0; i < TUI_FORM_PAGE; i++)
- pos = tui_form_act_step(pos, nf, acts, na, dir);
- return pos;
+ return tui_form_act_page(sel, nf, acts, na, dir);
}
return tui_form_next(sel, nf, ch);
}