Merge pull request #2 from zheiling/children-groups

Children groups
This commit is contained in:
2026-02-26 15:09:48 +02:00
committed by GitHub
33 changed files with 489 additions and 357 deletions
+9 -1
View File
@@ -1,15 +1,23 @@
# TODO: # 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: ## Features:
- [x] Search files - [x] Search files
- [x] Correct spacing in the search bar - [x] Correct spacing in the search bar
- [x] Finish registration - [x] Finish registration
- [ ] UI: vertical layout (needs for email in registration)
- [ ] Get rid of old notification mechanism - [ ] Get rid of old notification mechanism
- [ ] Privilege settings for files - [ ] Privilege settings for files
- [ ] Files removal - [ ] Files removal
- [ ] Encryption - [ ] Encryption
- [ ] UTF-8 support - [ ] UTF-8 support
## Fixes: ## Fixes:
- [ ] Check and fix registration and login - [ ] Check and fix registration and login
- [ ] Hotkeys for buttons - [ ] Hotkeys for buttons
+2
View File
@@ -44,6 +44,7 @@ add_subdirectory(widget_core)
add_subdirectory(widget) add_subdirectory(widget)
add_subdirectory(modals) add_subdirectory(modals)
add_subdirectory(lib) add_subdirectory(lib)
add_subdirectory(utils)
target_link_libraries(zbbs-client-tui target_link_libraries(zbbs-client-tui
PRIVATE PRIVATE
@@ -51,5 +52,6 @@ target_link_libraries(zbbs-client-tui
widget widget
modals modals
bstring bstring
utils
${CURSES_LIBRARIES} ${CURSES_LIBRARIES}
) )
+1
View File
@@ -44,6 +44,7 @@ int main(int argc, char **argv) {
q_args->buf = malloc(INBUFSIZE); q_args->buf = malloc(INBUFSIZE);
app->query_args = q_args; app->query_args = q_args;
q_args->file_list_ui = init_file_list(&(app->left_win), &(app->right_win)); 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 */ /* init client to connect to the server */
app->params->sd = init_client(); app->params->sd = init_client();
+8 -1
View File
@@ -3,7 +3,13 @@ add_library(modals STATIC)
file(GLOB M_HEADERS "*.h") file(GLOB M_HEADERS "*.h")
file(GLOB M_SOURCES "*.c") 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 target_sources(modals
PRIVATE PRIVATE
@@ -17,3 +23,4 @@ target_sources(modals
target_include_directories(modals PRIVATE "../widget") target_include_directories(modals PRIVATE "../widget")
target_include_directories(modals PRIVATE "../widget_core") target_include_directories(modals PRIVATE "../widget_core")
target_include_directories(modals PRIVATE "../lib/") target_include_directories(modals PRIVATE "../lib/")
target_include_directories(widget PRIVATE "../utils/")
+2 -2
View File
@@ -25,7 +25,7 @@ void notification(const char *title, const char *message,
return; return;
group_el_init_t actions[] = { 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)); 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->w.callback = alert_cb;
d->g_content = NULL; 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); dialogue_init_active_id(d);
d->color_scheme = color; d->color_scheme = color;
+8 -15
View File
@@ -1,15 +1,10 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <ncurses.h> #include <ncurses.h>
// #include "../app.h"
// #include "../widget/dialogue.h"
// #include "../widget/group.h"
// #include "../widget/input.h"
// #include "../widget/button.h"
#include <widget.h> #include <widget.h>
#include <widget_core.h>
#include "../connection.h" #include "../connection.h"
#include "group.h"
typedef struct { typedef struct {
button_t *element; button_t *element;
@@ -17,19 +12,17 @@ typedef struct {
} group_bt_t; } group_bt_t;
void asa_modal_dialogue_callback(callback_args_t *args) { void asa_modal_dialogue_callback(callback_args_t *args) {
int32_t response;
callback_args_t d_args; callback_args_t d_args;
app_t *app = args->app; app_t *app = args->app;
dialogue_t *d = (dialogue_t *)app->active_widget; dialogue_t *d = (dialogue_t *)app->active_widget;
memcpy(&d_args, args, sizeof(callback_args_t)); memcpy(&d_args, args, sizeof(callback_args_t));
d_args.app = NULL; d_args.app = NULL;
d_args.resp_data = &response;
d_args.element = app->active_widget; d_args.element = app->active_widget;
input_t *in_ip = d->g_content->elements[0].element; input_t *in_ip = d->g_content->elements[0].element;
input_t *in_port = d->g_content->elements[1].element; input_t *in_port = d->g_content->elements[1].element;
dialogue_default_callback(&d_args); dialogue_default_callback(&d_args);
if (response > -1) { if (d_args.resp_data.code == cbrp_val) {
switch (response) { switch (d_args.resp_data.val.val.num) {
case 0: case 0:
get_ip_port(app->params, in_ip->value, in_port->value); get_ip_port(app->params, in_ip->value, in_port->value);
connect_to_server(app); connect_to_server(app);
@@ -51,8 +44,8 @@ dialogue_t *init_asa_modal(app_t *app) {
{.type = w_end}}; {.type = w_end}};
group_el_init_t actions[] = { group_el_init_t actions[] = {
{.type = w_button, .label = "Connect", .is_default = 1}, {.type = w_button, .label = "Connect", .is_default = true, .val.num = 1},
{.type = w_button, .label = "Cancel", .is_default = 0}, {.type = w_button, .label = "Cancel", .is_default = false, .val.num = 2},
{.type = w_end}}; {.type = w_end}};
init_dialogue(&(app->modal), "Connect to server", init_dialogue(&(app->modal), "Connect to server",
@@ -60,8 +53,8 @@ dialogue_t *init_asa_modal(app_t *app) {
dialogue_t *d = &(app->modal); dialogue_t *d = &(app->modal);
d->w.callback = asa_modal_dialogue_callback; d->w.callback = asa_modal_dialogue_callback;
d->g_content = init_group(&(d->win), &(d->w), content, 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, horizontal); d->g_action = init_group(&(d->win), &(d->w), actions,&(d->id_map), horizontal, g_action);
dialogue_init_active_id(d); dialogue_init_active_id(d);
+4 -3
View File
@@ -1,3 +1,4 @@
#include "group.h"
#include <widget.h> #include <widget.h>
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
@@ -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", sprintf(text, "%s file: %s", is_upload ? "Uploading" : "Downloading",
is_upload ? app->query_args->file->name : app->file_args->f_selected.name); is_upload ? app->query_args->file->name : app->file_args->f_selected.name);
group_el_init_t actions[] = { 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; app->modal.w.parent_win = &app->win;
init_dialogue(&(app->modal), is_upload ? "Upload" : "Download", text, 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); dialogue_t *d = &(app->modal);
d->w.callback = dwn_pr_modal_cb; d->w.callback = dwn_pr_modal_cb;
d->g_content = init_group(&(d->win), &(d->w), content, 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, horizontal); 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->progress_bar = d->g_content->elements[0].element;
app->query_args->active_dialogue = d; app->query_args->active_dialogue = d;
+9 -10
View File
@@ -1,3 +1,4 @@
#include "group.h"
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@@ -12,20 +13,18 @@ typedef struct {
} group_bt_t; } group_bt_t;
void init_login_credentials_modal_cb(callback_args_t *args) { void init_login_credentials_modal_cb(callback_args_t *args) {
int32_t response;
callback_args_t d_args; callback_args_t d_args;
app_t *app = args->app; app_t *app = args->app;
dialogue_t *d = (dialogue_t *)app->active_widget; dialogue_t *d = (dialogue_t *)app->active_widget;
memcpy(&d_args, args, sizeof(callback_args_t)); memcpy(&d_args, args, sizeof(callback_args_t));
d_args.app = NULL; d_args.app = NULL;
d_args.resp_data = &response;
d_args.element = app->active_widget; d_args.element = app->active_widget;
input_t *in_name = d->g_content->elements[0].element; input_t *in_name = d->g_content->elements[0].element;
input_t *in_pass = d->g_content->elements[1].element; input_t *in_pass = d->g_content->elements[1].element;
dialogue_default_callback(&d_args); dialogue_default_callback(&d_args);
if (response > -1) { if (d_args.resp_data.code == cbrp_val) {
switch (response) { switch (d_args.resp_data.val.val.num) {
case 0: case 1:
app->params->uname = malloc(in_name->value_len + 1); app->params->uname = malloc(in_name->value_len + 1);
app->params->pass = malloc(in_pass->value_len + 1); app->params->pass = malloc(in_pass->value_len + 1);
strncpy(app->params->uname, in_name->value, in_name->value_len); 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; d->needs_destroy = true;
print_bars(app); print_bars(app);
break; break;
case 1: case 2:
app->query_args->state = S_ASK_LOGIN_TYPE; app->query_args->state = S_ASK_LOGIN_TYPE;
app->modal.needs_destroy = true; app->modal.needs_destroy = true;
} }
@@ -56,8 +55,8 @@ dialogue_t *init_login_credentials_modal(app_t *app) {
{.type = w_end}}; {.type = w_end}};
group_el_init_t actions[] = { group_el_init_t actions[] = {
{.type = w_button, .label = "Login", .is_default = true}, {.type = w_button, .label = "Login", .is_default = true, .val.num = 1},
{.type = w_button, .label = "Cancel", .is_default = false}, {.type = w_button, .label = "Cancel", .is_default = false, .val.num = 2},
{.type = w_end}}; {.type = w_end}};
init_dialogue(&(app->modal), "Login", "Your login credentials", 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); dialogue_t *d = &(app->modal);
d->w.callback = init_login_credentials_modal_cb; d->w.callback = init_login_credentials_modal_cb;
d->g_content = init_group(&(d->win), &(d->w), content, 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, horizontal); d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), horizontal, g_action);
dialogue_init_active_id(d); dialogue_init_active_id(d);
+11 -13
View File
@@ -1,3 +1,4 @@
#include "group.h"
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@@ -12,18 +13,16 @@ typedef struct {
} group_bt_t; } group_bt_t;
void login_modal_option_cb(callback_args_t *args) { void login_modal_option_cb(callback_args_t *args) {
int32_t response;
callback_args_t d_args; callback_args_t d_args;
app_t *app = args->app; app_t *app = args->app;
dialogue_t *d = (dialogue_t *)app->active_widget; dialogue_t *d = (dialogue_t *)app->active_widget;
memcpy(&d_args, args, sizeof(callback_args_t)); memcpy(&d_args, args, sizeof(callback_args_t));
d_args.app = NULL; d_args.app = NULL;
d_args.resp_data = &response;
d_args.element = app->active_widget; d_args.element = app->active_widget;
dialogue_default_callback(&d_args); dialogue_default_callback(&d_args);
if (response > -1) { if (d_args.resp_data.code == cbrp_val) {
switch (response) { switch (d_args.resp_data.val.val.num) {
case 0: case 1:
d->needs_destroy = true; d->needs_destroy = true;
app->params->uname = malloc(sizeof "anonymous"); app->params->uname = malloc(sizeof "anonymous");
strcpy(app->params->uname, "anonymous"); strcpy(app->params->uname, "anonymous");
@@ -31,11 +30,11 @@ void login_modal_option_cb(callback_args_t *args) {
app->query_args->state = S_WAIT_SERVER; app->query_args->state = S_WAIT_SERVER;
print_bars(app); print_bars(app);
break; break;
case 1: case 2:
d->needs_destroy = true; d->needs_destroy = true;
app->query_args->state = S_ASK_LOGIN_USER; app->query_args->state = S_ASK_LOGIN_USER;
break; break;
case 2: case 3:
d->needs_destroy = true; d->needs_destroy = true;
app->query_args->state = S_ASK_REGISTER; app->query_args->state = S_ASK_REGISTER;
break; break;
@@ -46,18 +45,17 @@ void login_modal_option_cb(callback_args_t *args) {
dialogue_t *init_login_option_modal(app_t *app) { dialogue_t *init_login_option_modal(app_t *app) {
if (app == NULL) if (app == NULL)
return NULL; return NULL;
group_el_init_t children[] = {{.type = w_button, .label = "Anonymous"}, group_el_init_t children[] = {{.type = w_button, .label = "Anonymous", .val.num = 1},
{.type = w_button, .label = "User"}, {.type = w_button, .label = "User", .val.num = 2},
{.type = w_button, .label = "Register"}, {.type = w_button, .label = "Register", .val.num = 3},
{.type = w_end}}; {.type = w_end}};
init_dialogue(&(app->modal), "Login", init_dialogue(&(app->modal), "Login",
"Select your login " "Select your login "
"option", "option",
&(app->coordinates)); &(app->coordinates));
app->modal.g_action = app->modal.g_action = init_group(&(app->modal.win), &(app->modal.w), children,
init_group(&(app->modal.win), &(app->modal.w), children, &(app->modal.id_map), horizontal, g_action);
horizontal);
app->modal.w.callback = login_modal_option_cb; app->modal.w.callback = login_modal_option_cb;
dialogue_init_active_id(&(app->modal)); dialogue_init_active_id(&(app->modal));
+5 -6
View File
@@ -1,3 +1,4 @@
#include "group.h"
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@@ -5,21 +6,17 @@
#include <widget.h> #include <widget.h>
/* TODO: get rid of this mechanism */
typedef struct { typedef struct {
button_t *element; button_t *element;
enum w_type type; enum w_type type;
} group_bt_t; } group_bt_t;
void init_notification_modal_cb(callback_args_t *args) { void init_notification_modal_cb(callback_args_t *args) {
int32_t response;
callback_args_t d_args; callback_args_t d_args;
app_t *app = args->app; app_t *app = args->app;
dialogue_t *d = (dialogue_t *)app->active_widget; dialogue_t *d = (dialogue_t *)app->active_widget;
memcpy(&d_args, args, sizeof(callback_args_t)); memcpy(&d_args, args, sizeof(callback_args_t));
d_args.app = NULL; d_args.app = NULL;
d_args.resp_data = &response;
d_args.element = app->active_widget; d_args.element = app->active_widget;
dialogue_default_callback(&d_args); dialogue_default_callback(&d_args);
@@ -32,7 +29,8 @@ dialogue_t *init_notification_modal(app_t *app) {
return NULL; return NULL;
group_el_init_t actions[] = { 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, init_dialogue(&(app->modal), "Notification", app->query_args->notification,
&(app->coordinates)); &(app->coordinates));
@@ -43,7 +41,8 @@ dialogue_t *init_notification_modal(app_t *app) {
d->w.callback = init_notification_modal_cb; d->w.callback = init_notification_modal_cb;
d->g_content = NULL; 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); dialogue_init_active_id(d);
+34 -20
View File
@@ -8,6 +8,8 @@
#include <widget.h> #include <widget.h>
#include "alert.h" #include "alert.h"
#include "group.h"
#include "widget_core.h"
typedef struct { typedef struct {
button_t *element; button_t *element;
@@ -17,21 +19,23 @@ typedef struct {
void init_register_modal_cb(callback_args_t *args) { void init_register_modal_cb(callback_args_t *args) {
char query[256]; char query[256];
int32_t qlen = 0; int32_t qlen = 0;
int32_t response;
callback_args_t d_args; callback_args_t d_args;
app_t *app = args->app; app_t *app = args->app;
dialogue_t *d = (dialogue_t *)app->active_widget; dialogue_t *d = (dialogue_t *)app->active_widget;
memcpy(&d_args, args, sizeof(callback_args_t)); memcpy(&d_args, args, sizeof(callback_args_t));
d_args.app = NULL; d_args.app = NULL;
d_args.resp_data = &response;
d_args.element = app->active_widget; d_args.element = app->active_widget;
input_t *in_name = d->g_content->elements[0].element; group_t *g_email_user = d->g_content->elements[0].element;
input_t *in_pass = d->g_content->elements[1].element; group_t *g_passwords = d->g_content->elements[1].element;
input_t *in_pass_r = d->g_content->elements[2].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); dialogue_default_callback(&d_args);
if (response > -1) { if (d_args.resp_data.code == cbrp_val &&
switch (response) { d_args.resp_data.val.type == val_num) {
case 0: switch (d_args.resp_data.val.val.num) {
case 1:
if (strcmp(in_pass->value, in_pass_r->value)) { if (strcmp(in_pass->value, in_pass_r->value)) {
alert("Your passwords do not match"); alert("Your passwords do not match");
in_pass->value[0] = '\0'; 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; app->params->uname[in_name->value_len] = 0;
strncpy(app->params->pass, in_pass->value, in_pass->value_len); strncpy(app->params->pass, in_pass->value, in_pass->value_len);
app->params->pass[in_pass->value_len] = 0; app->params->pass[in_pass->value_len] = 0;
sprintf(query, "register %s %s\n%n", app->params->uname, app->params->pass, sprintf(query, "register %s %s %*s\n%n", app->params->uname,
&qlen); app->params->pass, (int) in_email->value_len, in_email->value, &qlen);
write(app->params->sd, query, qlen); write(app->params->sd, query, qlen);
app->query_args->state = S_WAIT_REGISTER_CONFIRMATION; app->query_args->state = S_WAIT_REGISTER_CONFIRMATION;
break; break;
case 1: case 2:
app->query_args->state = S_ASK_LOGIN_TYPE; app->query_args->state = S_ASK_LOGIN_TYPE;
app->modal.needs_destroy = true; 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) { dialogue_t *init_register_modal(app_t *app) {
if (app == NULL) if (app == NULL)
return NULL; return NULL;
group_el_init_t content[] = { group_el_init_t content_name_email[] = {
{.type = w_input, .label = "Username", .length = 15}, {.type = w_input, .label = "Username", .length = 18},
{.type = w_input, {.type = w_input, .label = "Email", .length = 18},
{.type = w_end}};
group_el_init_t content_pass[] = {{.type = w_input,
.label = "Password", .label = "Password",
.length = 15, .length = 18,
.is_hidden_value = true}, .is_hidden_value = true},
{.type = w_input, {.type = w_input,
.label = "Password (repeat)", .label = "Password (repeat)",
.length = 15, .length = 18,
.is_hidden_value = true}, .is_hidden_value = true},
{.type = w_end}}; {.type = w_end}};
group_el_init_t content[] = {
{.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[] = { group_el_init_t actions[] = {
{.type = w_button, .label = "Register", .is_default = true}, {.type = w_button, .label = "Register", .is_default = true, .val.num = 1},
{.type = w_button, .label = "Cancel", .is_default = false}, {.type = w_button, .label = "Cancel", .is_default = false, .val.num = 2},
{.type = w_end}}; {.type = w_end}};
init_dialogue(&(app->modal), "Credentials", "There is information needed", 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); dialogue_t *d = &(app->modal);
d->w.callback = init_register_modal_cb; d->w.callback = init_register_modal_cb;
d->g_content = init_group(&(d->win), &(d->w), content, horizontal); d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map),
d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); horizontal, g_content);
d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map),
horizontal, g_action);
dialogue_init_active_id(d); dialogue_init_active_id(d);
+6 -7
View File
@@ -1,3 +1,4 @@
#include "group.h"
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@@ -11,18 +12,16 @@ typedef struct {
} group_bt_t; } group_bt_t;
void server_message_modal_cb(callback_args_t *args) { void server_message_modal_cb(callback_args_t *args) {
int32_t response;
callback_args_t d_args; callback_args_t d_args;
app_t *app = args->app; app_t *app = args->app;
dialogue_t *d = (dialogue_t *)app->active_widget; dialogue_t *d = (dialogue_t *)app->active_widget;
memcpy(&d_args, args, sizeof(callback_args_t)); memcpy(&d_args, args, sizeof(callback_args_t));
d_args.app = NULL; d_args.app = NULL;
d_args.resp_data = &response;
d_args.element = app->active_widget; d_args.element = app->active_widget;
dialogue_default_callback(&d_args); dialogue_default_callback(&d_args);
if (response > -1) { if (d_args.resp_data.code == cbrp_val) {
switch (response) { switch (d_args.resp_data.val.val.num) {
case 0: case 1:
d->needs_destroy = true; d->needs_destroy = true;
/* TODO: macros */ /* TODO: macros */
free(app->query_args->server_message.text); free(app->query_args->server_message.text);
@@ -39,12 +38,12 @@ void *init_server_message_modal(app_t *app) {
if (app == NULL) if (app == NULL)
return NULL; return NULL;
group_el_init_t children[] = { 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", init_dialogue(&(app->modal), "Server response",
app->query_args->server_message.text, &(app->coordinates)); app->query_args->server_message.text, &(app->coordinates));
app->modal.g_action = 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; app->modal.w.callback = server_message_modal_cb;
dialogue_init_active_id(&(app->modal)); dialogue_init_active_id(&(app->modal));
+10 -7
View File
@@ -1,22 +1,22 @@
#include "../file_processor.h" #include "../file_processor.h"
#include <widget.h> #include "group.h"
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <widget.h>
void upload_dialogue_modal_cb(callback_args_t *args) { void upload_dialogue_modal_cb(callback_args_t *args) {
int32_t response = -1;
callback_args_t d_args; callback_args_t d_args;
app_t *app = args->app; app_t *app = args->app;
dialogue_t *d = (dialogue_t *)app->active_widget; dialogue_t *d = (dialogue_t *)app->active_widget;
memcpy(&d_args, args, sizeof(callback_args_t)); memcpy(&d_args, args, sizeof(callback_args_t));
d_args.app = NULL; d_args.app = NULL;
d_args.resp_data = &response;
d_args.element = app->active_widget; d_args.element = app->active_widget;
dialogue_default_callback(&d_args); dialogue_default_callback(&d_args);
ui_fs_file_list_t *fui = ui_fs_file_list_t *fui =
(ui_fs_file_list_t *)d->g_content->elements[0].element; (ui_fs_file_list_t *)d->g_content->elements[0].element;
switch (response) { if (d_args.resp_data.code == cbrp_val) {
switch (d_args.resp_data.val.val.num) {
case 0: case 0:
app->query_args->state = S_WAIT_SERVER; app->query_args->state = S_WAIT_SERVER;
d->needs_destroy = true; d->needs_destroy = true;
@@ -31,6 +31,7 @@ void upload_dialogue_modal_cb(callback_args_t *args) {
app->query_args->state = WAIT_CLIENT; app->query_args->state = WAIT_CLIENT;
} }
} }
}
dialogue_t *init_upload_dialogue_modal(app_t *app) { dialogue_t *init_upload_dialogue_modal(app_t *app) {
if (app == NULL) if (app == NULL)
@@ -41,7 +42,7 @@ dialogue_t *init_upload_dialogue_modal(app_t *app) {
{.type = w_end}}; {.type = w_end}};
group_el_init_t actions[] = { 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; app->modal.w.parent_win = &app->win;
init_dialogue(&(app->modal), "Upload new file", "Enter essential data", 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); dialogue_t *d = &(app->modal);
d->w.callback = upload_dialogue_modal_cb; d->w.callback = upload_dialogue_modal_cb;
d->g_content = init_group(&(d->win), &(d->w), content, horizontal); d->g_content = init_group(&(d->win), &(d->w), content, &(d->id_map),
d->g_action = init_group(&(d->win), &(d->w), actions, horizontal); 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; app->query_args->active_dialogue = d;
+7 -8
View File
@@ -1,3 +1,4 @@
#include "group.h"
#include <widget.h> #include <widget.h>
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
@@ -7,20 +8,18 @@
#include <unistd.h> #include <unistd.h>
void upload_props_dialogue_modal_cb(callback_args_t *args) { void upload_props_dialogue_modal_cb(callback_args_t *args) {
int32_t response = -1;
callback_args_t d_args; callback_args_t d_args;
app_t *app = args->app; app_t *app = args->app;
dialogue_t *d = (dialogue_t *)app->active_widget; dialogue_t *d = (dialogue_t *)app->active_widget;
memcpy(&d_args, args, sizeof(callback_args_t)); memcpy(&d_args, args, sizeof(callback_args_t));
d_args.app = NULL; d_args.app = NULL;
d_args.resp_data = &response;
d_args.element = app->active_widget; d_args.element = app->active_widget;
dialogue_default_callback(&d_args); dialogue_default_callback(&d_args);
char query[256]; char query[256];
int32_t query_len = 0; int32_t query_len = 0;
input_t *desc_input = (input_t *)d->g_content->elements[0].element; input_t *desc_input = (input_t *)d->g_content->elements[0].element;
if (response > -1) { if (d_args.resp_data.code == cbrp_val) {
switch (response) { switch (d_args.resp_data.val.val.num) {
case 0: case 0:
query_len = query_len =
sprintf(query, "file upload \"%s\" %zu 1\n", 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}}; {.type = w_end}};
group_el_init_t actions[] = { group_el_init_t actions[] = {
{.type = w_button, .label = "Upload", .is_default = 1}, {.type = w_button, .label = "Upload", .is_default = true},
{.type = w_button, .label = "Cancel", .is_default = 0}, {.type = w_button, .label = "Cancel", .is_default = false},
{.type = w_end}, {.type = w_end},
}; };
@@ -64,8 +63,8 @@ dialogue_t *init_upload_props_dialogue_modal(app_t *app) {
dialogue_t *d = &(app->modal); dialogue_t *d = &(app->modal);
d->w.callback = upload_props_dialogue_modal_cb; d->w.callback = upload_props_dialogue_modal_cb;
d->g_content = init_group(&(d->win), &(d->w), content, 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, horizontal); d->g_action = init_group(&(d->win), &(d->w), actions, &(d->id_map), horizontal, g_action);
app->query_args->active_dialogue = d; app->query_args->active_dialogue = d;
+5 -3
View File
@@ -16,7 +16,6 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "app.h"
#include "connection.h" #include "connection.h"
#include "draw_modal.h" #include "draw_modal.h"
#include "file_processor.h" #include "file_processor.h"
@@ -25,6 +24,7 @@
#include "server.h" #include "server.h"
#include "types.h" #include "types.h"
#include "widget/app.h" #include "widget/app.h"
#include "widget_core/widget_core.h"
static void wait_side(app_t *app); static void wait_side(app_t *app);
void user_request_description(query_args_t *q_args); void user_request_description(query_args_t *q_args);
@@ -45,8 +45,10 @@ void query_loop(app_t *app) {
size_t qlen; size_t qlen;
int sr; int sr;
static file_args_t file_args; static file_args_t file_args;
callback_args_t d_args = { callback_args_t d_args = {.app = app,
.app = app, .element = NULL, .data = NULL, .resp_data = NULL}; .element = NULL,
.data = NULL,
.resp_data.code = cbrc_none};
init_file_args(&file_args); init_file_args(&file_args);
query_args->sd = sd; query_args->sd = sd;
+15
View File
@@ -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}
)
+34
View File
@@ -0,0 +1,34 @@
#include "d_array.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
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;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef D_ARRAY_H
#define D_ARRAY_H
/* Dynamic array of numbers */
#include <stdint.h>
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
+4
View File
@@ -0,0 +1,4 @@
#ifndef D_UTILS_H
#define D_UTILS_H
#include "d_array.h"
#endif
+2
View File
@@ -18,7 +18,9 @@ target_link_libraries(widget
PRIVATE PRIVATE
bstring bstring
widget_core widget_core
utils
) )
target_include_directories(widget PRIVATE "../widget_core") target_include_directories(widget PRIVATE "../widget_core")
target_include_directories(widget PRIVATE "../lib/") target_include_directories(widget PRIVATE "../lib/")
target_include_directories(widget PRIVATE "../utils/")
-1
View File
@@ -10,7 +10,6 @@
typedef enum { typedef enum {
modal_color_pair = 3, modal_color_pair = 3,
modal_border_color_pair = 4,
} color; } color;
typedef enum { typedef enum {
+10 -2
View File
@@ -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) { int32_t draw_button(button_t *btn, uint32_t active_id) {
char title[DIALOGUE_TITLE + 6]; char title[DIALOGUE_TITLE + 6];
WINDOW *win = *(btn->w.parent_win); WINDOW *win = *(btn->w.parent_win);
uint32_t margin_y = btn->w.m_y + btn->w.w_parent->m_y; uint32_t margin_y = btn->w.m_y;
uint32_t margin_x = btn->w.m_x + btn->w.w_parent->m_x; 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) { if (btn->w.id == active_id) {
sprintf(title, "[< %s >]", btn->w.title); sprintf(title, "[< %s >]", btn->w.title);
-1
View File
@@ -1,7 +1,6 @@
#ifndef BUTTON_H #ifndef BUTTON_H
#define BUTTON_H #define BUTTON_H
#include "../main.h"
#include <widget_core.h> #include <widget_core.h>
#include <stdint.h> #include <stdint.h>
+81 -139
View File
@@ -8,25 +8,41 @@
#include "file_list.h" #include "file_list.h"
#include "group.h" #include "group.h"
#include "input.h" #include "input.h"
#include "widget_core.h"
#define INCR_ACTIVE_ID(d, current, next) \ void incr_active_id(dialogue_t *d) {
if (d->active.id != d->current->last_id) { \ group_el_t *active_el = NULL;
d->active.id = d->active.id + 1; \ while (true) {
} else if (d->next != NULL) { \ for (int i = d->active_el->id + 1;
d->active.id = d->next->first_id; \ active_el == NULL && d->id_map.length > i; i++) {
d->active.type = next; \ active_el = d->id_map.arr[i];
} else { \ }
d->active.id = d->current->first_id; \ 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) \ void decr_active_id(dialogue_t *d) {
if (d->active.id != d->current->first_id) { \ group_el_t *active_el = NULL;
d->active.id = d->active.id - 1; \ while (true) {
} else if (d->next != NULL) { \ for (int i = d->active_el->id - 1; active_el == NULL && i > 0; i--) {
d->active.id = d->next->last_id; \ active_el = d->id_map.arr[i];
d->active.type = next; \ }
} else { \ d->active_el = active_el;
d->active.id = d->current->last_id; \ 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) \ #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) { void dialogue_default_callback(callback_args_t *args) {
dialogue_t *d = (void *)args->element; dialogue_t *d = (void *)args->element;
int32_t key = *((int32_t *)args->data); int32_t key = *((int32_t *)args->data);
callback_args_t new_args; callback_args_t new_args;
int32_t *resp_value = (int32_t *)args->resp_data;
memcpy(&new_args, args, sizeof(callback_args_t)); 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; int32_t diff;
d->needs_update = true; d->needs_update = true;
input_t *input; input_t *input;
widget_t *widget; widget_t *widget;
switch (key) { switch (key) {
case '\t': case '\t':
if (d->active.type == g_content) { incr_active_id(d);
INCR_ACTIVE_ID(d, g_content, g_action); args->resp_data.code = cbrc_none;
} else if (d->active.type == g_action) {
INCR_ACTIVE_ID(d, g_action, g_content);
}
*resp_value = -1;
break; break;
case '\33': /* Esc key */ case '\33': /* Esc key */
*resp_value = -2; args->resp_data.code = cbrp_val;
args->resp_data.val.val.num = -2;
break; break;
case KEY_RIGHT: case KEY_RIGHT:
if (d->active.type == g_content) { incr_active_id(d);
if (d->g_content->elements[d->active.id - d->g_content->first_id].type == args->resp_data.code = cbrc_none;
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;
break; break;
case KEY_LEFT: case KEY_LEFT:
if (d->active.type == g_content) { decr_active_id(d);
if (d->g_content->elements[d->active.id - d->g_content->first_id].type == args->resp_data.code = cbrc_none;
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;
break; break;
case '\n': case '\n':
widget = get_active_widget(d); widget = (widget_t *)d->active_el->element;
if (widget->callback != NULL) { /* Existing callback case */ if (widget->callback != NULL) { /* Existing callback case */
new_args.element = widget; new_args.element = widget;
widget->callback(&new_args); widget->callback(&new_args);
break; break;
} /* Default cases */ } /* Default cases */
if (d->active.type == g_action) { if (d->active_el->g_type == g_action) {
new_args.element = d->g_action; new_args.element = d->g_action;
group_default_callback(&new_args); group_default_callback(&new_args);
mempcpy(&(args->resp_data), &(new_args.resp_data),
sizeof(new_args.resp_data));
} else if (d->g_action != NULL) { } else if (d->g_action != NULL) {
for (int i = 0; i < d->g_action->count; i++) { for (int i = 0; i < d->g_action->count; i++) {
if (d->g_action->elements[i].is_default) { 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; return;
} }
} }
} else { } else {
/* TODO: temp solution, improve */ args->resp_data.code = cbrp_val;
*resp_value = d->active.id - d->g_content->first_id; args->resp_data.val.val.num = d->active_el->idx;
return; return;
} }
break; break;
case KEY_UP: case KEY_UP:
if (d->g_content->elements[d->active.id - d->g_content->first_id].type == if (d->active_el->type == w_fs_file_list) {
w_fs_file_list) {
new_args.element = d->g_content; new_args.element = d->g_content;
group_default_callback(&new_args); group_default_callback(&new_args);
} else { } else {
CH_GROUP(d, g_action, g_content); /* CH_GROUP(d, g_action, g_content); */
} }
break; break;
case KEY_DOWN: case KEY_DOWN:
if (d->g_content->elements[d->active.id - d->g_content->first_id].type == if (d->active_el->type == w_fs_file_list) {
w_fs_file_list) {
new_args.element = d->g_content; new_args.element = d->g_content;
group_default_callback(&new_args); group_default_callback(&new_args);
} else { } else {
CH_GROUP(d, g_content, g_action); /* CH_GROUP(d, g_content, g_action); */
} }
break; break;
default: default:
/* run callback function */ /* run callback function */
if (d->active.type == g_content) { if (d->active_el->g_type == g_content) {
new_args.element = d->g_content; new_args.element = d->g_content;
} else { } else {
new_args.element = d->g_action; new_args.element = d->g_action;
@@ -178,66 +154,41 @@ void init_dialogue(dialogue_t *dialogue, const char title[], const char text[],
strcpy(dialogue->w.title, title); strcpy(dialogue->w.title, title);
t_size = strlen(text); t_size = strlen(text);
strcpy(dialogue->text, text); strcpy(dialogue->text, text);
init_d_arr_ptr(&(dialogue->id_map), MAX_IDS);
/* trim the last new line symbol */ /* 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) { void dialogue_init_active_id(dialogue_t *dialogue) {
enum w_type widget_type;
if (dialogue->g_content != NULL) { if (dialogue->g_content != NULL) {
for (int i = 0; i < dialogue->g_content->count; i++) { if (group_init_active_id(dialogue->g_content, dialogue)) {
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; return;
} }
} }
}
if (dialogue->g_action != NULL) { if (dialogue->g_action != NULL) {
for (int i = 0; i < dialogue->g_action->count; i++) { if (group_init_active_id(dialogue->g_action, dialogue)) {
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; 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) \ #define DETECT_GROUP_SIZE(group, line_max_len, y, x) \
if (group) { \ if (group) { \
@@ -259,7 +210,6 @@ int32_t draw_dialogue(dialogue_t *d) {
} }
group_el_t *ae_ptr = NULL; /* active element */ group_el_t *ae_ptr = NULL; /* active element */
uint32_t ae_idx; /* active element */
/* count dimensions */ /* count dimensions */
uint32_t x = 1; /* when uses box */ uint32_t x = 1; /* when uses box */
uint32_t y = 1; /* when uses box */ uint32_t y = 1; /* when uses box */
@@ -317,23 +267,15 @@ int32_t draw_dialogue(dialogue_t *d) {
wattroff(d->win, A_REVERSE); wattroff(d->win, A_REVERSE);
if (d->g_content != NULL) { 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) { 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 */ /* move cursor */
if (d->g_content != NULL) { if (d->active_el != NULL && d->active_el->type == w_input) {
FIND_ACTIVE_ELEMENT(d->g_content, d->active.id, ae_ptr, ae_idx); input_t *input = d->active_el->element;
}
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.y = input->w.cur.y;
d->w.cur.x = input->w.cur.x + input->value_len; d->w.cur.x = input->w.cur.x + input->value_len;
d->w.cur.x -= input->cur_pos; d->w.cur.x -= input->cur_pos;
@@ -341,10 +283,10 @@ int32_t draw_dialogue(dialogue_t *d) {
wmove(d->win, d->w.cur.y, d->w.cur.x); wmove(d->win, d->w.cur.y, d->w.cur.x);
curs_set(true); curs_set(true);
} }
} else { } else {
curs_set(false); curs_set(false);
} }
}
d->needs_update = false; d->needs_update = false;
+7 -8
View File
@@ -6,8 +6,9 @@
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
#include <widget_core.h> #include <widget_core.h>
#include <utils.h>
#define MAX_IDS 64
enum g_type { g_content, g_action };
enum d_color_scheme { dc_normal, dc_alert }; enum d_color_scheme { dc_normal, dc_alert };
typedef struct { typedef struct {
@@ -15,16 +16,14 @@ typedef struct {
WINDOW *win; WINDOW *win;
group_t *g_content; group_t *g_content;
group_t *g_action; group_t *g_action;
struct { group_el_t *active_el;
int32_t id;
enum g_type type;
} active;
char text[DIALOGUE_TEXT]; char text[DIALOGUE_TEXT];
uint32_t is_initiated : 1; bool is_initiated;
uint32_t needs_update : 1; bool needs_update;
uint32_t needs_destroy : 1; bool needs_destroy;
coordinates_t *p_coordinates; coordinates_t *p_coordinates;
enum d_color_scheme color_scheme; enum d_color_scheme color_scheme;
d_array_ptr_t id_map;
} dialogue_t; } dialogue_t;
void init_dialogue(dialogue_t *d, const char title[], const char text[], void init_dialogue(dialogue_t *d, const char title[], const char text[],
+9 -2
View File
@@ -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->max_lines = getmaxy(parent_win) - 3; /* 2+1 (bottom info line) */
fui->active_search = false; fui->active_search = false;
fui->search_key = bfromcstrrangealloc(12, 64, ""); fui->search_key = bfromcstrrangealloc(12, 64, "");
fui->start = NULL;
fui->current = NULL;
return fui; 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 */ int32_t sz_y_f = sz_y - 2; /* TODO: можно заменить на поле max_lines */
p_y = 1; p_y = 1;
p_x = 1; p_x = 1;
fl_item_t *el = *(fui->start); fl_item_t *el = NULL;
fl_item_t *active_el = *(fui->start); fl_item_t *active_el = NULL;
int32_t cur_el_idx = 0; int32_t cur_el_idx = 0;
curs_set(false); curs_set(false);
if (fui->start != NULL) {
el = *(fui->start);
active_el = el;
}
if (fui->activate_last) { if (fui->activate_last) {
fui->current_idx = fui->current_count - 1; fui->current_idx = fui->current_count - 1;
fui->activate_last = false; fui->activate_last = false;
+1 -1
View File
@@ -133,7 +133,7 @@ void fs_file_list_cb(callback_args_t *args) {
} }
break; break;
case '\n': case '\n':
select_item(fui, (int32_t *) args->resp_data); select_item(fui, (int32_t *) args->resp_data.val.val.num);
break; break;
} }
} }
+66 -29
View File
@@ -1,37 +1,33 @@
#include "group.h" #include "group.h"
#include "button.h" #include "button.h"
#include "d_array.h"
#include "fs_file_list.h" #include "fs_file_list.h"
#include "input.h" #include "input.h"
#include "progress_bar.h" #include "progress_bar.h"
#include "widget_core.h"
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <utils.h>
#define MAKE_RESPONSE_M1(args, resp_data, response) \
if (args->resp_data != NULL) { \
*response = -1; \
}
void group_default_callback(callback_args_t *args) { void group_default_callback(callback_args_t *args) {
group_t *g = (group_t *)args->element; group_t *g = (group_t *)args->element;
int32_t key = *((int32_t *)args->data); 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; input_t *input;
widget_t *widget; widget_t *widget;
group_el_t *element_ptr; group_el_t *element_ptr = args->active_el;
int32_t element_idx = -1;
u_int32_t start_pos = 0; u_int32_t start_pos = 0;
callback_args_t new_args; callback_args_t new_args;
switch (key) { switch (key) {
case '\n': /* Enter */ case '\n': /* Enter */
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx); args->resp_data.code = cbrp_val;
*response = element_idx; mempcpy(&(args->resp_data.val), &(element_ptr->val), sizeof(struct val_t));
break; break;
case KEY_BACKSPACE: case KEY_BACKSPACE:
case KEY_DL: case KEY_DL:
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
if (element_ptr->type == w_input) { if (element_ptr->type == w_input) {
input = (input_t *)element_ptr->element; input = (input_t *)element_ptr->element;
if (input->value_len) { 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; break;
default: default:
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
if (element_ptr->type == w_input) { if (element_ptr->type == w_input) {
input = (input_t *)element_ptr->element; input = (input_t *)element_ptr->element;
if (input->max_len > input->value_len) { if (input->max_len > input->value_len) {
@@ -62,6 +57,7 @@ void group_default_callback(callback_args_t *args) {
} }
} }
} else { } else {
/* callback case */
widget = (widget_t *)element_ptr->element; widget = (widget_t *)element_ptr->element;
if (widget->callback != NULL) { if (widget->callback != NULL) {
memccpy(&new_args, args, 1, sizeof(callback_args_t)); memccpy(&new_args, args, 1, sizeof(callback_args_t));
@@ -70,14 +66,22 @@ void group_default_callback(callback_args_t *args) {
break; break;
} }
} }
MAKE_RESPONSE_M1(args, resp_data, response); args->resp_data.code = cbrc_none;
break; 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, 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)); 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, ""); init_widget(&(group->w), w_parent, win, "");
/* count elements */ /* count elements */
group->count = 0; 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++) { for (int32_t i = 0; i < group->count; i++) {
elements[i].type = children[i].type; elements[i].type = children[i].type;
elements[i].is_default = children[i].is_default; 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 */ /* 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) { switch (elements[i].type) {
case w_button: case w_button:
elements[i].element = init_button(win, &(group->w), children[i].label); 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); w = &(((button_t *)elements[i].element)->w);
break; break;
case w_box: case w_box:
case w_group:
case w_end: case w_end:
break; 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: case w_input:
elements[i].element = elements[i].element =
init_input(win, &(group->w), children[i].label, children[i].length, init_input(win, &(group->w), children[i].label, children[i].length,
@@ -122,15 +144,7 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
w = &(((ui_progress_bar_t *)elements[i].element)->w); w = &(((ui_progress_bar_t *)elements[i].element)->w);
break; break;
} }
/* set dimensions */ if (current.type != w_group) {
elements[i].id = 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) { if (i == 0) {
group->first_id = w->id; group->first_id = w->id;
group->last_id = w->id; group->last_id = w->id;
@@ -138,12 +152,31 @@ group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
group->last_id = w->id; 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;
} else {
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; return group;
} }
void draw_group(WINDOW *win, group_t *group, int32_t active_id, void draw_group(WINDOW *win, group_t *group, int32_t active_id) {
widget_t *dialog_w) {
group_el_t *children = group->elements; group_el_t *children = group->elements;
for (int i = 0; i < group->count; i++) { for (int i = 0; i < group->count; i++) {
group_el_t *el = &children[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: case w_button:
draw_button((button_t *)el->element, active_id); draw_button((button_t *)el->element, active_id);
break; break;
case w_box:
case w_group: case w_group:
draw_group(win, (group_t *)el->element, active_id);
break;
case w_box:
case w_end: case w_end:
break; break;
case w_input: case w_input:
@@ -176,8 +211,10 @@ void destroy_group(group_t *group) {
case w_button: case w_button:
destroy_button(el->element); destroy_button(el->element);
break; break;
case w_box:
case w_group: case w_group:
destroy_group(el->element);
break;
case w_box:
case w_end: case w_end:
break; break;
case w_input: case w_input:
+14 -23
View File
@@ -2,44 +2,35 @@
#define GROUP_H #define GROUP_H
#include <stdint.h> #include <stdint.h>
#include <utils.h>
#include <widget_core.h> #include <widget_core.h>
enum g_direction { typedef struct group_el_init_t {
horizontal,
vertical,
};
typedef struct {
uint32_t id;
void *element;
enum w_type type; enum w_type type;
uint32_t is_default : 1; bool is_default;
} group_el_t; bool is_hidden_value;
typedef struct {
enum w_type type;
uint32_t is_default : 1;
uint32_t is_hidden_value : 1;
char label[DIALOGUE_TITLE]; char label[DIALOGUE_TITLE];
uint32_t length; uint32_t length;
enum g_direction direction;
union {
int64_t num;
} val;
struct group_el_init_t *children;
} group_el_init_t; } group_el_init_t;
typedef struct { typedef struct group_t {
widget_t w; widget_t w;
group_el_t *elements; group_el_t *elements;
enum g_direction direction; enum g_direction direction;
uint32_t count; uint32_t count;
uint32_t first_id, last_id; uint32_t first_id, last_id;
struct group_t *parent_group;
} group_t; } 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, group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
enum g_direction dir); d_array_ptr_t *id_map, enum g_direction dir,
void draw_group(WINDOW *win, group_t *group, int32_t active_id, enum g_type g_type);
widget_t *dialog_w); void draw_group(WINDOW *win, group_t *group, int32_t active_id);
void destroy_group(group_t *group); void destroy_group(group_t *group);
void group_default_callback(callback_args_t *args); void group_default_callback(callback_args_t *args);
+22 -9
View File
@@ -4,8 +4,8 @@
#include <string.h> #include <string.h>
#include "app.h" #include "app.h"
#include <widget_core.h>
#include "input.h" #include "input.h"
#include <widget_core.h>
input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, input_t *init_input(WINDOW **win, widget_t *w_parent, char *label,
uint32_t length, uint32_t is_hidden_value) { uint32_t length, uint32_t is_hidden_value) {
@@ -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) { int32_t draw_input(input_t *input, uint32_t active_id) {
const char stars[] = "*******************"; const char stars[] = "*******************";
WINDOW *win = *(input->w.parent_win); WINDOW *win = *(input->w.parent_win);
uint32_t margin_y = input->w.m_y + input->w.w_parent->m_y; uint32_t margin_y = input->w.m_y;
uint32_t margin_x = input->w.m_x + input->w.w_parent->m_x; 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, margin_x, 0, input->w.x);
mvwhline(win, margin_y + 2, 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 // left
mvwvline(win, margin_y, margin_x, ACS_ULCORNER, 1); mvwvline(win, margin_y, margin_x, ACS_ULCORNER, 1);
mvwvline(win, margin_y + 1, margin_x, 0, 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 + 1, margin_x + input->w.x - 1, 0, 1);
mvwvline(win, margin_y + 2, margin_x + input->w.x - 1, ACS_LRCORNER, 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++; margin_x++;
if (input->w.id == active_id) { if (input->w.id == active_id) {
@@ -57,11 +70,11 @@ int32_t draw_input(input_t *input, uint32_t active_id) {
} }
if (input->is_hidden) { if (input->is_hidden) {
mvwprintw(win, margin_y + 1, margin_x, "%.*s%*s", (int) input->value_len, stars, mvwprintw(win, margin_y + 1, margin_x, "%.*s%*s", (int)input->value_len,
input->w.x - input->value_len - 2, ""); stars, (int)(input->w.x - input->value_len - 2), "");
} else { } else {
mvwprintw(win, margin_y + 1, margin_x, "%s%*s", input->value, 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.y = margin_y + 1;
+5 -5
View File
@@ -8,11 +8,11 @@
typedef struct { typedef struct {
widget_t w; widget_t w;
char value[INPUT_TEXT]; char value[INPUT_TEXT];
uint32_t cur_pos; /* is relative to the end of a string */ int64_t cur_pos; /* is relative to the end of a string */
uint32_t value_len; int64_t value_len;
uint32_t max_len; int64_t max_len;
uint32_t is_disabled : 1; bool is_disabled;
uint32_t is_hidden : 1; bool is_hidden;
} input_t; } input_t;
input_t *init_input(WINDOW **win, widget_t *w_parent, char *label, input_t *init_input(WINDOW **win, widget_t *w_parent, char *label,
-1
View File
@@ -8,5 +8,4 @@
#include "group.h" #include "group.h"
#include "input.h" #include "input.h"
#include "progress_bar.h" #include "progress_bar.h"
#endif #endif
+52 -11
View File
@@ -5,6 +5,13 @@
#include <ncurses.h> #include <ncurses.h>
#include <stdint.h> #include <stdint.h>
enum g_type { g_content, g_action };
enum g_direction {
horizontal,
vertical,
};
enum w_type { enum w_type {
w_end, w_end,
w_button, w_button,
@@ -15,12 +22,46 @@ enum w_type {
w_fs_file_list, 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 { typedef struct {
void *app; void *app;
void *element; void *element;
void *data; void *data;
void *resp_data; struct {
uint32_t active_id; enum cbrp_code code;
struct val_t val;
} resp_data;
void *active_el;
} callback_args_t; } callback_args_t;
enum rsize { enum rsize {
@@ -34,19 +75,18 @@ enum rsize {
}; };
typedef struct widget_t { typedef struct widget_t {
uint32_t id; int64_t id;
char title[DIALOGUE_TITLE]; char title[DIALOGUE_TITLE];
uint32_t x; int64_t x;
uint32_t y; int64_t y;
uint32_t m_x; int64_t m_x;
uint32_t m_y; int64_t m_y;
struct { struct {
uint32_t y; int64_t y;
uint32_t x; int64_t x;
} cur; } cur;
WINDOW *const *parent_win; WINDOW *const *parent_win;
struct widget_t *w_parent; struct widget_t *w_parent;
// enum rsize rsize;
void (*callback)(callback_args_t *args); void (*callback)(callback_args_t *args);
} widget_t; } widget_t;
@@ -59,7 +99,8 @@ enum pmt_attrs {
void init_widget(widget_t *w, widget_t *w_parent, WINDOW **win, char *title); 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); 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); const uint32_t x, const uint16_t attrs);
#endif #endif