From b669b4be8a22616bc7d3e0eef6cffdde7d49f1b5 Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Fri, 26 Dec 2025 17:34:51 +0200 Subject: [PATCH] ui: file list --- src/connection.c | 1 + src/deps.mk | 29 +++++----- src/file_processor.c | 5 +- src/main.c | 9 +-- src/query.c | 8 +-- src/ui/app.c | 26 +++++++-- src/ui/app.h | 6 +- src/ui/modals/ask_server_addr.c | 5 +- src/ui/modals/login_credentials.c | 6 +- src/ui/modals/login_option.c | 5 +- src/ui/modals/server_message.c | 5 +- src/ui/widget.h | 1 - src/ui/widget/dialogue.c | 7 ++- src/ui/widget/dialogue.h | 2 +- src/ui/widget/file_list.c | 91 +++++++++++++++++++++++++++++-- src/ui/widget/file_list.h | 7 ++- 16 files changed, 164 insertions(+), 49 deletions(-) diff --git a/src/connection.c b/src/connection.c index 3895a84..a4cab2f 100644 --- a/src/connection.c +++ b/src/connection.c @@ -24,6 +24,7 @@ void connect_to_server(app_t *app) { exit(2); } app->params->is_connected = TRUE; + print_bars(app); } void init_params(params_t *params) { diff --git a/src/deps.mk b/src/deps.mk index 2028220..2875dba 100644 --- a/src/deps.mk +++ b/src/deps.mk @@ -1,24 +1,25 @@ client.o: src/client.c src/file_processor.h src/main.h src/types.h \ src/client.h connection.o: src/connection.c src/main.h src/types.h src/ui/app.h \ - src/ui/../common.h src/ui/widget/dialogue.h src/ui/widget/../widget.h \ - src/ui/widget/../../main.h src/ui/widget/../../common.h \ - src/ui/widget/button.h src/ui/widget/../../main.h src/ui/widget/group.h -file_processor.o: src/file_processor.c src/client.h src/main.h \ - src/types.h src/query.h src/ui/app.h src/ui/../common.h \ + src/ui/../common.h src/ui/widget.h src/ui/../main.h \ src/ui/widget/dialogue.h src/ui/widget/../widget.h \ - src/ui/widget/../../main.h src/ui/widget/../../common.h \ - src/ui/widget/button.h src/ui/widget/../../main.h src/ui/widget/group.h \ + src/ui/widget/../../common.h src/ui/widget/button.h \ + src/ui/widget/../../main.h src/ui/widget/group.h +file_processor.o: src/file_processor.c src/client.h src/main.h \ + src/types.h src/query.h src/ui/app.h src/ui/../common.h src/ui/widget.h \ + src/ui/../main.h src/ui/widget/dialogue.h src/ui/widget/../widget.h \ + src/ui/widget/../../common.h src/ui/widget/button.h \ + src/ui/widget/../../main.h src/ui/widget/group.h \ src/ui/widget/file_list.h main.o: src/main.c src/connection.h src/main.h src/types.h src/ui/app.h \ - src/ui/../common.h src/ui/widget/dialogue.h src/ui/widget/../widget.h \ - src/ui/widget/../../main.h src/ui/widget/../../common.h \ - src/ui/widget/button.h src/ui/widget/../../main.h src/ui/widget/group.h \ - src/query.h src/ui/widget.h src/ui/widget/dialogue.h \ - src/ui/widget/file_list.h + src/ui/../common.h src/ui/widget.h src/ui/../main.h \ + src/ui/widget/dialogue.h src/ui/widget/../widget.h \ + src/ui/widget/../../common.h src/ui/widget/button.h \ + src/ui/widget/../../main.h src/ui/widget/group.h src/query.h \ + src/ui/widget.h src/ui/widget/file_list.h query.o: src/query.c src/client.h src/main.h src/types.h src/connection.h \ - src/ui/app.h src/ui/../common.h src/ui/widget/dialogue.h \ - src/ui/widget/../widget.h src/ui/widget/../../main.h \ + src/ui/app.h src/ui/../common.h src/ui/widget.h src/ui/../main.h \ + src/ui/widget/dialogue.h src/ui/widget/../widget.h \ src/ui/widget/../../common.h src/ui/widget/button.h \ src/ui/widget/../../main.h src/ui/widget/group.h src/file_processor.h \ src/server.h diff --git a/src/file_processor.c b/src/file_processor.c index d61dcb3..a717e14 100644 --- a/src/file_processor.c +++ b/src/file_processor.c @@ -30,6 +30,8 @@ void file_list(file_args_t *f_args, query_args_t *q_args) { static uint32_t idx = 1; static char qbuf[INBUFSIZE * 2]; static uint32_t qbuf_used = 0; + file_list_t *fui = (file_list_t *) q_args->file_list_ui; + fui->start = f_args->l_start; if (qbuf_used == 0) qbuf[0] = 0; @@ -37,7 +39,7 @@ void file_list(file_args_t *f_args, query_args_t *q_args) { &query))) { if (!strcmp("list_end\n", query)) { q_args->state = S_FILE_SELECT; - draw_file_list(q_args->file_list_ui, &(f_args->l_start)); + draw_file_list(fui); idx = 1; break; } @@ -45,6 +47,7 @@ void file_list(file_args_t *f_args, query_args_t *q_args) { qbuf_used += strlen(qbuf); if (strchr(qbuf, '\n') == NULL) continue; fl_add(&(f_args->l_current), &(f_args->l_start), qbuf); + fui->count++; free(query); query = NULL; qbuf_used = 0; diff --git a/src/main.c b/src/main.c index 996f956..dcae9b5 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,6 @@ #include "query.h" #include "ui/app.h" #include "ui/widget.h" -#include "ui/widget/dialogue.h" #include "ui/widget/file_list.h" uint32_t m_id = 0; @@ -69,14 +68,10 @@ int32_t process_user_input(app_t *app, callback_args_t *d_args) { switch (c) { case KEY_F(9): destroy_app(app); - return OK; + return ERR; default: - if (app->modal.win != NULL) { d_args->data = (void *)&c; - d_args->win = app->modal.win; - d_args->widget = &(app->modal); - app->modal.w.callback(d_args); - } + app->active_callback(d_args); break; } return OK; diff --git a/src/query.c b/src/query.c index 030aaac..0374af3 100644 --- a/src/query.c +++ b/src/query.c @@ -36,7 +36,7 @@ void query_loop(app_t *app) { int sr; static file_args_t file_args; callback_args_t d_args = { - .app = app, .win = NULL, .widget = NULL, .data = NULL, .resp_data = NULL}; + .app = app, .widget = NULL, .data = NULL, .resp_data = NULL}; init_file_args(&file_args); query_args->sd = sd; @@ -65,7 +65,7 @@ void query_loop(app_t *app) { free(query_args->next_server_command); query_args->next_server_command = NULL; query_args->from_server = TRUE; - if (-1 == process_query(query_args, &file_args)) { + if (ERR == process_query(query_args, &file_args)) { close_session(sd); exit(1); } @@ -88,7 +88,7 @@ void query_loop(app_t *app) { } else { query_args->buf_used = qlen; query_args->from_server = TRUE; - if (-1 == process_query(query_args, &file_args)) { + if (ERR == process_query(query_args, &file_args)) { close_session(sd); exit(1); } @@ -113,7 +113,7 @@ void query_loop(app_t *app) { /* query_args->buf_used = qlen; query_args->from_server = 0; */ // if (-1 == process_query(&query_args, &file_args)) { - if (-1 == process_user_input(app, &d_args)) { + if (ERR == process_user_input(app, &d_args)) { close_session(sd); exit(1); } diff --git a/src/ui/app.c b/src/ui/app.c index 0f2ab65..2aa9845 100644 --- a/src/ui/app.c +++ b/src/ui/app.c @@ -7,16 +7,19 @@ // #include "modals/server_message.h" // #include "action.h" #include +#include #include #include #include +#include +#include #include void ac_file(WINDOW *win, int is_action_w); app_t *init_app() { /* get values from terminal size */ - int y_max, x_max; + int32_t y_max, x_max; getmaxyx(stdscr, y_max, x_max); /* allocate app struct memory */ @@ -29,7 +32,7 @@ app_t *init_app() { _app->win = newwin(_app->coordinates.cur_y, _app->coordinates.cur_x, 0, 0); /* define the width for each sub window */ - int32_t left_w_x = x_max / 3; + int32_t left_w_x = x_max / 10 * 4; int32_t right_w_x = x_max - left_w_x - 2; /* create the menu window */ @@ -43,7 +46,7 @@ app_t *init_app() { _app->modal.is_initiated = 0; /* default win */ - _app->active_win = aw_left; + _app->active_win_type = aw_left; /* print decorative bars */ print_bars(_app); @@ -93,6 +96,8 @@ void draw_borders(app_t *app) { } void print_bars(app_t *app) { + char top_text[64] = "Hello!"; + wattrset(app->win, A_REVERSE); /* print top and bottom bars */ @@ -102,9 +107,14 @@ void print_bars(app_t *app) { } /* add content to the top bar */ - mvwprintw(app->win, 1, 2, "example cprint_barsurses app | "); - mvwprintw(app->win, 1, sizeof "example cprint_barsurses app | " + 1, - "size %d, %d", app->coordinates.cur_x, app->coordinates.cur_y); + if (app->params && app->params->is_connected) { + uint32_t ip_address = app->params->addr; + u_char ip_addr[4]; + mempcpy(ip_addr, &ip_address, 4); + sprintf(top_text, "Connected to %u.%u.%u.%u, user: %s", ip_addr[0], + ip_addr[1], ip_addr[2], ip_addr[3], app->params->uname); + } + mvwprintw(app->win, 1, 2, "%s", top_text); /* add content to the bottom bar */ mvwprintw(app->win, app->coordinates.cur_y - 2, 2, "F1 - Help | F9 - Quit"); @@ -160,6 +170,10 @@ void app_draw_modal(app_t *app) { case S_NEXT_ACTION: return; } + app->active_callback = app->modal.w.callback; + app->active_win = app->modal.win; + app->active_win_type = aw_modal; + app->active_widget = &(app->modal); } draw_dialogue(&(app->modal)); } diff --git a/src/ui/app.h b/src/ui/app.h index 65a7e19..945d27d 100644 --- a/src/ui/app.h +++ b/src/ui/app.h @@ -2,6 +2,7 @@ #define N_APP_H #include "../common.h" +#include "widget.h" #include "widget/dialogue.h" #include @@ -26,7 +27,10 @@ typedef struct { query_args_t *query_args; file_args_t *file_args; int32_t read_fd; - active_win_t active_win; + active_win_t active_win_type; + void (*active_callback)(callback_args_t *args); + WINDOW *active_win; + void *active_widget; } app_t; app_t *init_app(); diff --git a/src/ui/modals/ask_server_addr.c b/src/ui/modals/ask_server_addr.c index 8c1957a..1e663c9 100644 --- a/src/ui/modals/ask_server_addr.c +++ b/src/ui/modals/ask_server_addr.c @@ -18,10 +18,11 @@ 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 *)args->widget; + 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.widget = 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); @@ -30,7 +31,7 @@ void asa_modal_dialogue_callback(callback_args_t *args) { case 0: get_ip_port(app->params, in_ip->value, in_port->value); connect_to_server(app); - destroy_dialogue(d); + destroy_dialogue(d, app); app->query_args->state = S_WAIT_SERVER; break; case 1: diff --git a/src/ui/modals/login_credentials.c b/src/ui/modals/login_credentials.c index 3cfe6d5..ac87088 100644 --- a/src/ui/modals/login_credentials.c +++ b/src/ui/modals/login_credentials.c @@ -18,10 +18,11 @@ 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 *)args->widget; + 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.widget = 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); @@ -36,7 +37,8 @@ void init_login_credentials_modal_cb(callback_args_t *args) { app->params->pass[in_pass->value_len] = 0; write(app->params->sd, app->params->uname, in_name->value_len); app->query_args->state = S_WAIT_SERVER; - destroy_dialogue(d); + destroy_dialogue(d,app); + print_bars(app); break; case 1: destroy_app(app); diff --git a/src/ui/modals/login_option.c b/src/ui/modals/login_option.c index 6f33a00..7cfc548 100644 --- a/src/ui/modals/login_option.c +++ b/src/ui/modals/login_option.c @@ -15,17 +15,18 @@ 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 *)args->widget; + 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.widget = app->active_widget; dialogue_default_callback(&d_args); if (response > -1) { switch (response) { case 0: break; case 1: - destroy_dialogue(d); + destroy_dialogue(d, app); app->query_args->state = S_ASK_LOGIN_USER; break; } diff --git a/src/ui/modals/server_message.c b/src/ui/modals/server_message.c index 81a5b1c..505de0f 100644 --- a/src/ui/modals/server_message.c +++ b/src/ui/modals/server_message.c @@ -16,15 +16,16 @@ 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 *)args->widget; + 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.widget = app->active_widget; dialogue_default_callback(&d_args); if (response > -1) { switch (response) { case 0: - destroy_dialogue(d); + destroy_dialogue(d, app); /* TODO: macros */ free(app->query_args->server_message.text); app->query_args->server_message.capacity = 0; diff --git a/src/ui/widget.h b/src/ui/widget.h index 601e9b6..530c991 100644 --- a/src/ui/widget.h +++ b/src/ui/widget.h @@ -14,7 +14,6 @@ enum w_type { }; typedef struct { - WINDOW *win; void *app; void *widget; void *data; diff --git a/src/ui/widget/dialogue.c b/src/ui/widget/dialogue.c index 0fe6a63..2a411c2 100644 --- a/src/ui/widget/dialogue.c +++ b/src/ui/widget/dialogue.c @@ -5,6 +5,7 @@ #include "../app.h" #include "dialogue.h" +#include "file_list.h" #include "group.h" #include "input.h" @@ -251,7 +252,8 @@ int32_t draw_dialogue(dialogue_t *d) { return 0; }; -void destroy_dialogue(dialogue_t *d) { +void destroy_dialogue(dialogue_t *d, void *_app) { + app_t *app = (app_t *)_app; if (d->g_content) { destroy_group(d->g_content); } @@ -261,4 +263,7 @@ void destroy_dialogue(dialogue_t *d) { delwin(d->win); d->win = NULL; d->is_initiated = 0; + app->active_win_type = aw_left; + app->active_win = app->left_win; + app->active_callback = file_list_cb; } \ No newline at end of file diff --git a/src/ui/widget/dialogue.h b/src/ui/widget/dialogue.h index f527318..d91ba1b 100644 --- a/src/ui/widget/dialogue.h +++ b/src/ui/widget/dialogue.h @@ -27,7 +27,7 @@ typedef struct { void init_dialogue(dialogue_t *d, const char title[], const char text[], coordinates_t *p_coordinates); int32_t draw_dialogue(dialogue_t *d); -void destroy_dialogue(dialogue_t *d); +void destroy_dialogue(dialogue_t *d, void *app); void dialogue_default_callback(callback_args_t *args); void dialogue_init_active_id(dialogue_t *dialogue); diff --git a/src/ui/widget/file_list.c b/src/ui/widget/file_list.c index c5df124..af857f0 100644 --- a/src/ui/widget/file_list.c +++ b/src/ui/widget/file_list.c @@ -1,31 +1,114 @@ #include "file_list.h" +#include "../app.h" #include #include #include #include #include +void file_list_cb(callback_args_t *args) { + app_t *app = args->app; + file_list_t *fui = app->query_args->file_list_ui; + int32_t key = *((int32_t *)args->data); + switch (key) { + case KEY_DOWN: + if (fui->current_idx < fui->count - 1) { + fui->current_idx++; + redraw_file_list(fui); + } + break; + case KEY_UP: + if (fui->current_idx > 0) { + fui->current_idx--; + redraw_file_list(fui); + } + break; + } +} + file_list_t *init_file_list(WINDOW **win) { file_list_t *fl_ui = malloc(sizeof(file_list_t)); - init_widget(&(fl_ui->w), NULL, win,""); + init_widget(&(fl_ui->w), NULL, win, ""); + fl_ui->current_idx = 0; + fl_ui->current_page = 0; + fl_ui->pages = 0; + fl_ui->count = 0; return fl_ui; } -void draw_file_list(file_list_t *fl_ui, fl_item_t **fl_start) { +void reset_file_list(file_list_t *fl_ui) { + fl_ui->current_idx = 0; + fl_ui->current_page = 0; + fl_ui->pages = 0; + fl_ui->count = 0; +} + +void draw_file_list(file_list_t *fl_ui) { int32_t sz_y, sz_x; int32_t p_y, p_x; getmaxyx(*(fl_ui->w.parent_win), sz_y, sz_x); p_y = 1; p_x = 1; - fl_item_t *el = *fl_start; + fl_item_t *el = fl_ui->start; + int32_t cur_el_idx = 0; + curs_set(0); do { + if (cur_el_idx == fl_ui->current_idx) { + wattrset(*(fl_ui->w.parent_win), A_BOLD | A_REVERSE); + } p_x = 1; mvwprintw(*(fl_ui->w.parent_win), p_y, p_x, "%s%n", el->name, &p_x); for (uint i = 1; p_x < sz_x; i++) { - mvwprintw(*(fl_ui->w.parent_win), p_y, ++p_x, " "); + mvwprintw(*(fl_ui->w.parent_win), p_y, ++p_x, " "); + } + if (cur_el_idx == fl_ui->current_idx) { + wattroff(*(fl_ui->w.parent_win), A_BOLD | A_REVERSE); } p_y++; + cur_el_idx++; } while ((el = el->next) != NULL && p_y < sz_y); +} +void redraw_file_list(file_list_t *fl_ui) { + static uint32_t active_idx = 0; + int32_t sz_y, sz_x; + int32_t p_y, p_x; + getmaxyx(*(fl_ui->w.parent_win), sz_y, sz_x); + int32_t sz_y_f = sz_y - 2; // factual size (without box) + p_y = 1; + p_x = 1; + fl_item_t *el = fl_ui->start; + int32_t cur_el_idx = 0; + bool sm_size = sz_y_f < fl_ui->count; + bool print_all = false; + int32_t diff = 0; + + if (fl_ui->current_idx >= sz_y_f) { + print_all = true; + diff = fl_ui->current_idx - sz_y_f + 1; + } else if (active_idx - fl_ui->current_idx == 1) { + print_all = true; + } + + do { + if (cur_el_idx == fl_ui->current_idx) { + wattrset(*(fl_ui->w.parent_win), A_BOLD | A_REVERSE); + } else if (cur_el_idx != active_idx && !print_all) { + p_y++; + cur_el_idx++; + continue; + } + p_x = 1; + mvwprintw(*(fl_ui->w.parent_win), p_y-diff, p_x, "%s%n", el->name, &p_x); + for (uint i = 1; p_x < sz_x; i++) { + mvwprintw(*(fl_ui->w.parent_win), p_y-diff, ++p_x, " "); + } + if (cur_el_idx == fl_ui->current_idx) { + wattroff(*(fl_ui->w.parent_win), A_BOLD | A_REVERSE); + } + p_y++; + cur_el_idx++; + } while ((el = el->next) != NULL && p_y-diff < sz_y); + active_idx = fl_ui->current_idx; } \ No newline at end of file diff --git a/src/ui/widget/file_list.h b/src/ui/widget/file_list.h index 500b98b..5a1a254 100644 --- a/src/ui/widget/file_list.h +++ b/src/ui/widget/file_list.h @@ -7,8 +7,13 @@ typedef struct { fl_item_t *current; fl_item_t *start; int32_t current_idx; + uint32_t count; + uint32_t pages; + uint32_t current_page; } file_list_t; -void draw_file_list(file_list_t *fl_ui, fl_item_t **fl_start); +void draw_file_list(file_list_t *fl_ui); +void redraw_file_list(file_list_t *fl_ui); file_list_t *init_file_list(WINDOW **win); +void file_list_cb(callback_args_t *args); #endif \ No newline at end of file