fixes and improves tab navigation mechanism.

This commit is contained in:
2025-12-11 17:55:52 +02:00
parent d2e5bddbcb
commit 4395e11843
17 changed files with 180 additions and 149 deletions
+6 -2
View File
@@ -9,10 +9,12 @@
button_t *init_button(WINDOW **win, widget_t *w_parent, char *label) {
button_t *btn = malloc(sizeof(button_t));
init_widget(&(btn->w), w_parent, win, label);
init_widget(&(btn->w), w_parent, win, label);
btn->is_disabled = 0;
btn->w.x = strlen(btn->w.title) + 6; // + "[ ]"
btn->w.y = 1; // TODO: detect new line
btn->w.y = 1; // TODO: detect new line
btn->w.cur.y = 0;
btn->w.cur.x = 0;
return btn;
}
@@ -31,6 +33,8 @@ int32_t draw_button(button_t *btn, uint32_t active_id) {
}
mvwprintw(win, margin_y, margin_x, "%s", title);
btn->w.cur.y = margin_y;
btn->w.cur.x = margin_x;
wattroff(win, A_BOLD | A_REVERSE);
return strlen(title);
+45 -27
View File
@@ -7,54 +7,71 @@
#include "dialogue.h"
#include "group.h"
#define INCR_ACTIVE_ID(d, current, next) \
if (d->active.id != d->current->last_id) { \
d->active.id = d->active.id + 1; \
} else if (d->next != NULL) { \
d->active.id = d->next->first_id; \
d->active.type = next; \
} else { \
d->active.id = d->current->first_id; \
}
void dialogue_default_callback(callback_args_t *args) {
dialogue_t *d = (void *)args->widget;
char key = *((char *)args->data);
app_t *app = (app_t *)args->app;
callback_args_t new_args;
group_resp_t response;
int32_t *resp_value = (int32_t *)args->resp_data;
group_el_t *default_element = NULL;
memcpy(&new_args, args, sizeof(callback_args_t));
new_args.widget = d->g_content;
new_args.resp_data = &response;
new_args.active_id = d->active.id;
switch (key) {
case '\t':
// TODO: active task
if (d->active.type == g_content) {
if (d->active.id != d->g_content->last_id) {
d->active.id = d->active.id + 1;
} else {
d->active.id = d->g_content->first_id;
}
INCR_ACTIVE_ID(d, g_content, g_action);
} else if (d->active.type == g_action) {
INCR_ACTIVE_ID(d, g_action, g_content);
}
*resp_value = -1;
draw_dialogue(d);
break;
case '\n':
if (d->active.type == g_action) {
if (d->active.id != d->g_action->last_id) {
d->active.id = d->active.id + 1;
} else {
d->active.id = d->g_action->first_id;
new_args.widget = new_args.widget = d->g_action;
group_default_callback(&new_args);
} else {
for (int i = 0; i < d->g_action->count; i++) {
if (d->g_action->elements[i].is_default) {
*resp_value = i;
return;
}
}
}
draw_dialogue(d);
break;
default:
d->g_content->w.callback(&new_args);
if (response.value > -1) {
d->is_initiated = 0;
destroy_dialogue(d);
app->modal.type = none;
if (d->active.type == g_content) {
new_args.widget = new_args.widget = d->g_content;
group_default_callback(&new_args);
} else {
new_args.widget = new_args.widget = d->g_action;
group_default_callback(&new_args);
}
if (*resp_value == -1) {
draw_dialogue(d);
}
}
}
void init_dialogue(dialogue_t *dialogue, const char title[], const char text[],
uint32_t cur_y, uint32_t cur_x) {
coordinates_t *p_coordinates) {
dialogue->win = 0;
dialogue->g_content = NULL;
dialogue->w.x = 0;
dialogue->w.y = 0;
dialogue->cur_y = cur_y;
dialogue->cur_x = cur_x;
dialogue->p_coordinates = p_coordinates;
dialogue->w.callback = dialogue_default_callback;
dialogue->is_initiated = 1;
strcpy(dialogue->w.title, title);
@@ -123,12 +140,10 @@ int32_t draw_dialogue(dialogue_t *d) {
/* space for action block */
y += 2;
d->w.x = x;
d->w.y = y;
d->w.m_y = (d->cur_y - y) / 2;
d->w.m_x = (d->cur_x - x) / 2;
d->w.m_y = (d->p_coordinates->max_y - y) / 2;
d->w.m_x = (d->p_coordinates->max_x - x) / 2;
/* render window */
if (d->win == NULL) {
@@ -156,10 +171,10 @@ int32_t draw_dialogue(dialogue_t *d) {
print_multiline_text(d->win, d->text, d->w.x, 2, 1, PMT_ALIGN_CENTER);
wattroff(d->win, A_REVERSE);
if (d->g_content != NULL) {
draw_group(d->win, d->g_content, d->active.id);
draw_group(d->win, d->g_content, d->active.id, &(d->w));
}
if (d->g_action != NULL) {
draw_group(d->win, d->g_action, d->active.id);
draw_group(d->win, d->g_action, d->active.id, &(d->w));
}
return 0;
};
@@ -168,6 +183,9 @@ void destroy_dialogue(dialogue_t *d) {
if (d->g_content) {
destroy_group(d->g_content);
}
if (d->g_action) {
destroy_group(d->g_action);
}
delwin(d->win);
d->win = NULL;
d->is_initiated = 0;
+3 -4
View File
@@ -2,6 +2,7 @@
#define DIALOGUE_H
#include "../widget.h"
#include "../../common.h"
#include "button.h"
#include "group.h"
#include <ncurses.h>
@@ -17,16 +18,14 @@ typedef struct {
struct {
int32_t id;
enum g_type type;
uint32_t y, x;
} active;
uint32_t cur_y;
uint32_t cur_x;
char text[DIALOGUE_TEXT];
uint32_t is_initiated : 1;
coordinates_t *p_coordinates;
} dialogue_t;
void init_dialogue(dialogue_t *d, const char title[], const char text[],
uint32_t cur_x, uint32_t cur_y);
coordinates_t *p_coordinates);
int32_t draw_dialogue(dialogue_t *d);
void destroy_dialogue(dialogue_t *d);
void dialogue_default_callback(callback_args_t *args);
+29 -38
View File
@@ -9,36 +9,23 @@
#define MAKE_RESPONSE_M1(args, resp_data, response) \
if (args->resp_data != NULL) { \
response->active_id = g->active_id; \
response->value = -1; \
}
#define FIND_ELEMENT(args, element_ptr, element_idx) \
if (args->resp_data != NULL) { \
for (int i = 0; i < g->count; i++) { \
if (g->elements[i].id == g->active_id) { \
element_ptr = &(g->elements[i]); \
element_idx = i; \
break; \
} \
} \
*response = -1; \
}
void group_default_callback(callback_args_t *args) {
group_t *g = (group_t *)args->widget;
char key = *((char *)args->data);
group_resp_t *response = (group_resp_t *)args->resp_data;
int32_t *response = (int32_t *)args->resp_data;
input_t *input;
group_el_t *element_ptr;
int32_t element_idx = -1;
switch (key) {
case '\n': /* Enter */
FIND_ELEMENT(args, element_ptr, element_idx);
response->active_id = g->active_id;
response->value = element_idx;
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
*response = element_idx;
break;
case '\177': /* DEL */
FIND_ELEMENT(args, element_ptr, element_idx);
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
if (element_ptr->type == w_input) {
input = (input_t *)element_ptr->element;
if (input->value_len) {
@@ -48,7 +35,7 @@ void group_default_callback(callback_args_t *args) {
MAKE_RESPONSE_M1(args, resp_data, response);
break;
default:
FIND_ELEMENT(args, element_ptr, element_idx);
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
if (element_ptr->type == w_input) {
input = (input_t *)element_ptr->element;
if (input->max_len > input->value_len) {
@@ -76,12 +63,13 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
}
group->elements = calloc(group->count, sizeof(group_el_t));
group_el_t *elements = group->elements;
for (int i = 0; i < group->count; i++) {
for (int32_t i = 0; i < group->count; i++) {
elements[i].type = children[i].type;
elements[i].is_default = children[i].is_default;
}
/* init child elements */
for (int i = 0; i < group->count; i++) {
for (int32_t i = 0; i < group->count; i++) {
widget_t *w;
switch (elements[i].type) {
case w_button:
@@ -101,7 +89,7 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
// set dimensions
elements[i].id = w->id;
if (direction == horizontal) {
w->m_x = group->w.x;
w->m_x = group->w.x + 1;
w->m_y = group->w.m_y;
group->w.x += w->x + 1;
if (group->w.y < w->y)
@@ -109,7 +97,6 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
}
if (i == 0) {
group->first_id = w->id;
group->active_id = w->id;
} else {
group->last_id = w->id;
}
@@ -118,8 +105,11 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
return group;
}
void draw_group(WINDOW *win, group_t *group, int32_t active_id) {
void draw_group(WINDOW *win, group_t *group, int32_t active_id,
widget_t *dialog_w) {
group_el_t *children = group->elements;
group_el_t *active_element = NULL;
uint32_t active_idx;
for (int i = 0; i < group->count; i++) {
group_el_t *el = &children[i];
switch (el->type) {
@@ -135,22 +125,23 @@ void draw_group(WINDOW *win, group_t *group, int32_t active_id) {
break;
}
}
for (int i = 0; i < group->count; i++) {
if (group->elements[i].id == group->active_id &&
group->elements[i].type == w_input) {
input_t *input = group->elements[i].element;
uint32_t margin_y = input->w.m_y + input->w.w_parent->m_y;
uint32_t margin_x = input->w.m_x + input->w.w_parent->m_x + 1;
if (input->max_len == input->value_len) {
wmove(win, margin_y + 1, margin_x + input->value_len);
} else {
wmove(win, margin_y + 1,
margin_x + input->value_len +
1); // x: +1: margin left from the border
}
curs_set(1);
/* move cursor */
FIND_ACTIVE_ELEMENT(group, active_id, active_element, active_idx);
if (active_element != NULL && active_element->id == active_id &&
active_element->type == w_input) {
input_t *input = active_element->element;
dialog_w->cur.y = input->w.cur.y;
if (input->max_len == input->value_len) {
dialog_w->cur.x = input->w.cur.x + input->value_len - 1;
} else {
dialog_w->cur.x = input->w.cur.x + input->value_len;
}
}
if (dialog_w->cur.y || dialog_w->cur.x) {
wmove(win, dialog_w->cur.y, dialog_w->cur.x);
curs_set(1);
}
}
void destroy_group(group_t *group) {
+11 -6
View File
@@ -13,10 +13,12 @@ typedef struct {
uint32_t id;
void *element;
enum w_type type;
uint32_t is_default : 1;
} group_el_t;
typedef struct {
enum w_type type;
uint32_t is_default : 1;
char label[DIALOGUE_TITLE];
uint32_t length;
} group_el_init_t;
@@ -24,20 +26,23 @@ typedef struct {
typedef struct {
widget_t w;
group_el_t *elements;
uint32_t active_id; // TODO: needs to be removed
enum g_direction direction;
uint32_t count;
uint32_t first_id, last_id;
} group_t;
typedef struct {
int32_t value;
uint32_t active_id;
} group_resp_t;
#define FIND_ACTIVE_ELEMENT(g, active_id, element_ptr, element_idx) \
for (int i = 0; i < g->count; i++) { \
if (g->elements[i].id == active_id) { \
element_ptr = &(g->elements[i]); \
element_idx = i; \
break; \
} \
}
group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
enum g_direction dir);
void draw_group(WINDOW *win, group_t *group, int32_t active_id);
void draw_group(WINDOW *win, group_t *group, int32_t active_id, widget_t *dialog_w);
void destroy_group(group_t *group);
void group_default_callback(callback_args_t *args);
+7 -6
View File
@@ -13,7 +13,7 @@ input_t *init_input(WINDOW **win, widget_t *w_parent, char *label,
init_widget(&(input->w), w_parent, win, label);
input->is_disabled = 0;
input->w.y = 3; // with borders
input->w.x = length + 2; // with borders
input->w.x = length + 2; // with borders
uint32_t t_len = strlen(input->w.title) + 4; // with borders and space
if (input->w.x < t_len)
input->w.x = t_len;
@@ -27,7 +27,7 @@ input_t *init_input(WINDOW **win, widget_t *w_parent, char *label,
int32_t draw_input(input_t *input, uint32_t active_id) {
WINDOW *win = *(input->w.parent_win);
uint32_t margin_y = input->w.m_y + input->w.w_parent->m_y;
uint32_t margin_x = input->w.m_x + input->w.w_parent->m_x + 1; // +1: margin left from the border
uint32_t margin_x = input->w.m_x + input->w.w_parent->m_x;
wattrset(win, COLOR_PAIR(MODAL_COLOR_PAIR));
@@ -41,9 +41,9 @@ int32_t draw_input(input_t *input, uint32_t active_id) {
mvwvline(win, margin_y + 1, margin_x, 0, 1);
mvwvline(win, margin_y + 2, margin_x, ACS_LLCORNER, 1);
// right
mvwvline(win, margin_y, margin_x + input->w.x-1, ACS_URCORNER, 1);
mvwvline(win, margin_y + 1, margin_x + input->w.x-1, 0, 1);
mvwvline(win, margin_y + 2, margin_x + input->w.x-1, ACS_LRCORNER, 1);
mvwvline(win, margin_y, margin_x + input->w.x - 1, ACS_URCORNER, 1);
mvwvline(win, margin_y + 1, margin_x + input->w.x - 1, 0, 1);
mvwvline(win, margin_y + 2, margin_x + input->w.x - 1, ACS_LRCORNER, 1);
// TODO: correct sizes (x)
@@ -57,7 +57,8 @@ int32_t draw_input(input_t *input, uint32_t active_id) {
uint32_t x_c = 0;
mvwprintw(win, margin_y + 1, margin_x, "%s", input->value);
input->w.cur.y = margin_y + 1;
input->w.cur.x = margin_x;
for (int i = 0; i < input->w.x - input->value_len - 2; i++) {
mvwprintw(win, margin_y + 1, margin_x + i + input->value_len, " ");
}