aboutsummaryrefslogtreecommitdiff
path: root/clients
diff options
context:
space:
mode:
Diffstat (limited to 'clients')
-rw-r--r--clients/bokftui.c15
-rw-r--r--clients/tui.c71
-rw-r--r--clients/tui.h17
3 files changed, 76 insertions, 27 deletions
diff --git a/clients/bokftui.c b/clients/bokftui.c
index 3258f22..f7500bf 100644
--- a/clients/bokftui.c
+++ b/clients/bokftui.c
@@ -320,6 +320,7 @@ static void update_status(struct app *a)
/* Create a new fiscal year. Returns the new id (>0) or 0. */
static int64_t fy_new_form(struct app *a)
{
+ static int sel = 0;
char label[32] = "", start[16] = "", end[16] = "";
char *resp =
client_rpc(&a->conn, "fiscal_year.list", a->session, a->org, "{}");
@@ -372,7 +373,7 @@ static int64_t fy_new_form(struct app *a)
ff[2].value = end;
ff[2].cap = sizeof end;
ff[2].kind = TUI_F_DATE;
- int r = tui_form_run("Nytt räkenskapsår", ff, 3, 1);
+ int r = tui_form_run("Nytt räkenskapsår", ff, 3, 1, &sel);
if (r == TUI_FORM_BACK)
return 0;
if (r != TUI_FORM_REFRESH && r != TUI_FORM_SUBMIT)
@@ -4130,6 +4131,7 @@ static void board_screen(struct app *a)
static void company_screen(struct app *a)
{
+ static int sel = 0;
const int nf = (int)(sizeof COMPANY_FIELDS / sizeof COMPANY_FIELDS[0]);
int owner = a->role[0] && strcmp(a->role, "owner") == 0;
for (;;) {
@@ -4164,7 +4166,7 @@ static void company_screen(struct app *a)
free(resp);
ff[nf].label = "Styrelseledamöter";
ff[nf].kind = TUI_F_ACTION;
- int r = tui_form_run("Företagsuppgifter", ff, nf + 1, owner);
+ int r = tui_form_run("Företagsuppgifter", ff, nf + 1, owner, &sel);
if (r >= 0 && r < nf) {
if (!company_field_valid(&COMPANY_FIELDS[r], vals[r])) {
tui_message("Ogiltigt värde", "%s", COMPANY_FIELDS[r].label);
@@ -4204,6 +4206,7 @@ static const char *const SETTING_LABELS[] = { "Standardserie",
static void settings_screen(struct app *a)
{
+ static int sel = 0;
const int nset = (int)(sizeof SETTING_KEYS / sizeof SETTING_KEYS[0]);
for (;;) {
if (g_quit)
@@ -4231,7 +4234,7 @@ static void settings_screen(struct app *a)
ff[i].kind = TUI_F_TEXT;
}
free(resp);
- int r = tui_form_run("Inställningar", ff, nset, 1);
+ int r = tui_form_run("Inställningar", ff, nset, 1, &sel);
if (r >= 0) {
yyjson_mut_doc *d = yyjson_mut_doc_new(NULL);
yyjson_mut_val *o = yyjson_mut_obj(d);
@@ -4472,6 +4475,7 @@ static void bokslut_plan(struct app *a, const char *fond, const char *rate,
view. New years inherit the stable fields. */
static void bokslut_screen(struct app *a)
{
+ static int sel = 0;
static const char *const labels[6] = {
"Väsentliga händelser",
"Årsstämma (YYYY-MM-DD)",
@@ -4574,7 +4578,7 @@ static void bokslut_screen(struct app *a)
" bokslutsplan ^Enter = bokför planen (frågar"
" först) Esc/q = tillbaka ^C = avsluta");
int r = tui_form_run_actions("Bokslut", ff, nf + 2, can_edit, acts, 5,
- NULL);
+ NULL, &sel);
if (r >= 0 && r < nf) {
yyjson_mut_doc *d = yyjson_mut_doc_new(NULL);
yyjson_mut_val *o = yyjson_mut_obj(d);
@@ -5606,6 +5610,7 @@ static int try_login(struct app *a, const char *user, const char *pass,
static int login_screen(struct app *a)
{
+ static int sel = 0;
char socket_path[256], user[64], pass[128];
snprintf(socket_path, sizeof socket_path, "%s", a->socket);
const char *env_pass = getenv("BOKFD_PASSWORD");
@@ -5631,7 +5636,7 @@ static int login_screen(struct app *a)
ff[3].kind = TUI_F_ACTION;
for (;;) {
- int r = tui_form_run("bokf — inloggning", ff, 4, 1);
+ int r = tui_form_run("bokf — inloggning", ff, 4, 1, &sel);
if (r == TUI_FORM_BACK) {
if (g_quit) {
endwin();
diff --git a/clients/tui.c b/clients/tui.c
index a5b0cd2..c52538c 100644
--- a/clients/tui.c
+++ b/clients/tui.c
@@ -1346,6 +1346,36 @@ static int act_selectable(const struct tui_form_action *acts, int i, int na)
return acts && i >= 0 && i < na && acts[i].enabled != -1;
}
+int tui_form_focus_clamp(int focus, int nf,
+ const struct tui_form_action *acts, int na)
+{
+ if (nf < 0)
+ nf = 0;
+ if (na < 0)
+ na = 0;
+ int n = nf + na;
+ if (n <= 0)
+ return -1;
+ int pos = focus;
+ if (pos < 0)
+ pos = 0;
+ if (pos >= n)
+ pos = n - 1;
+ for (int i = 0; i < n; i++) {
+ if (pos < nf || act_selectable(acts, pos - nf, na))
+ return pos;
+ pos = (pos + 1) % n;
+ }
+ return -1;
+}
+
+int tui_form_focus_store(int *focus, int sel, int ret)
+{
+ if (focus)
+ *focus = sel;
+ return ret;
+}
+
int tui_form_act_step(int focus, int nf, const struct tui_form_action *acts,
int na, int dir)
{
@@ -1440,13 +1470,14 @@ static void form_draw_actions(const struct tui_form_action *acts, int na,
static int form_run(const char *title, struct tui_form_field *f, int nf,
int can_edit, const struct tui_form_action *acts, int na,
- const char *hint, int (*key)(void *ud, int ch), void *ud)
+ const char *hint, int (*key)(void *ud, int ch), void *ud,
+ int *focus)
{
- int sel = nf > 0 ? 0 : tui_form_act_first(0, acts, na);
+ int sel = tui_form_focus_clamp(focus ? *focus : -1, nf, acts, na);
for (;;) {
int ntot = nf + (na > 0 ? na : 0);
if (ntot <= 0)
- return TUI_FORM_BACK;
+ return tui_form_focus_store(focus, sel, TUI_FORM_BACK);
if (sel < 0)
sel = tui_form_act_first(nf, acts, na);
if (sel >= ntot)
@@ -1523,15 +1554,15 @@ static int form_run(const char *title, struct tui_form_field *f, int nf,
}
if (nxt == TUI_FORM_REFRESH || nxt == TUI_FORM_SUBMIT ||
nxt == TUI_FORM_BACK)
- return nxt;
+ return tui_form_focus_store(focus, sel, nxt);
if (key) {
int hk = key(ud, ch);
if (hk == TUI_HOOK_BACK)
- return TUI_FORM_BACK;
+ return tui_form_focus_store(focus, sel, TUI_FORM_BACK);
if (hk == TUI_HOOK_REFRESH)
- return TUI_FORM_REFRESH;
+ return tui_form_focus_store(focus, sel, TUI_FORM_REFRESH);
if (hk == TUI_HOOK_SUBMIT)
- return TUI_FORM_SUBMIT;
+ return tui_form_focus_store(focus, sel, TUI_FORM_SUBMIT);
if (hk != TUI_HOOK_NONE)
continue;
}
@@ -1550,7 +1581,8 @@ static int form_run(const char *title, struct tui_form_field *f, int nf,
}
if (act->enabled == -1)
continue;
- return TUI_FORM_ACTION + (sel - nf);
+ return tui_form_focus_store(focus, sel,
+ TUI_FORM_ACTION + (sel - nf));
}
if (!can_edit) {
tui_message(title, "Endast behöriga kan ändra.");
@@ -1558,49 +1590,50 @@ static int form_run(const char *title, struct tui_form_field *f, int nf,
}
struct tui_form_field *fl = &f[sel];
if (fl->kind == TUI_F_ACTION)
- return sel;
+ return tui_form_focus_store(focus, sel, sel);
char label[192];
snprintf(label, sizeof label, "%s: ", fl->label);
if (fl->kind == TUI_F_TEXT) {
if (fl->value &&
tui_prompt_into(fl->value, fl->cap, label, fl->value,
fl->mask))
- return sel;
+ return tui_form_focus_store(focus, sel, sel);
} else if (fl->kind == TUI_F_DATE) {
if (fl->value && tui_date_prompt_into(fl->value, fl->cap, label,
fl->value))
- return sel;
+ return tui_form_focus_store(focus, sel, sel);
} else if (fl->kind == TUI_F_AMOUNT) {
if (fl->ore && tui_amount_prompt_into(fl->ore, label, *fl->ore))
- return sel;
+ return tui_form_focus_store(focus, sel, sel);
} else if (fl->kind == TUI_F_CHOICE && fl->choice) {
int c = tui_choice_prompt(label, fl->choices, fl->nchoices,
*fl->choice);
if (c >= 0) {
*fl->choice = c;
- return sel;
+ return tui_form_focus_store(focus, sel, sel);
}
}
}
}
int tui_form_run(const char *title, struct tui_form_field *f, int n,
- int can_edit)
+ int can_edit, int *focus)
{
- return form_run(title, f, n, can_edit, NULL, 0, NULL, NULL, NULL);
+ return form_run(title, f, n, can_edit, NULL, 0, NULL, NULL, NULL, focus);
}
int tui_form_run_hook(const char *title, struct tui_form_field *f, int n,
- int can_edit, int (*key)(void *ud, int ch), void *ud)
+ int can_edit, int (*key)(void *ud, int ch), void *ud,
+ int *focus)
{
- return form_run(title, f, n, can_edit, NULL, 0, NULL, key, ud);
+ return form_run(title, f, n, can_edit, NULL, 0, NULL, key, ud, focus);
}
int tui_form_run_actions(const char *title, struct tui_form_field *f, int nf,
int can_edit, const struct tui_form_action *acts,
- int na, const char *hint)
+ int na, const char *hint, int *focus)
{
- return form_run(title, f, nf, can_edit, acts, na, hint, NULL, NULL);
+ return form_run(title, f, nf, can_edit, acts, na, hint, NULL, NULL, focus);
}
/* ------------------------------------------------------------------ */
diff --git a/clients/tui.h b/clients/tui.h
index d0656da..7250c0b 100644
--- a/clients/tui.h
+++ b/clients/tui.h
@@ -179,11 +179,13 @@ struct tui_form_field {
};
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);
+ int can_edit, int *focus);
void tui_form_hint(const char *hint); /* overrides the footer for the next run */
int tui_form_run_hook(const char *title, struct tui_form_field *f, int n,
- int can_edit, int (*key)(void *ud, int ch), void *ud);
+ int can_edit, int (*key)(void *ud, int ch), void *ud,
+ int *focus);
/* --- action list in a form (tui_form_run_actions) --- */
/* enabled: 1 = selectable and runs; 0 = dimmed but selectable (Enter shows
@@ -197,6 +199,15 @@ struct tui_form_action {
#define TUI_FORM_ACTION 1000 /* action i is returned as TUI_FORM_ACTION + i */
+/* Focus memory: the screen owns an int and passes its address to
+ tui_form_run*; on entry *focus is clamped to a selectable row — out of
+ range snaps to the nearest end and a heading row snaps forward, wrapping
+ — and on every return the row the form stopped on is written back.
+ Passing NULL starts at the first focusable row and stores nothing. */
+int tui_form_focus_clamp(int focus, int nf,
+ const struct tui_form_action *acts, int na);
+int tui_form_focus_store(int *focus, int sel, int ret);
+
/* Focus ring over fields (0..nf-1) and actions (nf..nf+na-1); heading rows
are skipped and the ring wraps. dir +1 = Tab/Down, -1 = Shift-Tab/Up. */
int tui_form_act_step(int focus, int nf, const struct tui_form_action *acts,
@@ -218,7 +229,7 @@ void tui_form_act_label(const struct tui_form_action *a, char *buf, size_t n);
footer; tui_form_hint() still takes precedence. */
int tui_form_run_actions(const char *title, struct tui_form_field *f, int nf,
int can_edit, const struct tui_form_action *acts,
- int na, const char *hint);
+ int na, const char *hint, int *focus);
/* --- row table --- */
enum { TUI_RT_EDIT = 0, TUI_RT_INFO, TUI_RT_DATE };