From 791c3055ba425205cfdea6f256a44ee6c74478d6 Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Fri, 27 Feb 2026 14:21:52 +0200 Subject: [PATCH] ui: advanced positioning system (not finished) --- TODO.md | 2 +- src/main.c | 2 +- src/modals/register.c | 32 +++++++++++----------- src/query.c | 6 ++--- src/server.c | 5 ++-- src/widget/button.c | 12 ++++----- src/widget/dialogue.c | 36 ++++++++++++------------- src/widget/fs_file_list.c | 4 +-- src/widget/group.c | 27 ++++++++++--------- src/widget/input.c | 50 +++++++++++++++++------------------ src/widget/progress_bar.c | 22 +++++++-------- src/widget_core/widget_core.c | 15 ++++++++--- src/widget_core/widget_core.h | 18 +++++++++---- 13 files changed, 123 insertions(+), 108 deletions(-) diff --git a/TODO.md b/TODO.md index f0e19c3..55f2bf3 100644 --- a/TODO.md +++ b/TODO.md @@ -5,7 +5,7 @@ - [x] Nested groups - [x] Create dynamic map of elements IDs and their pointers - [x] Adapt modals to new value-forwarding method -- [ ] Move text to the end if text in the input is larger, than field +- [ ] Advanced ui element positioning system - [ ] More intuitive navigation between nested groups (by pressing left and right buttons) ## Features: diff --git a/src/main.c b/src/main.c index 7d89c4f..d199e5f 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ #include "file_list.h" #include "main.h" #include "query.h" -#include "modals/alert.h" +#include uint32_t m_id = 0; diff --git a/src/modals/register.c b/src/modals/register.c index 0fd619b..5a02a2e 100644 --- a/src/modals/register.c +++ b/src/modals/register.c @@ -4,12 +4,11 @@ #include #include #include - #include +#include #include "alert.h" #include "group.h" -#include "widget_core.h" typedef struct { button_t *element; @@ -25,15 +24,16 @@ void init_register_modal_cb(callback_args_t *args) { memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; d_args.element = app->active_widget; - group_t *g_email_user = d->g_content->elements[0].element; - group_t *g_passwords = d->g_content->elements[1].element; - input_t *in_name = g_email_user->elements[0].element; - input_t *in_email = g_email_user->elements[1].element; - input_t *in_pass = g_passwords->elements[0].element; - input_t *in_pass_r = g_passwords->elements[1].element; dialogue_default_callback(&d_args); if (d_args.resp_data.code == cbrp_val && d_args.resp_data.val.type == val_num) { + /* TODO: Fix cancel case */ + group_t *g_email_user = d->g_content->elements[0].element; + group_t *g_passwords = d->g_content->elements[1].element; + input_t *in_name = g_email_user->elements[0].element; + input_t *in_email = g_email_user->elements[1].element; + input_t *in_pass = g_passwords->elements[0].element; + input_t *in_pass_r = g_passwords->elements[1].element; switch (d_args.resp_data.val.val.num) { case 1: if (strcmp(in_pass->value, in_pass_r->value)) { @@ -51,7 +51,8 @@ void init_register_modal_cb(callback_args_t *args) { strncpy(app->params->pass, in_pass->value, in_pass->value_len); app->params->pass[in_pass->value_len] = 0; sprintf(query, "register %s %s %*s\n%n", app->params->uname, - app->params->pass, (int) in_email->value_len, in_email->value, &qlen); + app->params->pass, (int)in_email->value_len, in_email->value, + &qlen); write(app->params->sd, query, qlen); app->query_args->state = S_WAIT_REGISTER_CONFIRMATION; break; @@ -65,10 +66,6 @@ void init_register_modal_cb(callback_args_t *args) { dialogue_t *init_register_modal(app_t *app) { if (app == NULL) return NULL; - group_el_init_t content_name_email[] = { - {.type = w_input, .label = "Username", .length = 18}, - {.type = w_input, .label = "Email", .length = 18}, - {.type = w_end}}; group_el_init_t content_pass[] = {{.type = w_input, .label = "Password", @@ -81,8 +78,9 @@ dialogue_t *init_register_modal(app_t *app) { {.type = w_end}}; group_el_init_t content[] = { - {.type = w_group, .direction = vertical, .children = content_name_email}, - {.type = w_group, .direction = vertical, .children = content_pass}, + {.type = w_input, .label = "Username", .length = 18}, + {.type = w_group, .direction = horizontal, .children = content_pass}, + {.type = w_input, .label = "Email", .length = 40}, {.type = w_end}}; group_el_init_t actions[] = { @@ -95,8 +93,8 @@ dialogue_t *init_register_modal(app_t *app) { dialogue_t *d = &(app->modal); d->w.callback = init_register_modal_cb; - d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map), - horizontal, g_content); + d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map), vertical, + g_content); d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), horizontal, g_action); diff --git a/src/query.c b/src/query.c index 58e5558..72df260 100644 --- a/src/query.c +++ b/src/query.c @@ -20,11 +20,11 @@ #include "draw_modal.h" #include "file_processor.h" #include "main.h" -#include "modals/alert.h" #include "server.h" #include "types.h" -#include "widget/app.h" -#include "widget_core/widget_core.h" +#include +#include +#include static void wait_side(app_t *app); void user_request_description(query_args_t *q_args); diff --git a/src/server.c b/src/server.c index 4389f93..150beb8 100644 --- a/src/server.c +++ b/src/server.c @@ -1,8 +1,7 @@ -#include "app.h" #include "dialogue.h" #include "main.h" -#include "modals/alert.h" -#include "widget/file_list.h" +#include +#include #include #include #include diff --git a/src/widget/button.c b/src/widget/button.c index 5394c10..3157e7e 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -11,8 +11,8 @@ 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); btn->is_disabled = 0; - btn->w.x = strlen(btn->w.title) + 6; // + "[ ]" - btn->w.y = 1; // TODO: detect new line + btn->w.sz.x = strlen(btn->w.title) + 6; // + "[ ]" + btn->w.sz.y = 1; // TODO: detect new line btn->w.cur.y = 0; btn->w.cur.x = 0; return btn; @@ -21,14 +21,14 @@ button_t *init_button(WINDOW **win, widget_t *w_parent, char *label) { int32_t draw_button(button_t *btn, uint32_t active_id) { char title[DIALOGUE_TITLE + 6]; WINDOW *win = *(btn->w.parent_win); - uint32_t margin_y = btn->w.m_y; - uint32_t margin_x = btn->w.m_x; + uint32_t margin_y = btn->w.ps.y + btn->w.m.y; + uint32_t margin_x = btn->w.ps.x + btn->w.m.x; widget_t *w_par = btn->w.w_parent; while (w_par->parent_win == btn->w.parent_win) { - margin_y += w_par->m_y; - margin_x += w_par->m_x; + margin_y += w_par->ps.y; + margin_x += w_par->ps.x; w_par = w_par->w_parent; } diff --git a/src/widget/dialogue.c b/src/widget/dialogue.c index 9ba523f..141ab15 100644 --- a/src/widget/dialogue.c +++ b/src/widget/dialogue.c @@ -143,8 +143,8 @@ void init_dialogue(dialogue_t *dialogue, const char title[], const char text[], uint32_t t_size = 0; dialogue->win = 0; dialogue->g_content = NULL; - dialogue->w.x = 0; - dialogue->w.y = 0; + dialogue->w.sz.x = 0; + dialogue->w.sz.y = 0; dialogue->p_coordinates = p_coordinates; dialogue->w.callback = dialogue_default_callback; dialogue->is_initiated = true; @@ -192,14 +192,14 @@ void dialogue_init_active_id(dialogue_t *dialogue) { #define DETECT_GROUP_SIZE(group, line_max_len, y, x) \ if (group) { \ - group->w.m_y = y; \ - if (line_max_len < group->w.x) { \ - line_max_len = group->w.x; \ - group->w.m_x = 0; \ + group->w.ps.y = y; \ + if (line_max_len < group->w.sz.x) { \ + line_max_len = group->w.sz.x; \ + group->w.ps.x = 0; \ } else { \ - group->w.m_x = (line_max_len - group->w.x) / 2; \ + group->w.ps.x = (line_max_len - group->w.sz.x) / 2; \ } \ - y += group->w.y; \ + y += group->w.sz.y; \ } int32_t draw_dialogue(dialogue_t *d) { @@ -229,14 +229,14 @@ int32_t draw_dialogue(dialogue_t *d) { x += 1; /* when uses box */ y += 1; /* when uses box */ - d->w.x = x; - d->w.y = y; - d->w.m_y = (d->p_coordinates->max_y - y) / 2; - d->w.m_x = (d->p_coordinates->max_x - x) / 2; + d->w.sz.x = x; + d->w.sz.y = y; + d->w.ps.y = (d->p_coordinates->max_y - y) / 2; + d->w.ps.x = (d->p_coordinates->max_x - x) / 2; /* render window */ if (d->win == NULL) { - d->win = newwin(y, x, d->w.m_y, d->w.m_x); + d->win = newwin(y, x, d->w.ps.y, d->w.ps.x); } switch (d->color_scheme) { @@ -249,12 +249,12 @@ int32_t draw_dialogue(dialogue_t *d) { } /* background */ - for (int yp = 1; yp < d->w.y - 1; yp++) { - mvwprintw(d->win, yp, 1, "%*s", d->w.x, ""); + for (int yp = 1; yp < d->w.sz.y - 1; yp++) { + mvwprintw(d->win, yp, 1, "%*s", d->w.sz.x, ""); } /* title */ - const uint32_t title_mx_pos = (d->w.x - strlen(d->w.title)) / 2; + const uint32_t title_mx_pos = (d->w.sz.x - strlen(d->w.title)) / 2; box(d->win, 0, 0); mvwprintw(d->win, 0, title_mx_pos - 1, " "); mvwprintw(d->win, 0, title_mx_pos, "%s", d->w.title); @@ -262,8 +262,8 @@ int32_t draw_dialogue(dialogue_t *d) { /* text */ wattroff(d->win, A_BOLD); - /* mvwhline(d->win, d->w.y - 3, 1, 0, d->w.x - 2); */ - print_multiline_text(d->win, d->text, d->w.x, 2, 1, PMT_ALIGN_CENTER); + /* mvwhline(d->win, d->w.sz.y - 3, 1, 0, d->w.sz.x - 2); */ + print_multiline_text(d->win, d->text, d->w.sz.x, 2, 1, PMT_ALIGN_CENTER); wattroff(d->win, A_REVERSE); if (d->g_content != NULL) { diff --git a/src/widget/fs_file_list.c b/src/widget/fs_file_list.c index c68924e..2ccc854 100644 --- a/src/widget/fs_file_list.c +++ b/src/widget/fs_file_list.c @@ -148,8 +148,8 @@ ui_fs_file_list_t *init_fs_file_list(WINDOW **win, widget_t *w_parent) { fl_ui->start = get_files_from_fs(fl_ui->d_path); fl_ui->current = fl_ui->start; fl_ui->w.callback = fs_file_list_cb; - fl_ui->w.x = getmaxx(win_par) / 10 * 8; - fl_ui->w.y = getmaxy(win_par) / 10 * 8; + fl_ui->w.sz.x = getmaxx(win_par) / 10 * 8; + fl_ui->w.sz.y = getmaxy(win_par) / 10 * 8; return fl_ui; } diff --git a/src/widget/group.c b/src/widget/group.c index ba29455..3836407 100644 --- a/src/widget/group.c +++ b/src/widget/group.c @@ -77,12 +77,14 @@ union current_element { }; group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children, - d_array_ptr_t *id_map, enum g_direction direction, enum g_type g_type) { + d_array_ptr_t *id_map, enum g_direction direction, + enum g_type g_type) { group_t *group = malloc(sizeof(group_t)); union current_element current; group->parent_group = NULL; current.type = w_end; init_widget(&(group->w), w_parent, win, ""); + group->w.m.x = 1; /* margin left */ /* count elements */ group->count = 0; for (; children[group->count].type != w_end; group->count++) @@ -153,25 +155,26 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children, } } /* set dimensions */ + /* TODO: revise */ elements[i].id = w->id; add_d_arr_ptr(id_map, elements + i, w->id); if (direction == horizontal) { - w->m_x = group->w.m_x + 1 + group->w.x; - w->m_y = group->w.m_y; - group->w.x += w->x + 1; - if (group->w.y < w->y) - group->w.y = w->y; + w->ps.x = group->w.ps.x + group->w.sz.x; + w->ps.y = group->w.ps.y; + group->w.sz.x += w->sz.x + 1; + if (group->w.sz.y < w->sz.y) + group->w.sz.y = w->sz.y; } else { - w->m_x = group->w.m_x; - w->m_y = group->w.m_y + group->w.y; - group->w.y += w->y; - if (group->w.x < w->x) - group->w.x = w->x; + w->ps.x = group->w.ps.x; + w->ps.y = group->w.ps.y + group->w.sz.y; + group->w.sz.y += w->sz.y; + if (group->w.sz.x < w->sz.x) + group->w.sz.x = w->sz.x; } } if (direction == vertical) - group->w.y++; + group->w.sz.y++; return group; } diff --git a/src/widget/input.c b/src/widget/input.c index 75c7d11..cf23fdd 100644 --- a/src/widget/input.c +++ b/src/widget/input.c @@ -12,12 +12,12 @@ input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, input_t *input = malloc(sizeof(input_t)); init_widget(&(input->w), w_parent, win, label); input->is_disabled = 0; - input->w.y = 3; // with borders - input->w.x = length + 3; // with borders and extra space for the last element + input->w.sz.y = 3; // with borders + input->w.sz.x = length + 3; // with borders and extra space for the last element uint32_t t_len = strlen(input->w.title) + 4; // with borders and space - if (input->w.x < t_len) - input->w.x = t_len; - input->w.m_x = 1; + if (input->w.sz.x < t_len) + input->w.sz.x = t_len; + input->w.ps.x = 1; input->value[0] = '\0'; input->value_len = 0; input->max_len = length; @@ -29,14 +29,14 @@ input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, int32_t draw_input(input_t *input, uint32_t active_id) { const char stars[] = "*******************"; WINDOW *win = *(input->w.parent_win); - uint32_t margin_y = input->w.m_y; - uint32_t margin_x = input->w.m_x; + uint32_t pos_y = input->w.ps.y + input->w.m.y; + uint32_t pos_x = input->w.ps.x + input->w.m.x; /* counts margins of the ancestors of the same window */ widget_t *w_par = input->w.w_parent; while (w_par->parent_win == input->w.parent_win) { - margin_y += w_par->m_y; - margin_x += w_par->m_x; + pos_y += w_par->ps.y; + pos_x += w_par->ps.x; w_par = w_par->w_parent; } @@ -46,22 +46,22 @@ int32_t draw_input(input_t *input, uint32_t active_id) { wattrset(win, COLOR_PAIR(0) | A_REVERSE | A_BOLD); } - mvwhline(win, margin_y, margin_x, 0, input->w.x); - mvwhline(win, margin_y + 2, margin_x, 0, input->w.x); + mvwhline(win, pos_y, pos_x, 0, input->w.sz.x); + mvwhline(win, pos_y + 2, pos_x, 0, input->w.sz.x); // left - mvwvline(win, margin_y, margin_x, ACS_ULCORNER, 1); - mvwvline(win, margin_y + 1, margin_x, 0, 1); - mvwvline(win, margin_y + 2, margin_x, ACS_LLCORNER, 1); + mvwvline(win, pos_y, pos_x, ACS_ULCORNER, 1); + mvwvline(win, pos_y + 1, pos_x, 0, 1); + mvwvline(win, pos_y + 2, pos_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, pos_y, pos_x + input->w.sz.x - 1, ACS_URCORNER, 1); + mvwvline(win, pos_y + 1, pos_x + input->w.sz.x - 1, 0, 1); + mvwvline(win, pos_y + 2, pos_x + input->w.sz.x - 1, ACS_LRCORNER, 1); wattrset(win, COLOR_PAIR(0) | A_REVERSE); - mvwprintw(win, margin_y, margin_x + 1, " %s ", input->w.title); + mvwprintw(win, pos_y, pos_x + 1, " %s ", input->w.title); - margin_x++; + pos_x++; if (input->w.id == active_id) { wattrset(win, COLOR_PAIR(modal_color_pair) | A_BOLD | A_REVERSE); @@ -70,15 +70,15 @@ int32_t draw_input(input_t *input, uint32_t active_id) { } if (input->is_hidden) { - mvwprintw(win, margin_y + 1, margin_x, "%.*s%*s", (int)input->value_len, - stars, (int)(input->w.x - input->value_len - 2), ""); + mvwprintw(win, pos_y + 1, pos_x, "%.*s%*s", (int)input->value_len, + stars, (int)(input->w.sz.x - input->value_len - 2), ""); } else { - mvwprintw(win, margin_y + 1, margin_x, "%s%*s", input->value, - (int)(input->w.x - input->value_len - 2), ""); + mvwprintw(win, pos_y + 1, pos_x, "%s%*s", input->value, + (int)(input->w.sz.x - input->value_len - 2), ""); } - input->w.cur.y = margin_y + 1; - input->w.cur.x = margin_x; + input->w.cur.y = pos_y + 1; + input->w.cur.x = pos_x; wattroff(win, A_BOLD | A_REVERSE); return 0; diff --git a/src/widget/progress_bar.c b/src/widget/progress_bar.c index dbd33e9..adf1d84 100644 --- a/src/widget/progress_bar.c +++ b/src/widget/progress_bar.c @@ -10,23 +10,23 @@ ui_progress_bar_t *init_ui_progress_bar(WINDOW **win, widget_t *w_parent) { init_widget(&pb->w, w_parent, win, ""); pb->procent = 0; pb->text[0] = '\0'; - pb->w.y = 4; - pb->w.x = getmaxx(win_par) / 10 * 9; + pb->w.sz.y = 4; + pb->w.sz.x = getmaxx(win_par) / 10 * 9; return pb; } void draw_ui_progress_bar(ui_progress_bar_t *pb) { WINDOW *win = *(pb->w.w_parent->parent_win); - uint32_t margin_y = pb->w.m_y + pb->w.w_parent->m_y; - uint32_t margin_x = pb->w.m_x + pb->w.w_parent->m_x + 1; + uint32_t margin_y = pb->w.ps.y + pb->w.w_parent->ps.y; + uint32_t margin_x = pb->w.ps.x + pb->w.w_parent->ps.x + 1; wattrset(win, COLOR_PAIR(modal_color_pair)); - mvwhline(win, margin_y, margin_x, 0, pb->w.x - 1); + mvwhline(win, margin_y, margin_x, 0, pb->w.sz.x - 1); float procent = pb->procent; procent /= 100; - uint32_t filled_num = procent * pb->w.x; + uint32_t filled_num = procent * pb->w.sz.x; if (filled_num > 2) { filled_num -= 2; } @@ -39,17 +39,17 @@ void draw_ui_progress_bar(ui_progress_bar_t *pb) { wattrset(win, COLOR_PAIR(modal_color_pair)); // bottom line - mvwhline(win, margin_y + 3, margin_x, 0, pb->w.x - 1); + mvwhline(win, margin_y + 3, margin_x, 0, pb->w.sz.x - 1); // left mvwvline(win, margin_y, margin_x, ACS_ULCORNER, 1); mvwvline(win, margin_y + 1, margin_x, 0, 1); mvwvline(win, margin_y + 2, margin_x, 0, 1); mvwvline(win, margin_y + 3, margin_x, ACS_LLCORNER, 1); // right - mvwvline(win, margin_y, margin_x + pb->w.x - 2, ACS_URCORNER, 1); - mvwvline(win, margin_y + 1, margin_x + pb->w.x - 2, 0, 1); - mvwvline(win, margin_y + 2, margin_x + pb->w.x - 2, 0, 1); - mvwvline(win, margin_y + 3, margin_x + pb->w.x - 2, ACS_LRCORNER, 1); + mvwvline(win, margin_y, margin_x + pb->w.sz.x - 2, ACS_URCORNER, 1); + mvwvline(win, margin_y + 1, margin_x + pb->w.sz.x - 2, 0, 1); + mvwvline(win, margin_y + 2, margin_x + pb->w.sz.x - 2, 0, 1); + mvwvline(win, margin_y + 3, margin_x + pb->w.sz.x - 2, ACS_LRCORNER, 1); } void destroy_ui_progress_bar(void *_pb) { diff --git a/src/widget_core/widget_core.c b/src/widget_core/widget_core.c index be5c9a6..da3c1a7 100644 --- a/src/widget_core/widget_core.c +++ b/src/widget_core/widget_core.c @@ -10,10 +10,17 @@ int32_t rsize_to_value(int32_t size, enum rsize rsize); void init_widget(widget_t *w, widget_t *w_parent, WINDOW **win, char *title) { w->id = m_id++; - w->x = 0; - w->y = 0; - w->m_x = 0; - w->m_y = 0; + w->sz.x = 0; + w->sz.y = 0; + w->ps.x = 0; + w->ps.y = 0; + if (w_parent != NULL && w_parent->w_parent != NULL) { /* not root element of the window */ + w->m.x = w_parent->m.x; + w->m.y = w_parent->m.y; + } else { + w->m.x = 0; + w->m.y = 0; + } w->parent_win = win; w->w_parent = w_parent; w->callback = NULL; diff --git a/src/widget_core/widget_core.h b/src/widget_core/widget_core.h index d058c83..26fa819 100644 --- a/src/widget_core/widget_core.h +++ b/src/widget_core/widget_core.h @@ -77,14 +77,22 @@ enum rsize { typedef struct widget_t { int64_t id; char title[DIALOGUE_TITLE]; - int64_t x; - int64_t y; - int64_t m_x; - int64_t m_y; struct { int64_t y; int64_t x; - } cur; + } cur; /* cursor position */ + struct { + int64_t y; + int64_t x; + } sz; /* size */ + struct { + int64_t y; + int64_t x; + } m; /* margin (relative to the parent) */ + struct { + int64_t y; + int64_t x; + } ps; /* position (relative to the window) */ WINDOW *const *parent_win; struct widget_t *w_parent; void (*callback)(callback_args_t *args);