diff --git a/TODO.md b/TODO.md index d1055a9..6550923 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,9 @@ # TODO: ## Current: +- [ ] Login and registration error - [ ] PageUp/PageDown key functionality in lists -- [ ] File upload multiline description +- [ ] File upload multiline description (window) - [ ] Permission checkboxes for file upload/edit - [ ] More intuitive navigation between nested groups (by pressing left and right buttons) diff --git a/src/draw_modal.c b/src/draw_modal.c index eb94c42..72bc1bb 100644 --- a/src/draw_modal.c +++ b/src/draw_modal.c @@ -36,19 +36,7 @@ void app_draw_modal(app_t *app) { case S_UPLOAD_PARAMS: init_upload_props_dialogue_modal(app); break; - case WAIT_SERVER_INIT: - case WAIT_SERVER: - case WAIT_REGISTER: - case WAIT_REGISTER_CONFIRMATION: - case WAIT_CLIENT: - case S_FILE_LIST: - case S_FILE_SELECT: - case S_UPLOAD_REQUESTED: - case S_ASK_USER_BEFORE_LOGIN: - case S_ERR: - case S_WAIT_SERVER: - case S_N_D: - case S_NEXT_ACTION: + default: if (app->query_args->notification != NULL) { init_notification_modal(app); } else { diff --git a/src/modals/upload_props_dialogue.c b/src/modals/upload_props_dialogue.c index 1b4ba46..7b3f8bb 100644 --- a/src/modals/upload_props_dialogue.c +++ b/src/modals/upload_props_dialogue.c @@ -1,11 +1,12 @@ #include "group.h" -#include +#include "widget_core.h" #include #include #include #include #include #include +#include void upload_props_dialogue_modal_cb(callback_args_t *args) { callback_args_t d_args; @@ -18,9 +19,10 @@ void upload_props_dialogue_modal_cb(callback_args_t *args) { char query[256]; int32_t query_len = 0; input_t *desc_input = (input_t *)d->g_content->elements[0].element; + /* TODO: permissions */ if (d_args.resp_data.code == cbrp_val) { switch (d_args.resp_data.val.val.num) { - case 0: + case 1: query_len = sprintf(query, "file upload \"%s\" %zu 1\n", app->query_args->file->name, app->query_args->file->size); @@ -31,7 +33,7 @@ void upload_props_dialogue_modal_cb(callback_args_t *args) { app->query_args->state = S_UPLOAD_REQUESTED; write(app->query_args->sd, query, query_len); break; - case 1: + case 2: if (app->query_args->file->name != NULL) free(app->query_args->file->name); if (app->query_args->file->path != NULL) @@ -48,12 +50,15 @@ dialogue_t *init_upload_props_dialogue_modal(app_t *app) { if (app == NULL) return NULL; group_el_init_t content[] = { - {.type = w_input, .label = "File description", .length = 30}, + {.type = w_checkbox, .label = "Visible for all", .is_default = true}, + {.type = w_checkbox, + .label = "Visible for registered", + .is_default = false}, {.type = w_end}}; group_el_init_t actions[] = { - {.type = w_button, .label = "Upload", .is_default = true}, - {.type = w_button, .label = "Cancel", .is_default = false}, + {.type = w_button, .label = "Upload", .is_default = false, .val.num = 1}, + {.type = w_button, .label = "Cancel", .is_default = false, .val.num = 2}, {.type = w_end}, }; @@ -63,8 +68,10 @@ 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, &(d->id_map), horizontal, g_content); - d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), horizontal, g_action); + 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 e0864dd..2807d5c 100644 --- a/src/query.c +++ b/src/query.c @@ -45,10 +45,8 @@ 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.code = cbrc_none}; + 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; @@ -183,12 +181,7 @@ int process_query(app_t *app) { case WAIT_REGISTER: wait_register(query_args); break; - case S_ASK_SEVER_IP: - case S_ASK_LOGIN_TYPE: - case S_N_D: - case S_ASK_LOGIN_USER: - case S_PRINT_SERVER_MESSAGE: - case S_UPLOAD_FILE_SELECT: + default: break; } return 0; diff --git a/src/server.c b/src/server.c index 150beb8..a6fd9a9 100644 --- a/src/server.c +++ b/src/server.c @@ -62,13 +62,13 @@ int process_server_command(char *line, int l_len, app_t *app) { } /* LOGIN AGAIN */ - if (!strncmp(line, "login_again>", ws_pos)) { + if (!strncmp(line, "login_again>\n", ws_pos)) { + alert("Incorrect credentials! Try again"); free(params->uname); free(params->pass); params->uname = NULL; params->pass = NULL; - // get_missing_params(params); - write(q_args->sd, params->uname, strlen(params->uname)); + q_args->state = S_ASK_LOGIN_USER; return 0; } diff --git a/src/widget/button.h b/src/widget/button.h index aacb19d..57d49d2 100644 --- a/src/widget/button.h +++ b/src/widget/button.h @@ -6,7 +6,7 @@ typedef struct { widget_t w; - char hotkey; + int32_t hotkey; uint32_t is_disabled : 1; } button_t; diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c new file mode 100644 index 0000000..1890642 --- /dev/null +++ b/src/widget/checkbox.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +#include "app.h" +#include "checkbox.h" +#include + +bool checkbox_default_key_action(callback_args_t *args) { + int32_t key = *((int32_t *)args->data); + group_el_t *g_el = args->active_el; + checkbox_t *cbx = g_el->element; + switch (key) { + case '\40': + cbx->value = !cbx->value; + break; + default: + break; + } + return true; +} + +checkbox_t *init_checkbox(WINDOW **win, widget_t *w_parent, char *label) { + checkbox_t *cbx = malloc(sizeof(checkbox_t)); + init_widget(&(cbx->w), w_parent, win, label); + cbx->is_disabled = false; + cbx->value = false; + cbx->w.sz.x = strlen(cbx->w.title) + 4; // + "[ ] " + cbx->w.sz.y = 1; + cbx->w.cur.y = 0; + cbx->w.cur.x = 1; + return cbx; +} + +int32_t draw_checkbox(checkbox_t *cbx, uint32_t active_id) { + char title[DIALOGUE_TITLE + 6]; + WINDOW *win = *(cbx->w.parent_win); + uint32_t margin_y = cbx->w.ps.y + cbx->w.m.y; + uint32_t margin_x = cbx->w.ps.x + cbx->w.m.x; + + widget_t *w_par = cbx->w.w_parent; + + while (w_par->parent_win == cbx->w.parent_win) { + margin_y += w_par->ps.y; + margin_x += w_par->ps.x; + w_par = w_par->w_parent; + } + + char val = cbx->value ? 'x' : ' '; + + if (cbx->w.id == active_id) { + sprintf(title, "[%c] %s", val, cbx->w.title); + wattrset(win, COLOR_PAIR(modal_color_pair) | A_BOLD | A_REVERSE); + } else { + sprintf(title, "[%c] %s", val, cbx->w.title); + wattrset(win, COLOR_PAIR(0) | A_REVERSE); + } + + mvwprintw(win, margin_y, margin_x, "%s", title); + cbx->w.cur.y = margin_y; + cbx->w.cur.x = margin_x + 1; + + wattroff(win, A_BOLD | A_REVERSE); + return strlen(title); +} + +void destroy_checkbox(checkbox_t *btn) { free(btn); } \ No newline at end of file diff --git a/src/widget/checkbox.h b/src/widget/checkbox.h new file mode 100644 index 0000000..60db01d --- /dev/null +++ b/src/widget/checkbox.h @@ -0,0 +1,17 @@ +#ifndef CHECKBOX_H +#define CHECKBOX_H + +#include +#include + +typedef struct { + widget_t w; + bool is_disabled; + bool value; +} checkbox_t; + +bool checkbox_default_key_action(callback_args_t *args); +checkbox_t *init_checkbox(WINDOW **win, widget_t *w_parent, char *label); +int32_t draw_checkbox(checkbox_t *cbx, uint32_t active_id); +void destroy_checkbox(checkbox_t *cbx); +#endif diff --git a/src/widget/dialogue.c b/src/widget/dialogue.c index dc678b2..7f50656 100644 --- a/src/widget/dialogue.c +++ b/src/widget/dialogue.c @@ -4,6 +4,8 @@ #include #include "app.h" +#include "button.h" +#include "checkbox.h" #include "dialogue.h" #include "file_list.h" #include "group.h" @@ -193,14 +195,14 @@ void dialogue_init_active_id(dialogue_t *dialogue) { #define DETECT_GROUP_SIZE(group, line_max_len, y, x) \ if (group) { \ - 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; \ + 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.ps.x = (line_max_len - group->w.sz.x) / 2; \ + group->w.ps.x = (line_max_len - group->w.sz.x) / 2; \ } \ - y += group->w.sz.y; \ + y += group->w.sz.y; \ } int32_t draw_dialogue(dialogue_t *d) { @@ -275,11 +277,11 @@ int32_t draw_dialogue(dialogue_t *d) { } /* move cursor */ - 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->active_el != NULL && + (d->active_el->type == w_input || d->active_el->type == w_checkbox)) { + widget_t *w = d->active_el->element; + d->w.cur.y = w->cur.y; + d->w.cur.x = w->cur.x; if (d->w.cur.y || d->w.cur.x) { wmove(d->win, d->w.cur.y, d->w.cur.x); curs_set(true); diff --git a/src/widget/group.c b/src/widget/group.c index bc8f98b..cd70423 100644 --- a/src/widget/group.c +++ b/src/widget/group.c @@ -1,5 +1,6 @@ #include "group.h" #include "button.h" +#include "checkbox.h" #include "d_array.h" #include "fs_file_list.h" #include "input.h" @@ -12,51 +13,31 @@ #include #include +bool group_default_key_action(callback_args_t *args) { + group_el_t *element = args->active_el; + switch (element->type) { + case w_input: + return input_default_key_action(args); + case w_checkbox: + return checkbox_default_key_action(args); + default: + return false; + } +} + void group_default_callback(callback_args_t *args) { - group_t *g = (group_t *)args->element; int32_t key = *((int32_t *)args->data); - int64_t response = args->resp_data.val.val.num; - input_t *input; widget_t *widget; group_el_t *element_ptr = args->active_el; - u_int32_t start_pos = 0; callback_args_t new_args; switch (key) { case '\n': /* Enter */ 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: - if (element_ptr->type == w_input) { - input = (input_t *)element_ptr->element; - if (input->value_len) { - if (input->cur_pos > 0) { - start_pos = input->value_len-- - input->cur_pos; - memmove(input->value + start_pos - 1, input->value + start_pos, - input->value_len - start_pos + 2); - } else { - input->value[--input->value_len] = '\0'; - } - } - } - args->resp_data.code = cbrc_none; + break; default: - if (element_ptr->type == w_input) { - input = (input_t *)element_ptr->element; - if (input->max_len > input->value_len) { - if (input->cur_pos > 0) { - start_pos = input->value_len++ - input->cur_pos; - memmove(input->value + start_pos + 1, input->value + start_pos, - input->value_len - start_pos); - input->value[start_pos] = key; - } else { - input->value[input->value_len++] = key; - input->value[input->value_len] = '\0'; - } - } - } else { + if (!group_default_key_action(args)) { /* callback case */ widget = (widget_t *)element_ptr->element; if (widget->callback != NULL) { @@ -145,6 +126,10 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children, elements[i].element = init_fs_file_list(win, &(group->w)); w = &(((ui_progress_bar_t *)elements[i].element)->w); break; + case w_checkbox: + elements[i].element = init_checkbox(win, &(group->w), children[i].label); + w = &(((checkbox_t *)elements[i].element)->w); + break; } if (current.type != w_group) { if (i == 0) { @@ -202,6 +187,9 @@ void draw_group(WINDOW *win, group_t *group, int32_t active_id) { case w_fs_file_list: draw_fs_file_list((ui_fs_file_list_t *)el->element); break; + case w_checkbox: + draw_checkbox((checkbox_t *)el->element, active_id); + break; } } } @@ -229,6 +217,9 @@ void destroy_group(group_t *group) { case w_fs_file_list: destroy_fs_file_list(el->element); break; + case w_checkbox: + destroy_checkbox(el->element); + break; } } if (group->elements != NULL) { diff --git a/src/widget/input.c b/src/widget/input.c index e8c5ea9..589aaca 100644 --- a/src/widget/input.c +++ b/src/widget/input.c @@ -7,13 +7,49 @@ #include "input.h" #include +bool input_default_key_action(callback_args_t *args) { + int32_t key = *((int32_t *)args->data); + group_el_t *g_el = args->active_el; + input_t *input = g_el->element; + int64_t start_pos = 0; + + switch (key) { + case KEY_BACKSPACE: + case KEY_DL: + if (input->value_len) { + if (input->cur_pos > 0) { + start_pos = input->value_len-- - input->cur_pos; + memmove(input->value + start_pos - 1, input->value + start_pos, + input->value_len - start_pos + 2); + } else { + input->value[--input->value_len] = '\0'; + } + } + break; + default: + if (input->cur_pos > 0) { + start_pos = input->value_len++ - input->cur_pos; + memmove(input->value + start_pos + 1, input->value + start_pos, + input->value_len - start_pos); + input->value[start_pos] = key; + } else { + input->value[input->value_len++] = key; + input->value[input->value_len] = '\0'; + } + break; + } + args->resp_data.code = cbrc_none; + return true; +} + 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.sz.y = 3; // with borders - input->w.sz.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.sz.x < t_len) input->w.sz.x = t_len; @@ -70,15 +106,15 @@ int32_t draw_input(input_t *input, uint32_t active_id) { } if (input->is_hidden) { - mvwprintw(win, pos_y + 1, pos_x, "%.*s%*s", (int)input->value_len, - stars, (int)(input->w.sz.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, pos_y + 1, pos_x, "%s%*s", input->value, (int)(input->w.sz.x - input->value_len - 2), ""); } input->w.cur.y = pos_y + 1; - input->w.cur.x = pos_x; + input->w.cur.x = pos_x + input->value_len - input->cur_pos; wattroff(win, A_BOLD | A_REVERSE); return 0; diff --git a/src/widget/input.h b/src/widget/input.h index 54b2707..4fcfe2a 100644 --- a/src/widget/input.h +++ b/src/widget/input.h @@ -15,6 +15,7 @@ typedef struct { bool is_hidden; } input_t; +bool input_default_key_action(callback_args_t *args); input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, uint32_t size, uint32_t is_hidden_value); int32_t draw_input(input_t *input, uint32_t active_id); diff --git a/src/widget/widget.h b/src/widget/widget.h index 2d7bb7a..68ff5a8 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -8,4 +8,5 @@ #include "group.h" #include "input.h" #include "progress_bar.h" +#include "checkbox.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 7e81ee5..c172c97 100644 --- a/src/widget_core/widget_core.h +++ b/src/widget_core/widget_core.h @@ -18,6 +18,7 @@ enum w_type { w_box, w_group, w_input, + w_checkbox, w_progress, w_fs_file_list, };