diff --git a/TODO.md b/TODO.md index 911c38c..f0e19c3 100644 --- a/TODO.md +++ b/TODO.md @@ -1,15 +1,23 @@ # TODO: +## Current: +- [x] UI: vertical layout (needs for email in registration) +- [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 +- [ ] More intuitive navigation between nested groups (by pressing left and right buttons) + ## Features: - [x] Search files - [x] Correct spacing in the search bar - [x] Finish registration -- [ ] UI: vertical layout (needs for email in registration) - [ ] Get rid of old notification mechanism - [ ] Privilege settings for files - [ ] Files removal - [ ] Encryption - [ ] UTF-8 support + ## Fixes: - [ ] Check and fix registration and login - [ ] Hotkeys for buttons diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 073fdc7..5ff0c89 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,7 @@ add_subdirectory(widget_core) add_subdirectory(widget) add_subdirectory(modals) add_subdirectory(lib) +add_subdirectory(utils) target_link_libraries(zbbs-client-tui PRIVATE @@ -51,5 +52,6 @@ target_link_libraries(zbbs-client-tui widget modals bstring + utils ${CURSES_LIBRARIES} ) \ No newline at end of file diff --git a/src/main.c b/src/main.c index 6fe37e7..7d89c4f 100644 --- a/src/main.c +++ b/src/main.c @@ -44,6 +44,7 @@ int main(int argc, char **argv) { q_args->buf = malloc(INBUFSIZE); app->query_args = q_args; q_args->file_list_ui = init_file_list(&(app->left_win), &(app->right_win)); + draw_file_list(q_args->file_list_ui); /* init client to connect to the server */ app->params->sd = init_client(); diff --git a/src/modals/CMakeLists.txt b/src/modals/CMakeLists.txt index 5634ebe..f1d75a5 100644 --- a/src/modals/CMakeLists.txt +++ b/src/modals/CMakeLists.txt @@ -3,7 +3,13 @@ add_library(modals STATIC) file(GLOB M_HEADERS "*.h") file(GLOB M_SOURCES "*.c") -target_link_libraries(modals PRIVATE widget widget_core bstring) +target_link_libraries(modals + PRIVATE + widget + widget_core + bstring + utils +) target_sources(modals PRIVATE @@ -16,4 +22,5 @@ target_sources(modals target_include_directories(modals PRIVATE "../widget") target_include_directories(modals PRIVATE "../widget_core") -target_include_directories(modals PRIVATE "../lib/") \ No newline at end of file +target_include_directories(modals PRIVATE "../lib/") +target_include_directories(widget PRIVATE "../utils/") \ No newline at end of file diff --git a/src/modals/alert.c b/src/modals/alert.c index 7863d4f..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)); @@ -33,7 +33,7 @@ void notification(const char *title, const char *message, d->w.callback = alert_cb; d->g_content = NULL; - d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); + d->g_action = init_group(&(d->win), &(d->w), actions,&(d->id_map), horizontal, g_action); dialogue_init_active_id(d); d->color_scheme = color; diff --git a/src/modals/ask_server_addr.c b/src/modals/ask_server_addr.c index c9d5100..27f3451 100644 --- a/src/modals/ask_server_addr.c +++ b/src/modals/ask_server_addr.c @@ -1,15 +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" typedef struct { button_t *element; @@ -17,19 +12,17 @@ typedef struct { } group_bt_t; void asa_modal_dialogue_callback(callback_args_t *args) { - int32_t response; callback_args_t d_args; app_t *app = args->app; dialogue_t *d = (dialogue_t *)app->active_widget; memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; - d_args.resp_data = &response; d_args.element = app->active_widget; input_t *in_ip = d->g_content->elements[0].element; input_t *in_port = d->g_content->elements[1].element; dialogue_default_callback(&d_args); - if (response > -1) { - switch (response) { + if (d_args.resp_data.code == cbrp_val) { + switch (d_args.resp_data.val.val.num) { case 0: get_ip_port(app->params, in_ip->value, in_port->value); connect_to_server(app); @@ -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", @@ -60,8 +53,8 @@ dialogue_t *init_asa_modal(app_t *app) { dialogue_t *d = &(app->modal); d->w.callback = asa_modal_dialogue_callback; - d->g_content = init_group(&(d->win), &(d->w), content, horizontal); - d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); + d->g_content = init_group(&(d->win), &(d->w), content,&(d->id_map), horizontal, g_content); + d->g_action = init_group(&(d->win), &(d->w), actions,&(d->id_map), horizontal, g_action); dialogue_init_active_id(d); diff --git a/src/modals/download_pr.c b/src/modals/download_pr.c index 214eed9..7d453b1 100644 --- a/src/modals/download_pr.c +++ b/src/modals/download_pr.c @@ -1,3 +1,4 @@ +#include "group.h" #include #include #include @@ -16,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, @@ -24,8 +25,8 @@ dialogue_t *init_dwn_pr_modal(app_t *app, bool is_upload) { dialogue_t *d = &(app->modal); d->w.callback = dwn_pr_modal_cb; - d->g_content = init_group(&(d->win), &(d->w), content, horizontal); - d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); + d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map), horizontal, g_content); + d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), horizontal, g_action); app->query_args->progress_bar = d->g_content->elements[0].element; app->query_args->active_dialogue = d; diff --git a/src/modals/login_credentials.c b/src/modals/login_credentials.c index e844040..13f282f 100644 --- a/src/modals/login_credentials.c +++ b/src/modals/login_credentials.c @@ -1,3 +1,4 @@ +#include "group.h" #include #include #include @@ -12,20 +13,18 @@ typedef struct { } group_bt_t; void init_login_credentials_modal_cb(callback_args_t *args) { - int32_t response; callback_args_t d_args; app_t *app = args->app; dialogue_t *d = (dialogue_t *)app->active_widget; memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; - d_args.resp_data = &response; 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; dialogue_default_callback(&d_args); - if (response > -1) { - switch (response) { - case 0: + if (d_args.resp_data.code == cbrp_val) { + switch (d_args.resp_data.val.val.num) { + 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); @@ -37,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; } @@ -56,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", @@ -65,8 +64,8 @@ dialogue_t *init_login_credentials_modal(app_t *app) { dialogue_t *d = &(app->modal); d->w.callback = init_login_credentials_modal_cb; - d->g_content = init_group(&(d->win), &(d->w), content, horizontal); - d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); + d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map), horizontal, g_content); + d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), horizontal, g_action); dialogue_init_active_id(d); diff --git a/src/modals/login_option.c b/src/modals/login_option.c index 439b807..09d4f69 100644 --- a/src/modals/login_option.c +++ b/src/modals/login_option.c @@ -1,3 +1,4 @@ +#include "group.h" #include #include #include @@ -12,30 +13,28 @@ typedef struct { } group_bt_t; void login_modal_option_cb(callback_args_t *args) { - int32_t response; callback_args_t d_args; app_t *app = args->app; dialogue_t *d = (dialogue_t *)app->active_widget; memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; - d_args.resp_data = &response; d_args.element = app->active_widget; dialogue_default_callback(&d_args); - if (response > -1) { - switch (response) { - case 0: + if (d_args.resp_data.code == cbrp_val) { + switch (d_args.resp_data.val.val.num) { + case 1: d->needs_destroy = true; app->params->uname = malloc(sizeof "anonymous"); strcpy(app->params->uname, "anonymous"); - write(app->params->sd, app->params->uname, sizeof "anonymous"-1); + write(app->params->sd, app->params->uname, sizeof "anonymous" - 1); 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; @@ -46,18 +45,17 @@ 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", "Select your login " "option", &(app->coordinates)); - app->modal.g_action = - init_group(&(app->modal.win), &(app->modal.w), children, - horizontal); + app->modal.g_action = init_group(&(app->modal.win), &(app->modal.w), children, + &(app->modal.id_map), horizontal, g_action); app->modal.w.callback = login_modal_option_cb; dialogue_init_active_id(&(app->modal)); diff --git a/src/modals/notification.c b/src/modals/notification.c index f0cdd05..a4988b3 100644 --- a/src/modals/notification.c +++ b/src/modals/notification.c @@ -1,3 +1,4 @@ +#include "group.h" #include #include #include @@ -5,21 +6,17 @@ #include -/* TODO: get rid of this mechanism */ - typedef struct { button_t *element; enum w_type type; } group_bt_t; void init_notification_modal_cb(callback_args_t *args) { - int32_t response; callback_args_t d_args; app_t *app = args->app; dialogue_t *d = (dialogue_t *)app->active_widget; memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; - d_args.resp_data = &response; d_args.element = app->active_widget; dialogue_default_callback(&d_args); @@ -32,7 +29,8 @@ dialogue_t *init_notification_modal(app_t *app) { return NULL; group_el_init_t actions[] = { - {.type = w_button, .label = "OK", .is_default = 1}, {.type = w_end}}; + {.type = w_button, .label = "OK", .is_default = true, .val.num = 1}, + {.type = w_end}}; init_dialogue(&(app->modal), "Notification", app->query_args->notification, &(app->coordinates)); @@ -43,7 +41,8 @@ dialogue_t *init_notification_modal(app_t *app) { d->w.callback = init_notification_modal_cb; d->g_content = NULL; - d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); + d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), + horizontal, g_action); dialogue_init_active_id(d); diff --git a/src/modals/register.c b/src/modals/register.c index bac1657..0fd619b 100644 --- a/src/modals/register.c +++ b/src/modals/register.c @@ -8,6 +8,8 @@ #include #include "alert.h" +#include "group.h" +#include "widget_core.h" typedef struct { button_t *element; @@ -17,21 +19,23 @@ typedef struct { void init_register_modal_cb(callback_args_t *args) { char query[256]; int32_t qlen = 0; - int32_t response; callback_args_t d_args; app_t *app = args->app; dialogue_t *d = (dialogue_t *)app->active_widget; memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; - d_args.resp_data = &response; 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 (response > -1) { - switch (response) { - case 0: + 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 1: if (strcmp(in_pass->value, in_pass_r->value)) { alert("Your passwords do not match"); in_pass->value[0] = '\0'; @@ -46,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; } @@ -61,21 +65,29 @@ 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", + .length = 18, + .is_hidden_value = true}, + {.type = w_input, + .label = "Password (repeat)", + .length = 18, + .is_hidden_value = true}, + {.type = w_end}}; + group_el_init_t content[] = { - {.type = w_input, .label = "Username", .length = 15}, - {.type = w_input, - .label = "Password", - .length = 15, - .is_hidden_value = true}, - {.type = w_input, - .label = "Password (repeat)", - .length = 15, - .is_hidden_value = true}, + {.type = w_group, .direction = vertical, .children = content_name_email}, + {.type = w_group, .direction = vertical, .children = content_pass}, {.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", @@ -83,8 +95,10 @@ 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, horizontal); - d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); + d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map), + horizontal, g_content); + d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), + horizontal, g_action); dialogue_init_active_id(d); diff --git a/src/modals/server_message.c b/src/modals/server_message.c index 9c312b4..e7fb528 100644 --- a/src/modals/server_message.c +++ b/src/modals/server_message.c @@ -1,3 +1,4 @@ +#include "group.h" #include #include #include @@ -11,18 +12,16 @@ typedef struct { } group_bt_t; void server_message_modal_cb(callback_args_t *args) { - int32_t response; callback_args_t d_args; app_t *app = args->app; dialogue_t *d = (dialogue_t *)app->active_widget; memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; - d_args.resp_data = &response; d_args.element = app->active_widget; dialogue_default_callback(&d_args); - if (response > -1) { - switch (response) { - case 0: + if (d_args.resp_data.code == cbrp_val) { + switch (d_args.resp_data.val.val.num) { + case 1: d->needs_destroy = true; /* TODO: macros */ free(app->query_args->server_message.text); @@ -39,12 +38,12 @@ 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}, {.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)); app->modal.g_action = - init_group(&(app->modal.win), &(app->modal.w), children, horizontal); + init_group(&(app->modal.win), &(app->modal.w), children, &(app->modal.id_map), horizontal, g_action); app->modal.w.callback = server_message_modal_cb; dialogue_init_active_id(&(app->modal)); diff --git a/src/modals/upload_dialogue.c b/src/modals/upload_dialogue.c index ea9fbd3..f1b33df 100644 --- a/src/modals/upload_dialogue.c +++ b/src/modals/upload_dialogue.c @@ -1,34 +1,35 @@ #include "../file_processor.h" -#include +#include "group.h" #include #include #include +#include void upload_dialogue_modal_cb(callback_args_t *args) { - int32_t response = -1; callback_args_t d_args; app_t *app = args->app; dialogue_t *d = (dialogue_t *)app->active_widget; memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; - d_args.resp_data = &response; d_args.element = app->active_widget; dialogue_default_callback(&d_args); ui_fs_file_list_t *fui = (ui_fs_file_list_t *)d->g_content->elements[0].element; - switch (response) { - case 0: - app->query_args->state = S_WAIT_SERVER; - d->needs_destroy = true; - break; - case 1: - file_upload_open(fui->d_path, fui->current->name, app->query_args); - d->needs_destroy = true; - app->query_args->state = S_UPLOAD_PARAMS; - break; - case -2: - d->needs_destroy = true; - app->query_args->state = WAIT_CLIENT; + if (d_args.resp_data.code == cbrp_val) { + switch (d_args.resp_data.val.val.num) { + case 0: + app->query_args->state = S_WAIT_SERVER; + d->needs_destroy = true; + break; + case 1: + file_upload_open(fui->d_path, fui->current->name, app->query_args); + d->needs_destroy = true; + app->query_args->state = S_UPLOAD_PARAMS; + break; + case -2: + d->needs_destroy = true; + app->query_args->state = WAIT_CLIENT; + } } } @@ -41,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", @@ -49,8 +50,10 @@ dialogue_t *init_upload_dialogue_modal(app_t *app) { dialogue_t *d = &(app->modal); d->w.callback = upload_dialogue_modal_cb; - d->g_content = init_group(&(d->win), &(d->w), content, horizontal); - d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); + d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map), + horizontal, g_content); + d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), + horizontal, g_action); app->query_args->active_dialogue = d; diff --git a/src/modals/upload_props_dialogue.c b/src/modals/upload_props_dialogue.c index dc7be6d..def81ec 100644 --- a/src/modals/upload_props_dialogue.c +++ b/src/modals/upload_props_dialogue.c @@ -1,3 +1,4 @@ +#include "group.h" #include #include #include @@ -7,20 +8,18 @@ #include void upload_props_dialogue_modal_cb(callback_args_t *args) { - int32_t response = -1; callback_args_t d_args; app_t *app = args->app; dialogue_t *d = (dialogue_t *)app->active_widget; memcpy(&d_args, args, sizeof(callback_args_t)); d_args.app = NULL; - d_args.resp_data = &response; d_args.element = app->active_widget; dialogue_default_callback(&d_args); char query[256]; int32_t query_len = 0; input_t *desc_input = (input_t *)d->g_content->elements[0].element; - if (response > -1) { - switch (response) { + if (d_args.resp_data.code == cbrp_val) { + switch (d_args.resp_data.val.val.num) { case 0: query_len = sprintf(query, "file upload \"%s\" %zu 1\n", @@ -53,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}, }; @@ -64,8 +63,8 @@ dialogue_t *init_upload_props_dialogue_modal(app_t *app) { dialogue_t *d = &(app->modal); d->w.callback = upload_props_dialogue_modal_cb; - d->g_content = init_group(&(d->win), &(d->w), content, horizontal); - d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); + d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map), horizontal, g_content); + d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), horizontal, g_action); app->query_args->active_dialogue = d; diff --git a/src/query.c b/src/query.c index 6c6fd15..58e5558 100644 --- a/src/query.c +++ b/src/query.c @@ -16,7 +16,6 @@ #include #include -#include "app.h" #include "connection.h" #include "draw_modal.h" #include "file_processor.h" @@ -25,6 +24,7 @@ #include "server.h" #include "types.h" #include "widget/app.h" +#include "widget_core/widget_core.h" static void wait_side(app_t *app); void user_request_description(query_args_t *q_args); @@ -45,8 +45,10 @@ void query_loop(app_t *app) { size_t qlen; int sr; static file_args_t file_args; - callback_args_t d_args = { - .app = app, .element = NULL, .data = NULL, .resp_data = NULL}; + callback_args_t d_args = {.app = app, + .element = NULL, + .data = NULL, + .resp_data.code = cbrc_none}; init_file_args(&file_args); query_args->sd = sd; diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt new file mode 100644 index 0000000..7c04195 --- /dev/null +++ b/src/utils/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(utils STATIC) + +file(GLOB M_HEADERS "*.h") +file(GLOB M_SOURCES "*.c") + +list(REMOVE_ITEM M_HEADERS "utils.h") + +target_sources(utils + PRIVATE + ${M_SOURCES} + PUBLIC + FILE_SET HEADERS + FILES + ${M_HEADERS} +) diff --git a/src/utils/d_array.c b/src/utils/d_array.c new file mode 100644 index 0000000..979a6fc --- /dev/null +++ b/src/utils/d_array.c @@ -0,0 +1,34 @@ + +#include "d_array.h" +#include +#include +#include + +void init_d_arr_ptr(d_array_ptr_t *arr, int64_t init_capacity) { + arr->capacity = init_capacity; + arr->length = 0; + arr->arr = malloc(sizeof(void *) * init_capacity); + arr->fist_el = NULL; + arr->last_el = NULL; + memset(arr->arr, 0, init_capacity); +} + +void add_d_arr_ptr(d_array_ptr_t *arr, void *ptr, int64_t idx) { + int64_t new_capacity = idx * 2; + if (idx > arr->capacity - 1) { + arr->arr = realloc(arr->arr, new_capacity); + memset(arr->arr+arr->capacity, 0, arr->capacity - new_capacity); + arr->capacity = new_capacity; + } + if (arr->fist_el == NULL) arr->fist_el = ptr; + arr->last_el = ptr; + arr->arr[idx] = ptr; + arr->length = idx+1; +} + +void free_d_arr(d_array_ptr_t *arr) { + arr->capacity = 0; + arr->length = 0; + free(arr->arr); + arr->arr = NULL; +} \ No newline at end of file diff --git a/src/utils/d_array.h b/src/utils/d_array.h new file mode 100644 index 0000000..786896c --- /dev/null +++ b/src/utils/d_array.h @@ -0,0 +1,17 @@ +#ifndef D_ARRAY_H +#define D_ARRAY_H +/* Dynamic array of numbers */ +#include +typedef struct d_array_ptr_t { + int64_t capacity; + int64_t length; + void **arr; + void *fist_el; + void *last_el; +} d_array_ptr_t; + +void init_d_arr_ptr(d_array_ptr_t *arr, int64_t init_capacity); +void add_d_arr_ptr(d_array_ptr_t *arr, void *ptr, int64_t idx); +void free_d_arr(d_array_ptr_t *arr); + +#endif \ No newline at end of file diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..be68e58 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,4 @@ +#ifndef D_UTILS_H +#define D_UTILS_H +#include "d_array.h" +#endif \ No newline at end of file diff --git a/src/widget/CMakeLists.txt b/src/widget/CMakeLists.txt index 978176e..fcaa36f 100644 --- a/src/widget/CMakeLists.txt +++ b/src/widget/CMakeLists.txt @@ -18,7 +18,9 @@ target_link_libraries(widget PRIVATE bstring widget_core + utils ) target_include_directories(widget PRIVATE "../widget_core") -target_include_directories(widget PRIVATE "../lib/") \ No newline at end of file +target_include_directories(widget PRIVATE "../lib/") +target_include_directories(widget PRIVATE "../utils/") \ No newline at end of file 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/button.c b/src/widget/button.c index 8852d75..246c581 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -21,8 +21,16 @@ 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 + btn->w.w_parent->m_y; - uint32_t margin_x = btn->w.m_x + btn->w.w_parent->m_x; + uint32_t margin_y = btn->w.m_y; + uint32_t margin_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; + w_par = w_par->w_parent; + } if (btn->w.id == active_id) { sprintf(title, "[< %s >]", btn->w.title); diff --git a/src/widget/button.h b/src/widget/button.h index 57f88dc..aacb19d 100644 --- a/src/widget/button.h +++ b/src/widget/button.h @@ -1,7 +1,6 @@ #ifndef BUTTON_H #define BUTTON_H -#include "../main.h" #include #include diff --git a/src/widget/dialogue.c b/src/widget/dialogue.c index 8de483f..7cdb10a 100644 --- a/src/widget/dialogue.c +++ b/src/widget/dialogue.c @@ -8,26 +8,42 @@ #include "file_list.h" #include "group.h" #include "input.h" +#include "widget_core.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 incr_active_id(dialogue_t *d) { + group_el_t *active_el = NULL; + while (true) { + for (int i = d->active_el->id + 1; + active_el == NULL && d->id_map.length > i; i++) { + active_el = d->id_map.arr[i]; + } + d->active_el = active_el; + if (d->active_el == NULL) { + d->active_el = d->id_map.fist_el; + break; + } else if (d->active_el->type != w_box && d->active_el->type != w_group) { + break; + } + active_el = NULL; } +} -#define DECR_ACTIVE_ID(d, current, next) \ - if (d->active.id != d->current->first_id) { \ - d->active.id = d->active.id - 1; \ - } else if (d->next != NULL) { \ - d->active.id = d->next->last_id; \ - d->active.type = next; \ - } else { \ - d->active.id = d->current->last_id; \ +void decr_active_id(dialogue_t *d) { + group_el_t *active_el = NULL; + while (true) { + for (int i = d->active_el->id - 1; active_el == NULL && i > 0; i--) { + active_el = d->id_map.arr[i]; + } + d->active_el = active_el; + if (d->active_el == NULL) { + d->active_el = d->id_map.last_el; + break; + } else if (d->active_el->type != w_box && d->active_el->type != w_group) { + break; + } + active_el = NULL; } +} #define CH_GROUP(d, current, next) \ { \ @@ -42,118 +58,78 @@ } \ } -widget_t *get_active_widget(dialogue_t *d) { - group_t *g; - if (d->active.type == g_action) { - g = d->g_action; - } else { - g = d->g_content; - } - widget_t *w = (widget_t *)g->elements[d->active.id - g->first_id].element; - return w; -} - void dialogue_default_callback(callback_args_t *args) { dialogue_t *d = (void *)args->element; int32_t key = *((int32_t *)args->data); callback_args_t new_args; - int32_t *resp_value = (int32_t *)args->resp_data; memcpy(&new_args, args, sizeof(callback_args_t)); - new_args.active_id = d->active.id; + new_args.active_el = d->active_el; int32_t diff; d->needs_update = true; input_t *input; widget_t *widget; switch (key) { case '\t': - if (d->active.type == g_content) { - 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; + incr_active_id(d); + args->resp_data.code = cbrc_none; break; case '\33': /* Esc key */ - *resp_value = -2; + args->resp_data.code = cbrp_val; + args->resp_data.val.val.num = -2; break; case KEY_RIGHT: - if (d->active.type == g_content) { - if (d->g_content->elements[d->active.id - d->g_content->first_id].type == - w_input) { - input = d->g_content->elements[d->active.id - d->g_content->first_id] - .element; - if (input->cur_pos > 0) { - input->cur_pos -= 1; - } - } else { - 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; + incr_active_id(d); + args->resp_data.code = cbrc_none; break; case KEY_LEFT: - if (d->active.type == g_content) { - if (d->g_content->elements[d->active.id - d->g_content->first_id].type == - w_input) { - input = d->g_content->elements[d->active.id - d->g_content->first_id] - .element; - if (input->value_len > input->cur_pos) { - input->cur_pos += 1; - } - } else { - DECR_ACTIVE_ID(d, g_content, g_action); - } - } else if (d->active.type == g_action) { - DECR_ACTIVE_ID(d, g_action, g_content); - } - *resp_value = -1; + decr_active_id(d); + args->resp_data.code = cbrc_none; break; case '\n': - widget = get_active_widget(d); + widget = (widget_t *)d->active_el->element; if (widget->callback != NULL) { /* Existing callback case */ new_args.element = widget; widget->callback(&new_args); break; } /* Default cases */ - if (d->active.type == g_action) { + 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)); } else if (d->g_action != NULL) { for (int i = 0; i < d->g_action->count; i++) { if (d->g_action->elements[i].is_default) { - *resp_value = i; + args->resp_data.code = cbrp_val; + args->resp_data.val.val.num = i; return; } } } else { - /* TODO: temp solution, improve */ - *resp_value = d->active.id - d->g_content->first_id; + args->resp_data.code = cbrp_val; + args->resp_data.val.val.num = d->active_el->idx; return; } break; case KEY_UP: - if (d->g_content->elements[d->active.id - d->g_content->first_id].type == - w_fs_file_list) { + if (d->active_el->type == w_fs_file_list) { new_args.element = d->g_content; group_default_callback(&new_args); } else { - CH_GROUP(d, g_action, g_content); + /* CH_GROUP(d, g_action, g_content); */ } break; case KEY_DOWN: - if (d->g_content->elements[d->active.id - d->g_content->first_id].type == - w_fs_file_list) { + if (d->active_el->type == w_fs_file_list) { new_args.element = d->g_content; group_default_callback(&new_args); } else { - CH_GROUP(d, g_content, g_action); + /* CH_GROUP(d, g_content, g_action); */ } break; default: /* run callback function */ - if (d->active.type == g_content) { + if (d->active_el->g_type == g_content) { new_args.element = d->g_content; } else { new_args.element = d->g_action; @@ -178,67 +154,42 @@ void init_dialogue(dialogue_t *dialogue, const char title[], const char text[], strcpy(dialogue->w.title, title); t_size = strlen(text); strcpy(dialogue->text, text); + init_d_arr_ptr(&(dialogue->id_map), MAX_IDS); /* trim the last new line symbol */ - if (t_size && dialogue->text[t_size-1] == '\n') dialogue->text[t_size-1] = '\0'; + if (t_size && dialogue->text[t_size - 1] == '\n') + dialogue->text[t_size - 1] = '\0'; +} + +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) { - enum w_type widget_type; - 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.type = g_content; - widget_t *w = (widget_t *)dialogue->g_content->elements[i].element; - dialogue->active.id = w->id; - 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.type = g_action; - widget_t *w = (widget_t *)dialogue->g_action->elements[i].element; - dialogue->active.id = w->id; - return; - } + if (group_init_active_id(dialogue->g_action, dialogue)) { + return; } } } -// void dialogue_init_active_id(dialogue_t *dialogue) { -// enum w_type widget_type; - -// 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.type = g_content; -// widget_t *w = (widget_t *)dialogue->g_content->elements[i].element; -// dialogue->active.id = w->id; -// break; -// } -// } -// } else 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.type = g_action; -// widget_t *w = (widget_t *)dialogue->g_action->elements[i].element; -// dialogue->active.id = w->id; -// break; -// } -// } -// } -// } - #define DETECT_GROUP_SIZE(group, line_max_len, y, x) \ if (group) { \ group->w.m_y = y; \ @@ -259,7 +210,6 @@ int32_t draw_dialogue(dialogue_t *d) { } group_el_t *ae_ptr = NULL; /* active element */ - uint32_t ae_idx; /* active element */ /* count dimensions */ uint32_t x = 1; /* when uses box */ uint32_t y = 1; /* when uses box */ @@ -317,33 +267,25 @@ int32_t draw_dialogue(dialogue_t *d) { wattroff(d->win, A_REVERSE); if (d->g_content != NULL) { - draw_group(d->win, d->g_content, d->active.id, &(d->w)); + draw_group(d->win, d->g_content, d->active_el->id); } if (d->g_action != NULL) { - draw_group(d->win, d->g_action, d->active.id, &(d->w)); + draw_group(d->win, d->g_action, d->active_el->id); } /* move cursor */ - if (d->g_content != NULL) { - FIND_ACTIVE_ELEMENT(d->g_content, d->active.id, ae_ptr, ae_idx); - } - if (ae_ptr == NULL && d->g_action != NULL) { - FIND_ACTIVE_ELEMENT(d->g_action, d->active.id, ae_ptr, ae_idx); - } - - if (ae_ptr != NULL && ae_ptr->id == d->active.id) { - if (ae_ptr->type == w_input) { - input_t *input = ae_ptr->element; - d->w.cur.y = input->w.cur.y; - d->w.cur.x = input->w.cur.x + input->value_len; - d->w.cur.x -= input->cur_pos; - if (d->w.cur.y || d->w.cur.x) { - wmove(d->win, d->w.cur.y, d->w.cur.x); - curs_set(true); - } - } else { - curs_set(false); + if (d->active_el != NULL && d->active_el->type == w_input) { + input_t *input = d->active_el->element; + d->w.cur.y = input->w.cur.y; + d->w.cur.x = input->w.cur.x + input->value_len; + d->w.cur.x -= input->cur_pos; + if (d->w.cur.y || d->w.cur.x) { + wmove(d->win, d->w.cur.y, d->w.cur.x); + curs_set(true); } + + } else { + curs_set(false); } d->needs_update = false; diff --git a/src/widget/dialogue.h b/src/widget/dialogue.h index 895a120..3d7f017 100644 --- a/src/widget/dialogue.h +++ b/src/widget/dialogue.h @@ -6,8 +6,9 @@ #include #include #include +#include +#define MAX_IDS 64 -enum g_type { g_content, g_action }; enum d_color_scheme { dc_normal, dc_alert }; typedef struct { @@ -15,16 +16,14 @@ typedef struct { WINDOW *win; group_t *g_content; group_t *g_action; - struct { - int32_t id; - enum g_type type; - } active; + group_el_t *active_el; char text[DIALOGUE_TEXT]; - uint32_t is_initiated : 1; - uint32_t needs_update : 1; - uint32_t needs_destroy : 1; + bool is_initiated; + bool needs_update; + bool needs_destroy; coordinates_t *p_coordinates; enum d_color_scheme color_scheme; + d_array_ptr_t id_map; } dialogue_t; void init_dialogue(dialogue_t *d, const char title[], const char text[], diff --git a/src/widget/file_list.c b/src/widget/file_list.c index 3156e18..e4ed0dc 100644 --- a/src/widget/file_list.c +++ b/src/widget/file_list.c @@ -114,6 +114,8 @@ ui_file_list_t *init_file_list(WINDOW **win, WINDOW *const *info_win) { fui->max_lines = getmaxy(parent_win) - 3; /* 2+1 (bottom info line) */ fui->active_search = false; fui->search_key = bfromcstrrangealloc(12, 64, ""); + fui->start = NULL; + fui->current = NULL; return fui; } @@ -135,11 +137,16 @@ void draw_file_list(ui_file_list_t *fui) { int32_t sz_y_f = sz_y - 2; /* TODO: можно заменить на поле max_lines */ p_y = 1; p_x = 1; - fl_item_t *el = *(fui->start); - fl_item_t *active_el = *(fui->start); + fl_item_t *el = NULL; + fl_item_t *active_el = NULL; int32_t cur_el_idx = 0; curs_set(false); + if (fui->start != NULL) { + el = *(fui->start); + active_el = el; + } + if (fui->activate_last) { fui->current_idx = fui->current_count - 1; fui->activate_last = false; diff --git a/src/widget/fs_file_list.c b/src/widget/fs_file_list.c index 5983045..c68924e 100644 --- a/src/widget/fs_file_list.c +++ b/src/widget/fs_file_list.c @@ -133,7 +133,7 @@ void fs_file_list_cb(callback_args_t *args) { } break; case '\n': - select_item(fui, (int32_t *) args->resp_data); + select_item(fui, (int32_t *) args->resp_data.val.val.num); break; } } diff --git a/src/widget/group.c b/src/widget/group.c index c8b5971..ba29455 100644 --- a/src/widget/group.c +++ b/src/widget/group.c @@ -1,37 +1,33 @@ #include "group.h" #include "button.h" +#include "d_array.h" #include "fs_file_list.h" #include "input.h" #include "progress_bar.h" +#include "widget_core.h" #include #include #include #include #include - -#define MAKE_RESPONSE_M1(args, resp_data, response) \ - if (args->resp_data != NULL) { \ - *response = -1; \ - } +#include void group_default_callback(callback_args_t *args) { group_t *g = (group_t *)args->element; int32_t key = *((int32_t *)args->data); - int32_t *response = (int32_t *)args->resp_data; + int64_t response = args->resp_data.val.val.num; input_t *input; widget_t *widget; - group_el_t *element_ptr; - int32_t element_idx = -1; + group_el_t *element_ptr = args->active_el; u_int32_t start_pos = 0; callback_args_t new_args; switch (key) { case '\n': /* Enter */ - FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx); - *response = element_idx; + args->resp_data.code = cbrp_val; + mempcpy(&(args->resp_data.val), &(element_ptr->val), sizeof(struct val_t)); break; case KEY_BACKSPACE: case KEY_DL: - 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) { @@ -44,10 +40,9 @@ void group_default_callback(callback_args_t *args) { } } } - MAKE_RESPONSE_M1(args, resp_data, response); + args->resp_data.code = cbrc_none; break; default: - 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) { @@ -62,7 +57,8 @@ void group_default_callback(callback_args_t *args) { } } } else { - widget = (widget_t *) element_ptr->element; + /* callback case */ + widget = (widget_t *)element_ptr->element; if (widget->callback != NULL) { memccpy(&new_args, args, 1, sizeof(callback_args_t)); new_args.element = element_ptr->element; @@ -70,14 +66,22 @@ void group_default_callback(callback_args_t *args) { break; } } - MAKE_RESPONSE_M1(args, resp_data, response); + args->resp_data.code = cbrc_none; break; } } +union current_element { + group_t *group; + enum w_type type; +}; + group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children, - enum g_direction direction) { + 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, ""); /* count elements */ group->count = 0; @@ -93,6 +97,9 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children, for (int32_t i = 0; i < group->count; i++) { elements[i].type = children[i].type; elements[i].is_default = children[i].is_default; + elements[i].g_type = g_type; + elements[i].idx = i; + elements[i].val.type = val_nul; } /* init child elements */ @@ -101,12 +108,27 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children, switch (elements[i].type) { case w_button: elements[i].element = init_button(win, &(group->w), children[i].label); + elements[i].val.type = val_num; + elements[i].val.val.num = children[i].val.num; w = &(((button_t *)elements[i].element)->w); break; case w_box: - case w_group: case w_end: break; + case w_group: + elements[i].element = init_group(win, &(group->w), children[i].children, + id_map, children[i].direction, g_type); + w = &(((group_t *)elements[i].element)->w); + current.group = (group_t *)elements[i].element; + current.group->parent_group = group; + if (i == 0) { + group->first_id = current.group->first_id; + group->last_id = current.group->last_id; + } else { + group->last_id = current.group->last_id; + } + current.type = w_group; + break; case w_input: elements[i].element = init_input(win, &(group->w), children[i].label, children[i].length, @@ -122,28 +144,39 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children, w = &(((ui_progress_bar_t *)elements[i].element)->w); break; } + if (current.type != w_group) { + if (i == 0) { + group->first_id = w->id; + group->last_id = w->id; + } else { + group->last_id = w->id; + } + } /* set dimensions */ 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; - } - if (i == 0) { - group->first_id = w->id; - group->last_id = w->id; } else { - group->last_id = w->id; + 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; } } + if (direction == vertical) + group->w.y++; + return group; } -void draw_group(WINDOW *win, group_t *group, int32_t active_id, - widget_t *dialog_w) { +void draw_group(WINDOW *win, group_t *group, int32_t active_id) { group_el_t *children = group->elements; for (int i = 0; i < group->count; i++) { group_el_t *el = &children[i]; @@ -151,8 +184,10 @@ void draw_group(WINDOW *win, group_t *group, int32_t active_id, case w_button: draw_button((button_t *)el->element, active_id); break; - case w_box: case w_group: + draw_group(win, (group_t *)el->element, active_id); + break; + case w_box: case w_end: break; case w_input: @@ -176,8 +211,10 @@ void destroy_group(group_t *group) { case w_button: destroy_button(el->element); break; - case w_box: case w_group: + destroy_group(el->element); + break; + case w_box: case w_end: break; case w_input: diff --git a/src/widget/group.h b/src/widget/group.h index e7cf353..fb7cc40 100644 --- a/src/widget/group.h +++ b/src/widget/group.h @@ -2,44 +2,35 @@ #define GROUP_H #include +#include #include -enum g_direction { - horizontal, - vertical, -}; - -typedef struct { - uint32_t id; - void *element; +typedef struct group_el_init_t { enum w_type type; - uint32_t is_default : 1; -} group_el_t; - -typedef struct { - enum w_type type; - uint32_t is_default : 1; - uint32_t is_hidden_value : 1; + bool is_default; + bool is_hidden_value; char label[DIALOGUE_TITLE]; uint32_t length; + enum g_direction direction; + union { + int64_t num; + } val; + struct group_el_init_t *children; } group_el_init_t; -typedef struct { +typedef struct group_t { widget_t w; group_el_t *elements; enum g_direction direction; uint32_t count; uint32_t first_id, last_id; + struct group_t *parent_group; } group_t; -#define FIND_ACTIVE_ELEMENT(g, active_id, element_ptr, element_idx) \ - element_idx = active_id - g->first_id; \ - element_ptr = &(g->elements[element_idx]); - 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, - widget_t *dialog_w); + d_array_ptr_t *id_map, enum g_direction dir, + enum g_type g_type); +void draw_group(WINDOW *win, group_t *group, int32_t active_id); void destroy_group(group_t *group); void group_default_callback(callback_args_t *args); diff --git a/src/widget/input.c b/src/widget/input.c index 518884a..75c7d11 100644 --- a/src/widget/input.c +++ b/src/widget/input.c @@ -4,16 +4,16 @@ #include #include "app.h" -#include #include "input.h" +#include input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, uint32_t length, uint32_t is_hidden_value) { 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.y = 3; // with borders + input->w.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; @@ -29,16 +29,26 @@ 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 + input->w.w_parent->m_y; - uint32_t margin_x = input->w.m_x + input->w.w_parent->m_x; + uint32_t margin_y = input->w.m_y; + uint32_t margin_x = input->w.m_x; - wattrset(win, COLOR_PAIR(modal_color_pair)); + /* 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; + w_par = w_par->w_parent; + } + + 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); @@ -48,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) { @@ -57,13 +70,13 @@ 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, ""); + mvwprintw(win, margin_y + 1, margin_x, "%.*s%*s", (int)input->value_len, + 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; input->w.cur.x = margin_x; diff --git a/src/widget/input.h b/src/widget/input.h index 2409eec..54b2707 100644 --- a/src/widget/input.h +++ b/src/widget/input.h @@ -8,11 +8,11 @@ typedef struct { widget_t w; char value[INPUT_TEXT]; - uint32_t cur_pos; /* is relative to the end of a string */ - uint32_t value_len; - uint32_t max_len; - uint32_t is_disabled : 1; - uint32_t is_hidden : 1; + int64_t cur_pos; /* is relative to the end of a string */ + int64_t value_len; + int64_t max_len; + bool is_disabled; + bool is_hidden; } input_t; input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, diff --git a/src/widget/widget.h b/src/widget/widget.h index 2582210..2d7bb7a 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -8,5 +8,4 @@ #include "group.h" #include "input.h" #include "progress_bar.h" - #endif \ No newline at end of file diff --git a/src/widget_core/widget_core.h b/src/widget_core/widget_core.h index 3a07e09..d058c83 100644 --- a/src/widget_core/widget_core.h +++ b/src/widget_core/widget_core.h @@ -5,6 +5,13 @@ #include #include +enum g_type { g_content, g_action }; + +enum g_direction { + horizontal, + vertical, +}; + enum w_type { w_end, w_button, @@ -15,12 +22,46 @@ enum w_type { w_fs_file_list, }; +enum val_type { + val_num, + val_ptr, + val_nul, +}; + +struct val_t { + enum val_type type; + union { + void *ptr; + int64_t num; + } val; +}; + +typedef struct { + int64_t id; + int64_t idx; /* element index in the group */ + void *element; + enum w_type type; + enum g_type g_type; + bool is_default; + struct val_t val; +} group_el_t; + +enum cbrp_code { + cbrc_none, /* default */ + cbrp_val, + cbrp_g_el, /* element of type group_el_t */ + cbrp_err +}; + typedef struct { void *app; void *element; void *data; - void *resp_data; - uint32_t active_id; + struct { + enum cbrp_code code; + struct val_t val; + } resp_data; + void *active_el; } callback_args_t; enum rsize { @@ -34,19 +75,18 @@ enum rsize { }; typedef struct widget_t { - uint32_t id; + int64_t id; char title[DIALOGUE_TITLE]; - uint32_t x; - uint32_t y; - uint32_t m_x; - uint32_t m_y; + int64_t x; + int64_t y; + int64_t m_x; + int64_t m_y; struct { - uint32_t y; - uint32_t x; + int64_t y; + int64_t x; } cur; WINDOW *const *parent_win; struct widget_t *w_parent; - // enum rsize rsize; void (*callback)(callback_args_t *args); } widget_t; @@ -59,7 +99,8 @@ enum pmt_attrs { void init_widget(widget_t *w, widget_t *w_parent, WINDOW **win, char *title); int32_t get_max_line_len(const char *text, uint32_t *line_count); -uint32_t print_multiline_text(WINDOW *win, const char *text, const uint32_t win_width, const uint32_t y, +uint32_t print_multiline_text(WINDOW *win, const char *text, + const uint32_t win_width, const uint32_t y, const uint32_t x, const uint16_t attrs); #endif \ No newline at end of file