From 2bc3ee438e992bf48cfc1449c82ee5cd6d1e34e8 Mon Sep 17 00:00:00 2001 From: Alexander Zhylin Date: Tue, 14 Jul 2026 19:12:26 +0300 Subject: [PATCH] further development in text edit window. main_dev_widget mode. --- CMakeLists.txt | 2 + README.md | 4 +- src/CMakeLists.txt | 6 +++ src/app.c | 30 ++++++----- src/app.h | 2 +- src/main.c | 36 ++++++------- src/main.h | 2 +- src/main_dev_widget.c | 117 ++++++++++++++++++++++++++++++++++++++++ src/query.c | 1 - src/windows/text_edit.c | 36 +++++++------ src/windows/text_edit.h | 5 +- 11 files changed, 186 insertions(+), 55 deletions(-) create mode 100644 src/main_dev_widget.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fb08a7..006dfd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required(VERSION 3.23) +set(CACHE DEV_WIDGET BOOL OFF "Enable development widget mode") + project(ZBBSClientTUI VERSION 1.0.0 ) diff --git a/README.md b/README.md index 7806cb8..5073f01 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ It will create all necessary file structure in order to run the program correctl 2. Build the binary running `$ make` or `$ make bbs-client` 3. Run it by `$ make run` -## Develop +## Development +### Widget development +In order to switch to widget/screen development, configure cmake with `-DDEV_WIDGET=ON` ### Name conventions: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5523a2b..f2bdb97 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,12 @@ endif() file(GLOB M_SOURCES "*.c") +if(DEV_WIDGET) + list(FILTER M_SOURCES EXCLUDE REGEX "main\\.c$") +else() + list(FILTER M_SOURCES EXCLUDE REGEX "main_dev_widget\\.c$") +endif() + target_sources(zbbs-client-tui PRIVATE ${M_SOURCES} diff --git a/src/app.c b/src/app.c index 111cf0a..789c5c6 100644 --- a/src/app.c +++ b/src/app.c @@ -14,41 +14,43 @@ void ac_file(WINDOW *win, int is_action_w); -app_t *app_init(void) { +app_t *app_init(app_t *app) { /* get values from terminal size */ int32_t y_max, x_max; getmaxyx(stdscr, y_max, x_max); /* allocate app struct memory */ - app_t *_app = calloc(1, sizeof(app_t)); + if (app == NULL) { + app = calloc(1, sizeof(app_t)); + } /* associate values for screen size */ - _app->coordinates.max_x = _app->coordinates.cur_x = x_max; - _app->coordinates.max_y = _app->coordinates.cur_y = y_max; + app->coordinates.max_x = app->coordinates.cur_x = x_max; + app->coordinates.max_y = app->coordinates.cur_y = y_max; - _app->win = newwin(_app->coordinates.cur_y, _app->coordinates.cur_x, 0, 0); + app->win = newwin(app->coordinates.cur_y, app->coordinates.cur_x, 0, 0); /* dialogue */ - _app->modal.win = NULL; - _app->modal.is_initiated = 0; + app->modal.win = NULL; + app->modal.is_initiated = 0; /* print top and bottom bars */ - _app->main_ui.b_keys_len = 0; - app_draw_bars(_app); + app->main_ui.b_keys_len = 0; + app_draw_bars(app); /* here goes box borders */ - app_draw_borders(_app); + app_draw_borders(app); /* NULL to main_ui */ - MAIN_UI_RESET(_app); + MAIN_UI_RESET(app); - keypad(_app->win, TRUE); + keypad(app->win, TRUE); /* refresh the windows */ - wnoutrefresh(_app->win); + wnoutrefresh(app->win); doupdate(); - return _app; + return app; } void app_init_nc(void) { diff --git a/src/app.h b/src/app.h index c79523d..4e72f20 100644 --- a/src/app.h +++ b/src/app.h @@ -27,7 +27,7 @@ typedef struct { main_window_t main_ui; } app_t; -app_t *app_init(void); +app_t *app_init(app_t *app); void app_init_nc(void); void app_destroy(app_t *app, int32_t exit_code); void app_draw_borders(app_t *app); diff --git a/src/main.c b/src/main.c index 3b128d1..ce1c16c 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -15,11 +14,11 @@ #include #include -#include "main.h" #include "../app.h" #include "alert.h" #include "connection.h" -#include "file_list.h" +// #include "file_list.h" +#include "main.h" #include "query.h" int32_t m_id = 0; @@ -27,42 +26,39 @@ int32_t m_id = 0; int32_t process_user_input(app_t *app, w_cb_args_t *d_args); int main(int argc, char **argv) { - app_t *app; + app_t app; params_t params; - query_args_t *q_args = malloc(sizeof(query_args_t)); - - app = calloc(1, sizeof(app_t)); + query_args_t q_args; app_init_nc(); - app = app_init(); + app.params = ¶ms; + app_init(&app); init_params(¶ms); - app->params = ¶ms; analyze_args(argc, argv, ¶ms); /* init alert */ - w_alert_init(app); + w_alert_init(&app); - init_query_args(q_args, app->params); - q_args->buf = malloc(INBUFSIZE); - app->query_args = q_args; + init_query_args(&q_args, app.params); + app.query_args = &q_args; - main_window_set(app, mw_fl_server); + main_window_set(&app, mw_fl_server); /* init client to connect to the server */ - app->params->sd = init_client(); + app.params->sd = init_client(); if (params.addr == 0) { - app->query_args->state = S_ASK_SEVER_IP; + app.query_args->state = S_ASK_SEVER_IP; } else { - connect_to_server(app); + connect_to_server(&app); } - app->query_args->main_ui = &(app->main_ui); + app.query_args->main_ui = &(app.main_ui); - query_loop(app); + query_loop(&app); clear_params(¶ms); - app_destroy(app, 0); + app_destroy(&app, 0); return OK; } diff --git a/src/main.h b/src/main.h index 4b07ae3..c458f1d 100644 --- a/src/main.h +++ b/src/main.h @@ -119,7 +119,7 @@ typedef struct query_args { int32_t buf_used; p_file_t *file; enum state state; - char *buf; + char buf[INBUFSIZE]; bool from_server; params_t *params; struct { diff --git a/src/main_dev_widget.c b/src/main_dev_widget.c new file mode 100644 index 0000000..9ab67ec --- /dev/null +++ b/src/main_dev_widget.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (c) 2026 Oleksandr Zhylin */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../app.h" +#include "alert.h" +#include "connection.h" +#include "main.h" +#include "query.h" + +int32_t m_id = 0; + + +void mini_loop(app_t *app) { + w_cb_args_t d_args = { + .app = app, .element = NULL, .data = NULL, .resp_data.code = cbrc_none}; + + fd_set readfds; + + while (true) { + app_draw_modal(app); + main_window_draw(app); + app_refresh(app); + + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + int maxfd = STDIN_FILENO; + + int sr = select(maxfd + 1, &readfds, NULL, NULL, NULL); + + if (sr == -1) { + /* perror("select"); */ + exit(3); + } + + if (app->main_ui.cb_b_press != NULL && app->modal.is_initiated == false) { + if (ERR == app->main_ui.cb_b_press(app, &d_args)) { + w_alert("error while processing user input"); + } + } + } + +} + +int main(void) { + app_t app; + file_args_t fargs; + query_args_t q_args; + params_t params; + p_file_t file; + + app.params = ¶ms; + app.query_args = &q_args; + app.file_args = &fargs; + q_args.file = &file; + app.query_args->main_ui = &(app.main_ui); + + file.name = "Test file #1"; + params.is_connected = false; + app.modal.is_initiated = false; + + app_init_nc(); + app_init(&app); + init_params(¶ms); + init_query_args(&q_args, app.params); + w_alert_init(&app); + app_init(&app); + main_window_set(&app, mw_f_desc); + mini_loop(&app); + exit(0); +} + +int32_t process_user_input(app_t *app, w_cb_args_t *d_args) { + int32_t c; + w_ui_file_list_t *fui = (w_ui_file_list_t *)app->query_args->main_ui->ui; + c = wgetch(app->win); + switch (c) { + case KEY_F(9): + app_destroy(app, 0); + return OK; + case 'U': + case 'u': + if (!app->modal.is_initiated && !fui->active_search && + app->main_ui.type != mw_fl_local) { + /* app->query_args->state = S_UPLOAD_FILE_SELECT; */ + main_window_set(app, mw_fl_local); + main_window_draw(app); + d_args->element = app->main_ui.ui; + break; + } + case 's': + case 'S': + if (!app->modal.is_initiated && !fui->active_search) { + fui->active_search = true; + w_fl_draw(fui); + return OK; + } + default: + d_args->data = (void *)&c; + app->active_callback(d_args); + break; + } + return OK; +} \ No newline at end of file diff --git a/src/query.c b/src/query.c index fd0b4c6..8a2d4ba 100644 --- a/src/query.c +++ b/src/query.c @@ -291,7 +291,6 @@ static int process_command(app_t *app, wait_server_cb *callback) { } void init_query_args(query_args_t *q_args, params_t *params) { - q_args->buf = NULL; q_args->sd = -1; q_args->state = S_N_D; q_args->buf_used = 0; diff --git a/src/windows/text_edit.c b/src/windows/text_edit.c index 9795808..749db9f 100644 --- a/src/windows/text_edit.c +++ b/src/windows/text_edit.c @@ -20,11 +20,9 @@ static void w_te_cb(w_cb_args_t *args) { int32_t key = *((int32_t *)args->data); w_te_ui_t *fui = app->query_args->main_ui->ui; switch (key) { - case '\n': - // TODO: new line case - break; - case '\b': - // TODO: new line case + case KEY_BACKSPACE: + case KEY_DL: + fui->text[fui->text_len--] = 0; break; default: fui->text[fui->text_len++] = key; @@ -92,16 +90,14 @@ w_te_ui_t *w_te_init_win(app_t *app) { fui->w.sz.y = getmaxy(app->win); fui->w.parent_win = &(app->win); /* * INIT UI * */ - - /* define the width for each sub window */ - int32_t left_w_x = app->coordinates.max_x / 10 * 5; - int32_t right_w_x = app->coordinates.max_x - left_w_x - 2; + fui->win = newwin(fui->w.sz.y - 4, fui->w.sz.x - 2, 2, 1); return fui; } void w_te_reset(w_te_ui_t *fl_ui) { fl_ui->text[0] = 0; - fl_ui->scroll_pos = 0; + fl_ui->cur_pos.x = 0; + fl_ui->cur_pos.y = 0; fl_ui->text_len = 0; } @@ -119,18 +115,26 @@ void w_te_draw(w_te_ui_t *fui) { int32_t sz_y_f = sz_y - 1; // actual size (without box) int32_t sz_x_f = sz_x - 1; // actual size (without box) - p_y = 1; - p_x = 1; + p_y = 0; + p_x = 0; - for (int i = 0; i < fui->w.sz.y; i++) { - mvwaddnwstr(win, p_y, p_x, fui->text + fui->w.sz.x * i, fui->w.sz.x); + wattrset(win, COLOR_PAIR(modal_color_pair) | A_BOLD | A_REVERSE); + + int i = 0; + for (i = 0; i < fui->w.sz.y; i++) { + mvwprintw(win, p_y + i, p_x, "%*s", fui->w.sz.x, ""); } - box(fui->win, 0, 0); + int len_rest = fui->text_len; + mvwaddnwstr(win, p_y, p_x, fui->text, fui->text_len); + + fui->cur_pos.y = i; + p_x = 1; wattroff(win, A_BOLD); - curs_set(false); + + curs_set(true); } void w_te_destroy(w_te_ui_t **fui) { diff --git a/src/windows/text_edit.h b/src/windows/text_edit.h index 14a503d..6e8a529 100644 --- a/src/windows/text_edit.h +++ b/src/windows/text_edit.h @@ -17,7 +17,10 @@ typedef struct { WINDOW *win; wchar_t text[INBUFSIZE * 10]; int text_len; - int scroll_pos; + struct { + int x; + int y; + } cur_pos; void *file_pt; // TODO: уточнить } w_te_ui_t;