From 8f6ec355e7e872715ca57063e6c31acf9712a406 Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Thu, 26 Feb 2026 15:07:04 +0200 Subject: [PATCH] ui: finishes nested groups; +email field in registration modal --- TODO.md | 8 +++--- src/modals/alert.c | 2 +- src/modals/ask_server_addr.c | 13 +++------- src/modals/download_pr.c | 2 +- src/modals/login_credentials.c | 8 +++--- src/modals/login_option.c | 12 ++++----- src/modals/notification.c | 2 +- src/modals/register.c | 21 ++++++++------- src/modals/server_message.c | 2 +- src/modals/upload_dialogue.c | 2 +- src/modals/upload_props_dialogue.c | 4 +-- src/widget/app.h | 1 - src/widget/dialogue.c | 41 +++++++++++++++++------------- src/widget/input.c | 17 ++++++++----- 14 files changed, 71 insertions(+), 64 deletions(-) diff --git a/TODO.md b/TODO.md index cdeedc7..f0e19c3 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,12 @@ # TODO: ## Current: -- [ ] UI: vertical layout (needs for email in registration) -- [ ] Nested groups +- [x] UI: vertical layout (needs for email in registration) +- [x] Nested groups - [x] Create dynamic map of elements IDs and their pointers -- [ ] Adapt modals to new value-forwarding method +- [x] Adapt modals to new value-forwarding method +- [ ] Move text to the end if text in the input is larger, than field +- [ ] More intuitive navigation between nested groups (by pressing left and right buttons) ## Features: - [x] Search files diff --git a/src/modals/alert.c b/src/modals/alert.c index ccf176b..8b23e04 100644 --- a/src/modals/alert.c +++ b/src/modals/alert.c @@ -25,7 +25,7 @@ void notification(const char *title, const char *message, return; group_el_init_t actions[] = { - {.type = w_button, .label = "OK", .is_default = 1}, {.type = w_end}}; + {.type = w_button, .label = "OK", .is_default = true}, {.type = w_end}}; dialogue_t *d = malloc(sizeof(dialogue_t)); diff --git a/src/modals/ask_server_addr.c b/src/modals/ask_server_addr.c index dfe2a13..27f3451 100644 --- a/src/modals/ask_server_addr.c +++ b/src/modals/ask_server_addr.c @@ -1,17 +1,10 @@ #include #include #include - -// #include "../app.h" -// #include "../widget/dialogue.h" -// #include "../widget/group.h" -// #include "../widget/input.h" -// #include "../widget/button.h" - #include +#include #include "../connection.h" #include "group.h" -#include "widget_core.h" typedef struct { button_t *element; @@ -51,8 +44,8 @@ dialogue_t *init_asa_modal(app_t *app) { {.type = w_end}}; group_el_init_t actions[] = { - {.type = w_button, .label = "Connect", .is_default = 1}, - {.type = w_button, .label = "Cancel", .is_default = 0}, + {.type = w_button, .label = "Connect", .is_default = true, .val.num = 1}, + {.type = w_button, .label = "Cancel", .is_default = false, .val.num = 2}, {.type = w_end}}; init_dialogue(&(app->modal), "Connect to server", diff --git a/src/modals/download_pr.c b/src/modals/download_pr.c index 13173f8..7d453b1 100644 --- a/src/modals/download_pr.c +++ b/src/modals/download_pr.c @@ -17,7 +17,7 @@ dialogue_t *init_dwn_pr_modal(app_t *app, bool is_upload) { sprintf(text, "%s file: %s", is_upload ? "Uploading" : "Downloading", is_upload ? app->query_args->file->name : app->file_args->f_selected.name); group_el_init_t actions[] = { - {.type = w_button, .label = "Cancel", .is_default = 1}, {.type = w_end}}; + {.type = w_button, .label = "Cancel", .is_default = true, .val.num = 1}, {.type = w_end}}; app->modal.w.parent_win = &app->win; init_dialogue(&(app->modal), is_upload ? "Upload" : "Download", text, diff --git a/src/modals/login_credentials.c b/src/modals/login_credentials.c index d6de53e..13f282f 100644 --- a/src/modals/login_credentials.c +++ b/src/modals/login_credentials.c @@ -24,7 +24,7 @@ void init_login_credentials_modal_cb(callback_args_t *args) { dialogue_default_callback(&d_args); if (d_args.resp_data.code == cbrp_val) { switch (d_args.resp_data.val.val.num) { - case 0: + case 1: app->params->uname = malloc(in_name->value_len + 1); app->params->pass = malloc(in_pass->value_len + 1); strncpy(app->params->uname, in_name->value, in_name->value_len); @@ -36,7 +36,7 @@ void init_login_credentials_modal_cb(callback_args_t *args) { d->needs_destroy = true; print_bars(app); break; - case 1: + case 2: app->query_args->state = S_ASK_LOGIN_TYPE; app->modal.needs_destroy = true; } @@ -55,8 +55,8 @@ dialogue_t *init_login_credentials_modal(app_t *app) { {.type = w_end}}; group_el_init_t actions[] = { - {.type = w_button, .label = "Login", .is_default = true}, - {.type = w_button, .label = "Cancel", .is_default = false}, + {.type = w_button, .label = "Login", .is_default = true, .val.num = 1}, + {.type = w_button, .label = "Cancel", .is_default = false, .val.num = 2}, {.type = w_end}}; init_dialogue(&(app->modal), "Login", "Your login credentials", diff --git a/src/modals/login_option.c b/src/modals/login_option.c index e5d7e1b..09d4f69 100644 --- a/src/modals/login_option.c +++ b/src/modals/login_option.c @@ -22,7 +22,7 @@ void login_modal_option_cb(callback_args_t *args) { dialogue_default_callback(&d_args); if (d_args.resp_data.code == cbrp_val) { switch (d_args.resp_data.val.val.num) { - case 0: + case 1: d->needs_destroy = true; app->params->uname = malloc(sizeof "anonymous"); strcpy(app->params->uname, "anonymous"); @@ -30,11 +30,11 @@ void login_modal_option_cb(callback_args_t *args) { app->query_args->state = S_WAIT_SERVER; print_bars(app); break; - case 1: + case 2: d->needs_destroy = true; app->query_args->state = S_ASK_LOGIN_USER; break; - case 2: + case 3: d->needs_destroy = true; app->query_args->state = S_ASK_REGISTER; break; @@ -45,9 +45,9 @@ void login_modal_option_cb(callback_args_t *args) { dialogue_t *init_login_option_modal(app_t *app) { if (app == NULL) return NULL; - group_el_init_t children[] = {{.type = w_button, .label = "Anonymous"}, - {.type = w_button, .label = "User"}, - {.type = w_button, .label = "Register"}, + group_el_init_t children[] = {{.type = w_button, .label = "Anonymous", .val.num = 1}, + {.type = w_button, .label = "User", .val.num = 2}, + {.type = w_button, .label = "Register", .val.num = 3}, {.type = w_end}}; init_dialogue(&(app->modal), "Login", diff --git a/src/modals/notification.c b/src/modals/notification.c index f85ca1e..a4988b3 100644 --- a/src/modals/notification.c +++ b/src/modals/notification.c @@ -29,7 +29,7 @@ dialogue_t *init_notification_modal(app_t *app) { return NULL; group_el_init_t actions[] = { - {.type = w_button, .label = "OK", .is_default = 1, .val.num = 1}, + {.type = w_button, .label = "OK", .is_default = true, .val.num = 1}, {.type = w_end}}; init_dialogue(&(app->modal), "Notification", app->query_args->notification, diff --git a/src/modals/register.c b/src/modals/register.c index a0e570c..0fd619b 100644 --- a/src/modals/register.c +++ b/src/modals/register.c @@ -25,14 +25,17 @@ 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; - input_t *in_name = d->g_content->elements[0].element; - input_t *in_pass = d->g_content->elements[1].element; - input_t *in_pass_r = d->g_content->elements[2].element; + 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) { switch (d_args.resp_data.val.val.num) { - case 0: + case 1: if (strcmp(in_pass->value, in_pass_r->value)) { alert("Your passwords do not match"); in_pass->value[0] = '\0'; @@ -47,12 +50,12 @@ void init_register_modal_cb(callback_args_t *args) { app->params->uname[in_name->value_len] = 0; strncpy(app->params->pass, in_pass->value, in_pass->value_len); app->params->pass[in_pass->value_len] = 0; - sprintf(query, "register %s %s\n%n", app->params->uname, - app->params->pass, &qlen); + sprintf(query, "register %s %s %*s\n%n", app->params->uname, + 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; - case 1: + case 2: app->query_args->state = S_ASK_LOGIN_TYPE; app->modal.needs_destroy = true; } @@ -83,8 +86,8 @@ dialogue_t *init_register_modal(app_t *app) { {.type = w_end}}; group_el_init_t actions[] = { - {.type = w_button, .label = "Register", .is_default = true}, - {.type = w_button, .label = "Cancel", .is_default = false}, + {.type = w_button, .label = "Register", .is_default = true, .val.num = 1}, + {.type = w_button, .label = "Cancel", .is_default = false, .val.num = 2}, {.type = w_end}}; init_dialogue(&(app->modal), "Credentials", "There is information needed", diff --git a/src/modals/server_message.c b/src/modals/server_message.c index 3b6278f..e7fb528 100644 --- a/src/modals/server_message.c +++ b/src/modals/server_message.c @@ -38,7 +38,7 @@ void *init_server_message_modal(app_t *app) { if (app == NULL) return NULL; group_el_init_t children[] = { - {.type = w_button, .label = "OK", .is_default = 1, .val.num = 1}, {.type = w_end}}; + {.type = w_button, .label = "OK", .is_default = true, .val.num = 1}, {.type = w_end}}; init_dialogue(&(app->modal), "Server response", app->query_args->server_message.text, &(app->coordinates)); diff --git a/src/modals/upload_dialogue.c b/src/modals/upload_dialogue.c index 78440c8..f1b33df 100644 --- a/src/modals/upload_dialogue.c +++ b/src/modals/upload_dialogue.c @@ -42,7 +42,7 @@ dialogue_t *init_upload_dialogue_modal(app_t *app) { {.type = w_end}}; group_el_init_t actions[] = { - {.type = w_button, .label = "Cancel", .is_default = 0}, {.type = w_end}}; + {.type = w_button, .label = "Cancel", .is_default = false, .val.num = 0}, {.type = w_end}}; app->modal.w.parent_win = &app->win; init_dialogue(&(app->modal), "Upload new file", "Enter essential data", diff --git a/src/modals/upload_props_dialogue.c b/src/modals/upload_props_dialogue.c index 3857e68..def81ec 100644 --- a/src/modals/upload_props_dialogue.c +++ b/src/modals/upload_props_dialogue.c @@ -52,8 +52,8 @@ dialogue_t *init_upload_props_dialogue_modal(app_t *app) { {.type = w_end}}; group_el_init_t actions[] = { - {.type = w_button, .label = "Upload", .is_default = 1}, - {.type = w_button, .label = "Cancel", .is_default = 0}, + {.type = w_button, .label = "Upload", .is_default = true}, + {.type = w_button, .label = "Cancel", .is_default = false}, {.type = w_end}, }; diff --git a/src/widget/app.h b/src/widget/app.h index 79d84c3..1714e0b 100644 --- a/src/widget/app.h +++ b/src/widget/app.h @@ -10,7 +10,6 @@ typedef enum { modal_color_pair = 3, - modal_border_color_pair = 4, } color; typedef enum { diff --git a/src/widget/dialogue.c b/src/widget/dialogue.c index 63fae47..7cdb10a 100644 --- a/src/widget/dialogue.c +++ b/src/widget/dialogue.c @@ -95,7 +95,8 @@ void dialogue_default_callback(callback_args_t *args) { if (d->active_el->g_type == g_action) { new_args.element = d->g_action; group_default_callback(&new_args); - mempcpy(&(args->resp_data), &(new_args.resp_data), sizeof(new_args.resp_data)); + mempcpy(&(args->resp_data), &(new_args.resp_data), + sizeof(new_args.resp_data)); } else if (d->g_action != NULL) { for (int i = 0; i < d->g_action->count; i++) { if (d->g_action->elements[i].is_default) { @@ -105,7 +106,6 @@ void dialogue_default_callback(callback_args_t *args) { } } } else { - /* TODO: temp solution, improve */ args->resp_data.code = cbrp_val; args->resp_data.val.val.num = d->active_el->idx; return; @@ -160,27 +160,32 @@ void init_dialogue(dialogue_t *dialogue, const char title[], const char text[], dialogue->text[t_size - 1] = '\0'; } -void dialogue_init_active_id(dialogue_t *dialogue) { - enum w_type widget_type; +int group_init_active_id(group_t *g, dialogue_t *d) { + enum w_type wt; + for (int i = 0; i < g->count; i++) { + wt = g->elements[i].type; + if (wt == w_button || wt == w_input || + wt == w_fs_file_list) { /* Add here new types */ + d->active_el = g->elements + i; + return 1; + } else if (wt == w_group) { + group_t *child_g = g->elements[i].element; + return group_init_active_id(child_g, d); + } + } + return 0; +} + +void dialogue_init_active_id(dialogue_t *dialogue) { if (dialogue->g_content != NULL) { - for (int i = 0; i < dialogue->g_content->count; i++) { - widget_type = dialogue->g_content->elements[i].type; - if (widget_type == w_button || widget_type == w_input || - widget_type == w_fs_file_list) { /* Add here new types */ - dialogue->active_el = dialogue->g_content->elements + i; - return; - } + if (group_init_active_id(dialogue->g_content, dialogue)) { + return; } } if (dialogue->g_action != NULL) { - for (int i = 0; i < dialogue->g_action->count; i++) { - widget_type = dialogue->g_action->elements[i].type; - if (widget_type == w_button || widget_type == w_input || - widget_type == w_fs_file_list) { - dialogue->active_el = dialogue->g_action->elements + i; - return; - } + if (group_init_active_id(dialogue->g_action, dialogue)) { + return; } } } diff --git a/src/widget/input.c b/src/widget/input.c index eeea55a..75c7d11 100644 --- a/src/widget/input.c +++ b/src/widget/input.c @@ -31,7 +31,7 @@ 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; uint32_t margin_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) { @@ -40,13 +40,15 @@ int32_t draw_input(input_t *input, uint32_t active_id) { w_par = w_par->w_parent; } - wattrset(win, COLOR_PAIR(modal_color_pair)); + if (input->w.id == active_id) { + wattrset(win, COLOR_PAIR(3)); + } else { + 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); - mvwprintw(win, margin_y, margin_x + 1, " %s ", input->w.title); - // left mvwvline(win, margin_y, margin_x, ACS_ULCORNER, 1); mvwvline(win, margin_y + 1, margin_x, 0, 1); @@ -56,6 +58,9 @@ int32_t draw_input(input_t *input, uint32_t active_id) { 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); + wattrset(win, COLOR_PAIR(0) | A_REVERSE); + mvwprintw(win, margin_y, margin_x + 1, " %s ", input->w.title); + margin_x++; if (input->w.id == active_id) { @@ -66,10 +71,10 @@ 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, input->w.x - input->value_len - 2, ""); + stars, (int)(input->w.x - input->value_len - 2), ""); } else { mvwprintw(win, margin_y + 1, margin_x, "%s%*s", input->value, - input->w.x - input->value_len - 2, ""); + (int)(input->w.x - input->value_len - 2), ""); } input->w.cur.y = margin_y + 1;