From 1f8523635165d150a38a4b9781063ab2a67b9b64 Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Tue, 9 Dec 2025 20:41:26 +0200 Subject: [PATCH] implementation of input --- src/deps.mk | 7 +-- src/main.c | 16 +++--- src/main.h | 1 + src/ui/app.h | 1 + src/ui/modals/ask_server_addr.c | 46 ++++++++++++++++ src/ui/modals/ask_server_addr.h | 9 ++++ src/ui/widget.c | 23 +++++++- src/ui/widget.h | 11 ++++ src/ui/widget/dialogue.c | 4 +- src/ui/widget/dialogue.h | 2 +- src/ui/widget/group.c | 93 +++++++++++++++++++++++++++------ src/ui/widget/group.h | 1 + src/ui/widget/input.c | 69 ++++++++++++++++++++++++ src/ui/widget/input.h | 19 +++++++ 14 files changed, 273 insertions(+), 29 deletions(-) create mode 100644 src/ui/modals/ask_server_addr.c create mode 100644 src/ui/modals/ask_server_addr.h create mode 100644 src/ui/widget/input.c create mode 100644 src/ui/widget/input.h diff --git a/src/deps.mk b/src/deps.mk index 1b3488f..d3e8ba8 100644 --- a/src/deps.mk +++ b/src/deps.mk @@ -6,9 +6,10 @@ file_processor.o: src/file_processor.c src/client.h src/main.h \ main.o: src/main.c src/connection.h src/main.h src/types.h src/ui/app.h \ src/ui/widget/dialogue.h src/ui/widget/../widget.h \ src/ui/widget/../../main.h src/ui/widget/button.h \ - src/ui/widget/../../main.h src/ui/widget/group.h src/ui/modals/login.h \ - src/ui/modals/../widget/dialogue.h src/ui/modals/../app.h \ - src/ui/widget.h src/ui/widget/dialogue.h + src/ui/widget/../../main.h src/ui/widget/group.h \ + src/ui/modals/ask_server_addr.h src/ui/modals/../app.h \ + src/ui/modals/../widget/dialogue.h src/ui/modals/login.h src/ui/widget.h \ + src/ui/widget/dialogue.h query.o: src/query.c src/file_processor.h src/main.h src/types.h \ src/connection.h src/client.h src/server.h server.o: src/server.c src/client.h src/main.h src/types.h \ diff --git a/src/main.c b/src/main.c index 697ef65..0e855c6 100644 --- a/src/main.c +++ b/src/main.c @@ -12,6 +12,7 @@ #include "connection.h" #include "main.h" #include "ui/app.h" +#include "ui/modals/ask_server_addr.h" #include "ui/modals/login.h" #include "ui/widget.h" #include "ui/widget/dialogue.h" @@ -37,7 +38,7 @@ int main(int argc, char **argv) { wrefresh(app->right_win); // temporal - app->modal.type = login; + app->modal.type = ask_server_addr; event_loop(app); @@ -62,12 +63,12 @@ void event_loop(app_t *app) { for (;;) { c = wgetch(app->win); switch (c) { - // 113 is q key. This exits the program - case 113: + // 113 is q key. This exits the program + case 113: return; - case KEY_F(9): + case KEY_F(9): return; - default: + default: if (app->modal.type != none) { d_args.win = app->modal.dialogue.win; d_args.widget = &(app->modal.dialogue); @@ -102,11 +103,14 @@ void app_draw_modal(app_t *app) { case login: init_login_modal(app); break; + case ask_server_addr: + init_asa_modal(app); + break; case none: default: break; } - draw_dialogue(&(app->modal.dialogue)); + draw_dialogue(NULL, &(app->modal.dialogue)); } } diff --git a/src/main.h b/src/main.h index 9aed41c..401df1a 100644 --- a/src/main.h +++ b/src/main.h @@ -12,6 +12,7 @@ #define DOWNLOADS_DIR "./Downloads" #define DIALOGUE_TITLE 64 #define DIALOGUE_TEXT 128 +#define INPUT_TEXT DIALOGUE_TITLE typedef struct params { unsigned short port; diff --git a/src/ui/app.h b/src/ui/app.h index 31c7a67..f455242 100644 --- a/src/ui/app.h +++ b/src/ui/app.h @@ -12,6 +12,7 @@ typedef enum { typedef enum { none = 0, login = 1, + ask_server_addr = 2, } dialogue_e; typedef struct { diff --git a/src/ui/modals/ask_server_addr.c b/src/ui/modals/ask_server_addr.c new file mode 100644 index 0000000..98d0956 --- /dev/null +++ b/src/ui/modals/ask_server_addr.c @@ -0,0 +1,46 @@ +#include "../app.h" +#include "../widget/dialogue.h" +#include "../widget/group.h" +#include +#include + +typedef struct { + button_t *element; + enum w_type type; +} group_bt_t; + +void asa_modal_group_callback(callback_args_t *args) { + group_resp_t *response = (group_resp_t *)args->resp_data; + callback_args_t ch_args; + memcpy(&ch_args, args, sizeof(callback_args_t)); + ch_args.app = NULL; + group_default_callback(&ch_args); + if (response->value > -1) { + switch (response->value) { + case 0: + // exit(10); + case 1: + // exit(11); + case 2: + // exit(12); + } + } +} + +dialogue_t *init_asa_modal(app_t *app) { + if (app == NULL) + return NULL; + group_el_init_t children[] = { + {.type = w_input, .label = "Address", .length = 15}, + {.type = w_input, .label = "Port", .length = 5}, + {.type = w_end}}; + + init_dialogue(&(app->modal.dialogue), "Connect to server", + "There is information needed", app->cur_y, app->cur_x); + app->modal.dialogue.ch_group = + init_group(&(app->modal.dialogue.win), &(app->modal.dialogue.w), children, + horizontal); + app->modal.dialogue.ch_group->w.callback = asa_modal_group_callback; + + return NULL; +} \ No newline at end of file diff --git a/src/ui/modals/ask_server_addr.h b/src/ui/modals/ask_server_addr.h new file mode 100644 index 0000000..7b741a8 --- /dev/null +++ b/src/ui/modals/ask_server_addr.h @@ -0,0 +1,9 @@ +#ifndef ASK_SERVER_ADDR_H +#define ASK_SERVER_ADDR_H + +#include "../app.h" +#include "../widget/dialogue.h" + +dialogue_t *init_asa_modal(app_t *app); + +#endif \ No newline at end of file diff --git a/src/ui/widget.c b/src/ui/widget.c index 492aba1..914269f 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c @@ -5,6 +5,7 @@ #include extern uint32_t m_id; +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++; @@ -35,7 +36,8 @@ int32_t get_max_line_len(const char *text, uint32_t *line_count) { line_num++; } } - if (line_count != NULL) *line_count = line_num; + if (line_count != NULL) + *line_count = line_num; if (c_len > m_len) { return c_len; } else { @@ -80,4 +82,23 @@ uint32_t print_multiline_text(WINDOW *win, const char *text, PRINT_TEXT(win, l_buf, text, i, c_line_len, win_width, line_v_pos, attrs) return 1; +} + +int32_t rsize_to_value(int32_t size, enum rsize rsize) { + switch (rsize) { + case s_auto: + return size; + case s_1: + return size; + case s_1_2: + return size / 2; + case s_1_3: + return size / 3; + case s_2_3: + return size / 3 * 2; + case s_1_4: + return size / 4; + case s_3_4: + return size / 4 * 3; + } } \ No newline at end of file diff --git a/src/ui/widget.h b/src/ui/widget.h index 980b111..99b18d5 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -21,6 +21,16 @@ typedef struct { void *resp_data; } callback_args_t; +enum rsize { + s_auto, + s_1, + s_1_2, + s_1_3, + s_2_3, + s_1_4, + s_3_4, +}; + typedef struct widget_t { uint32_t id; char title[DIALOGUE_TITLE]; @@ -30,6 +40,7 @@ typedef struct widget_t { uint32_t m_y; WINDOW *const *parent_win; struct widget_t *w_parent; + enum rsize rsize; void (*callback)(callback_args_t *args); } widget_t; diff --git a/src/ui/widget/dialogue.c b/src/ui/widget/dialogue.c index 3b3dc5d..391cec1 100644 --- a/src/ui/widget/dialogue.c +++ b/src/ui/widget/dialogue.c @@ -24,7 +24,7 @@ void dialogue_default_callback(callback_args_t *args) { destroy_dialogue(d); app->modal.type = none; } else { - draw_dialogue(d); + draw_dialogue(NULL, d); } } } @@ -43,7 +43,7 @@ void init_dialogue(dialogue_t *dialogue, const char title[], const char text[], strcpy(dialogue->text, text); } -int32_t draw_dialogue(dialogue_t *d) { +int32_t draw_dialogue(void *e, dialogue_t *d) { if (!d->is_initiated) return -1; /* count dimensions */ uint32_t x = 1; /* when uses box */ diff --git a/src/ui/widget/dialogue.h b/src/ui/widget/dialogue.h index 1b5196b..8b6d45a 100644 --- a/src/ui/widget/dialogue.h +++ b/src/ui/widget/dialogue.h @@ -18,7 +18,7 @@ typedef struct { void init_dialogue(dialogue_t *d, const char title[], const char text[], uint32_t cur_x, uint32_t cur_y); -int32_t draw_dialogue(dialogue_t *d); +int32_t draw_dialogue(void *, dialogue_t *d); void destroy_dialogue(dialogue_t *d); void dialogue_default_callback(callback_args_t *args); diff --git a/src/ui/widget/group.c b/src/ui/widget/group.c index ed49232..06ae403 100644 --- a/src/ui/widget/group.c +++ b/src/ui/widget/group.c @@ -1,5 +1,6 @@ #include "group.h" #include "button.h" +#include "input.h" #include #include #include @@ -7,7 +8,8 @@ void group_default_callback(callback_args_t *args) { group_t *g = (group_t *)args->widget; char key = *((char *)args->data); - group_resp_t *response = (group_resp_t *) args->resp_data; + group_resp_t *response = (group_resp_t *)args->resp_data; + input_t *inpt; switch (key) { case '\t': if (g->active_id != g->last_id) { @@ -22,7 +24,7 @@ void group_default_callback(callback_args_t *args) { break; case '\n': if (args->resp_data != NULL) { - for (int i=0; i < g->count; i++) { + for (int i = 0; i < g->count; i++) { if (g->elements[i].id == g->active_id) { response->active_id = g->active_id; response->value = i; @@ -30,6 +32,40 @@ void group_default_callback(callback_args_t *args) { } } break; + case '\177': + for (int i = 0; i < g->count; i++) { + if (g->elements[i].id == g->active_id) { + if (g->elements[i].type == w_input) { + inpt = (input_t *)g->elements[i].element; + if (inpt->value_len) { + inpt->value[--inpt->value_len] = '\0'; + } + break; + } + } + } + if (args->resp_data != NULL) { + response->active_id = g->active_id; + response->value = -1; + } + break; + default: + for (int i = 0; i < g->count; i++) { + if (g->elements[i].id == g->active_id) { + if (g->elements[i].type == w_input) { + inpt = (input_t *)g->elements[i].element; + if (inpt->max_len > inpt->value_len) { + inpt->value[inpt->value_len++] = key; + inpt->value[inpt->value_len] = '\0'; + } + break; + } + } + } + if (args->resp_data != NULL) { + response->active_id = g->active_id; + response->value = -1; + } } } @@ -53,32 +89,37 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children, } /* init child elements */ - uint32_t el_id = 0; for (int i = 0; i < group->count; i++) { + widget_t *w; switch (elements[i].type) { case w_button: elements[i].element = init_button(win, &(group->w), children[i].label); - button_t *b = (button_t *)elements[i].element; - el_id = b->w.id; - elements[i].id = b->w.id; - if (direction == horizontal) { - b->w.m_x = group->w.x; - b->w.m_y = group->w.m_y; - group->w.x += b->w.x + 1; - if (group->w.y < b->w.y) - group->w.y = b->w.y; - } + w = &(((button_t *)elements[i].element)->w); break; case w_box: case w_group: case w_end: break; + case w_input: + elements[i].element = + init_input(win, &(group->w), children[i].label, children[i].length); + w = &(((input_t *)elements[i].element)->w); + break; + } + // set dimensions + elements[i].id = w->id; + if (direction == horizontal) { + w->m_x = 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 = el_id; - group->active_id = el_id; + group->first_id = w->id; + group->active_id = w->id; } else { - group->last_id = el_id; + group->last_id = w->id; } } @@ -97,6 +138,23 @@ void draw_group(WINDOW *win, group_t *group) { case w_group: case w_end: break; + case w_input: + draw_input((input_t *)el->element, group->active_id); + break; + } + } + for (int i = 0; i < group->count; i++) { + if (group->elements[i].id == group->active_id && + group->elements[i].type == w_input) { + input_t *input = group->elements[i].element; + uint32_t margin_y = input->w.m_y + input->w.w_parent->m_y; + uint32_t margin_x = input->w.m_x + input->w.w_parent->m_x + 1; + if (input->max_len == input->value_len) { + wmove(win, margin_y + 1, margin_x + input->value_len); + } else { + wmove(win, margin_y + 1, margin_x + input->value_len + 1); // x: +1: margin left from the border + } + curs_set(1); } } } @@ -113,6 +171,9 @@ void destroy_group(group_t *group) { case w_group: case w_end: break; + case w_input: + destroy_input(el->element); + break; } } if (group->elements != NULL) { diff --git a/src/ui/widget/group.h b/src/ui/widget/group.h index 5670d2a..fd88aa1 100644 --- a/src/ui/widget/group.h +++ b/src/ui/widget/group.h @@ -18,6 +18,7 @@ typedef struct { typedef struct { enum w_type type; char label[DIALOGUE_TITLE]; + uint32_t length; } group_el_init_t; typedef struct { diff --git a/src/ui/widget/input.c b/src/ui/widget/input.c new file mode 100644 index 0000000..374cd65 --- /dev/null +++ b/src/ui/widget/input.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +#include "../app.h" +#include "../widget.h" +#include "input.h" + +input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, + uint32_t length) { + 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 + 2; // with borders + uint32_t t_len = strlen(input->w.title) + 4; // with borders and space + if (input->w.x < t_len) + input->w.x = t_len; + input->w.m_x = 1; + input->value[0] = '\0'; + input->value_len = 0; + input->max_len = length; + return input; +} + +int32_t draw_input(input_t *input, uint32_t active_id) { + WINDOW *win = *(input->w.parent_win); + uint32_t margin_y = input->w.m_y + input->w.w_parent->m_y; + uint32_t margin_x = input->w.m_x + input->w.w_parent->m_x + 1; // +1: margin left from the border + + wattrset(win, COLOR_PAIR(MODAL_COLOR_PAIR)); + + 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); + mvwvline(win, margin_y + 2, margin_x, ACS_LLCORNER, 1); + // right + mvwvline(win, margin_y, margin_x + input->w.x-1, ACS_URCORNER, 1); + mvwvline(win, margin_y + 1, margin_x + input->w.x-1, 0, 1); + mvwvline(win, margin_y + 2, margin_x + input->w.x-1, ACS_LRCORNER, 1); + + // TODO: correct sizes (x) + + margin_x++; + + if (input->w.id == active_id) { + wattrset(win, COLOR_PAIR(MODAL_COLOR_PAIR) | A_BOLD | A_REVERSE); + } else { + wattrset(win, COLOR_PAIR(0) | A_BOLD); + } + + uint32_t x_c = 0; + mvwprintw(win, margin_y + 1, margin_x, "%s", input->value); + + for (int i = 0; i < input->w.x - input->value_len - 2; i++) { + mvwprintw(win, margin_y + 1, margin_x + i + input->value_len, " "); + } + + wattroff(win, A_BOLD | A_REVERSE); + return 0; +} + +void destroy_input(input_t *btn) { free(btn); } \ No newline at end of file diff --git a/src/ui/widget/input.h b/src/ui/widget/input.h new file mode 100644 index 0000000..a15f4c8 --- /dev/null +++ b/src/ui/widget/input.h @@ -0,0 +1,19 @@ +#ifndef INPUT_H +#define INPUT_H + +#include "../../main.h" +#include "../widget.h" +#include + +typedef struct { + widget_t w; + char value[INPUT_TEXT]; + uint32_t value_len; + uint32_t max_len; + uint32_t is_disabled : 1; +} input_t; + +input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, uint32_t size); +int32_t draw_input(input_t *input, uint32_t active_id); +void destroy_input(input_t *input); +#endif \ No newline at end of file