CMake integration

This commit is contained in:
2026-02-09 17:44:07 +02:00
parent ba77017857
commit 6dd887d502
55 changed files with 247 additions and 183 deletions
+22
View File
@@ -0,0 +1,22 @@
add_library(widget STATIC)
file(GLOB M_HEADERS "*.h")
file(GLOB M_SOURCES "*.c")
list(REMOVE_ITEM M_HEADERS "widget.h")
target_sources(widget
PRIVATE
${M_SOURCES}
PUBLIC
FILE_SET HEADERS
FILES
${M_HEADERS}
)
target_link_libraries(widget
PRIVATE
ui-widget-core
)
target_include_directories(widget PRIVATE "../ui-widget-core")
+136
View File
@@ -0,0 +1,136 @@
#include "app.h"
#include <ncurses.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
void ac_file(WINDOW *win, int is_action_w);
app_t *init_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));
/* 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->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 / 10 * 4;
int32_t right_w_x = x_max - left_w_x - 2;
/* create the menu window */
_app->left_win = newwin(y_max - 4, left_w_x, 2, 1);
/* create the action window */
_app->right_win = newwin(y_max - 4, right_w_x, 2, left_w_x + 1);
/* dialogue */
_app->modal.win = NULL;
_app->modal.is_initiated = 0;
/* default win */
_app->active_win_type = aw_left;
/* print decorative bars */
print_bars(_app);
/* here goes box borders */
draw_borders(_app);
keypad(_app->win, TRUE);
/* refresh the windows */
wnoutrefresh(_app->win);
wnoutrefresh(_app->left_win);
wnoutrefresh(_app->right_win);
doupdate();
return _app;
}
void init_nc() {
initscr();
cbreak();
keypad(stdscr, TRUE);
noecho();
curs_set(false);
set_escdelay(50);
if (!has_colors()) {
printf("Your terminal does not support color\n");
} else {
start_color();
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(modal_color_pair, COLOR_BLUE, COLOR_WHITE);
}
}
void draw_borders(app_t *app) {
if (app->modal.win != NULL && !app->modal.needs_update) {
return;
}
clear();
box(app->win, 0, 0);
box(app->left_win, 0, 0);
box(app->right_win, 0, 0);
}
void print_bars(app_t *app) {
char top_text[64] = "Hello!";
wattrset(app->win, A_REVERSE);
/* print top and bottom bars */
for (int i = 1; i < app->coordinates.cur_x - 1; i++) {
mvwprintw(app->win, 1, i, " ");
mvwprintw(app->win, app->coordinates.cur_y - 2, i, " ");
}
/* add content to the top bar */
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 | U - upload | F9 - Quit");
wattroff(app->win, A_REVERSE);
}
void app_refresh(app_t *app) {
draw_borders(app);
wnoutrefresh(app->win);
wnoutrefresh(app->left_win);
wnoutrefresh(app->right_win);
if (app->modal.win != NULL) {
if (app->modal.is_initiated != 0) {
wnoutrefresh(app->modal.win);
}
}
doupdate();
}
void destroy_app(app_t *app, int32_t exit_code) {
delwin(app->win);
endwin();
app->win = NULL;
exit(exit_code);
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef N_APP_H
#define N_APP_H
#include "../main.h"
#include "../common.h"
#include "dialogue.h"
#include <ncurses.h>
#include <ui-widget-core.h>
typedef enum {
modal_color_pair = 3,
modal_border_color_pair = 4,
} color;
typedef enum {
aw_left,
aw_right,
aw_modal
} active_win_t;
typedef struct {
WINDOW *win;
WINDOW *left_win;
WINDOW *right_win;
dialogue_t modal;
params_t *params;
coordinates_t coordinates;
query_args_t *query_args;
file_args_t *file_args;
int32_t read_fd;
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();
void init_nc();
void destroy_app(app_t *app, int32_t exit_code);
void draw_borders(app_t *app);
void print_bars(app_t *app);
void app_refresh(app_t *app);
void app_draw_modal(app_t *app);
#endif // N_APP_H
+43
View File
@@ -0,0 +1,43 @@
#include <ncurses.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "app.h"
#include <ui-widget-core.h>
#include "button.h"
button_t *init_button(WINDOW **win, widget_t *w_parent, char *label) {
button_t *btn = malloc(sizeof(button_t));
init_widget(&(btn->w), w_parent, win, label);
btn->is_disabled = 0;
btn->w.x = strlen(btn->w.title) + 6; // + "[ ]"
btn->w.y = 1; // TODO: detect new line
btn->w.cur.y = 0;
btn->w.cur.x = 0;
return btn;
}
int32_t draw_button(button_t *btn, uint32_t active_id) {
char title[DIALOGUE_TITLE + 6];
WINDOW *win = *(btn->w.parent_win);
uint32_t margin_y = btn->w.m_y + btn->w.w_parent->m_y;
uint32_t margin_x = btn->w.m_x + btn->w.w_parent->m_x;
if (btn->w.id == active_id) {
sprintf(title, "[< %s >]", btn->w.title);
wattrset(win, COLOR_PAIR(modal_color_pair) | A_BOLD | A_REVERSE);
} else {
sprintf(title, "[ %s ]", btn->w.title);
wattrset(win, COLOR_PAIR(0) | A_REVERSE);
}
mvwprintw(win, margin_y, margin_x, "%s", title);
btn->w.cur.y = margin_y;
btn->w.cur.x = margin_x;
wattroff(win, A_BOLD | A_REVERSE);
return strlen(title);
}
void destroy_button(button_t *btn) { free(btn); }
+17
View File
@@ -0,0 +1,17 @@
#ifndef BUTTON_H
#define BUTTON_H
#include "../main.h"
#include <ui-widget-core.h>
#include <stdint.h>
typedef struct {
widget_t w;
char hotkey;
uint32_t is_disabled : 1;
} button_t;
button_t *init_button(WINDOW **win, widget_t *w_parent, char *label);
int32_t draw_button(button_t *btn, uint32_t active_id);
void destroy_button(button_t *btn);
#endif
+359
View File
@@ -0,0 +1,359 @@
#include <ncurses.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include "app.h"
#include "dialogue.h"
#include "file_list.h"
#include "group.h"
#include "input.h"
#define INCR_ACTIVE_ID(d, current, next) \
if (d->active.id != d->current->last_id) { \
d->active.id = d->active.id + 1; \
} else if (d->next != NULL) { \
d->active.id = d->next->first_id; \
d->active.type = next; \
} else { \
d->active.id = d->current->first_id; \
}
#define DECR_ACTIVE_ID(d, current, next) \
if (d->active.id != d->current->first_id) { \
d->active.id = d->active.id - 1; \
} else if (d->next != NULL) { \
d->active.id = d->next->last_id; \
d->active.type = next; \
} else { \
d->active.id = d->current->last_id; \
}
#define CH_GROUP(d, current, next) \
{ \
if (d->active.type == current) { \
d->active.type = next; \
diff = d->active.id - d->current->first_id; \
if (diff > d->next->last_id - d->next->first_id) { \
d->active.id = d->next->last_id; \
} else { \
d->active.id = d->next->first_id + diff; \
} \
} \
}
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) {
dialogue_t *d = (void *)args->element;
int32_t key = *((int32_t *)args->data);
callback_args_t new_args;
int32_t *resp_value = (int32_t *)args->resp_data;
memcpy(&new_args, args, sizeof(callback_args_t));
new_args.active_id = d->active.id;
int32_t diff;
d->needs_update = true;
input_t *input;
widget_t *widget;
switch (key) {
case '\t':
if (d->active.type == g_content) {
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;
case '\33': /* Esc key */
*resp_value = -2;
break;
case KEY_RIGHT:
if (d->active.type == g_content) {
if (d->g_content->elements[d->active.id - d->g_content->first_id].type ==
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;
case KEY_LEFT:
if (d->active.type == g_content) {
if (d->g_content->elements[d->active.id - d->g_content->first_id].type ==
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;
case '\n':
widget = get_active_widget(d);
if (widget->callback != NULL) { /* Existing callback case */
new_args.element = widget;
widget->callback(&new_args);
break;
} /* Default cases */
if (d->active.type == g_action) {
new_args.element = d->g_action;
group_default_callback(&new_args);
} else if (d->g_action != NULL) {
for (int i = 0; i < d->g_action->count; i++) {
if (d->g_action->elements[i].is_default) {
*resp_value = i;
return;
}
}
} else {
/* TODO: temp solution, improve */
*resp_value = d->active.id - d->g_content->first_id;
return;
}
break;
case KEY_UP:
if (d->g_content->elements[d->active.id - d->g_content->first_id].type ==
w_fs_file_list) {
new_args.element = d->g_content;
group_default_callback(&new_args);
} else {
CH_GROUP(d, g_action, g_content);
}
break;
case KEY_DOWN:
if (d->g_content->elements[d->active.id - d->g_content->first_id].type ==
w_fs_file_list) {
new_args.element = d->g_content;
group_default_callback(&new_args);
} else {
CH_GROUP(d, g_content, g_action);
}
break;
default:
/* run callback function */
if (d->active.type == g_content) {
new_args.element = d->g_content;
} else {
new_args.element = d->g_action;
}
group_default_callback(&new_args);
}
}
void init_dialogue(dialogue_t *dialogue, const char title[], const char text[],
coordinates_t *p_coordinates) {
dialogue->win = 0;
dialogue->g_content = NULL;
dialogue->w.x = 0;
dialogue->w.y = 0;
dialogue->p_coordinates = p_coordinates;
dialogue->w.callback = dialogue_default_callback;
dialogue->is_initiated = true;
dialogue->needs_update = true;
dialogue->needs_destroy = false;
strcpy(dialogue->w.title, title);
strcpy(dialogue->text, text);
}
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;
return;
}
}
}
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;
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) \
if (group) { \
group->w.m_y = y; \
if (line_max_len < group->w.x) { \
line_max_len = group->w.x; \
group->w.m_x = 0; \
} else { \
group->w.m_x = (line_max_len - group->w.x) / 2; \
} \
y += group->w.y; \
}
int32_t draw_dialogue(dialogue_t *d) {
if (!d->is_initiated)
return -1;
else if (!d->needs_update) {
return 0;
}
group_el_t *ae_ptr = NULL; /* active element */
uint32_t ae_idx; /* active element */
/* count dimensions */
uint32_t x = 1; /* when uses box */
uint32_t y = 1; /* when uses box */
/* analyze text content */
uint32_t line_count = 0;
uint32_t line_max_len = 0;
line_max_len = get_max_line_len(d->text, &line_count);
y += line_count;
y += 2; /* margin for text */
/* analyze groups */
DETECT_GROUP_SIZE(d->g_content, line_max_len, y, x);
DETECT_GROUP_SIZE(d->g_action, line_max_len, y, x);
x += line_max_len;
x += 1; /* when uses box */
y += 1; /* when uses box */
d->w.x = x;
d->w.y = y;
d->w.m_y = (d->p_coordinates->max_y - y) / 2;
d->w.m_x = (d->p_coordinates->max_x - x) / 2;
/* render window */
if (d->win == NULL) {
d->win = newwin(y, x, d->w.m_y, d->w.m_x);
}
wattrset(d->win, COLOR_PAIR(0) | A_BOLD | A_REVERSE);
/* background */
for (int yp = 1; yp < d->w.y - 1; yp++) {
mvwprintw(d->win, yp, 1, "%*s", d->w.x, "");
}
/* title */
const uint32_t title_mx_pos = (d->w.x - strlen(d->w.title)) / 2;
box(d->win, 0, 0);
mvwprintw(d->win, 0, title_mx_pos - 1, " ");
mvwprintw(d->win, 0, title_mx_pos, "%s", d->w.title);
mvwprintw(d->win, 0, title_mx_pos + strlen(d->w.title), " ");
/* text */
wattroff(d->win, A_BOLD);
/* mvwhline(d->win, d->w.y - 3, 1, 0, d->w.x - 2); */
print_multiline_text(d->win, d->text, d->w.x, 2, 1, PMT_ALIGN_CENTER);
wattroff(d->win, A_REVERSE);
if (d->g_content != NULL) {
draw_group(d->win, d->g_content, d->active.id, &(d->w));
}
if (d->g_action != NULL) {
draw_group(d->win, d->g_action, d->active.id, &(d->w));
}
/* move cursor */
if (d->g_content != NULL) {
FIND_ACTIVE_ELEMENT(d->g_content, d->active.id, ae_ptr, ae_idx);
}
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.x = input->w.cur.x + input->value_len;
d->w.cur.x -= input->cur_pos;
if (d->w.cur.y || d->w.cur.x) {
wmove(d->win, d->w.cur.y, d->w.cur.x);
curs_set(true);
}
} else {
curs_set(false);
}
}
d->needs_update = false;
return 0;
}
void destroy_dialogue(dialogue_t *d, void *_app) {
app_t *app = (app_t *)_app;
if (d->g_content) {
destroy_group(d->g_content);
}
if (d->g_action) {
destroy_group(d->g_action);
}
delwin(d->win);
d->win = NULL;
d->is_initiated = 0;
d->needs_destroy = false;
app->active_win_type = aw_left;
app->active_win = app->left_win;
app->active_callback = file_list_cb;
app->query_args->active_dialogue = NULL;
app_refresh(app);
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef DIALOGUE_H
#define DIALOGUE_H
#include "../common.h"
#include "group.h"
#include <ncurses.h>
#include <stdint.h>
#include <ui-widget-core.h>
enum g_type { g_content, g_action };
typedef struct {
widget_t w;
WINDOW *win;
group_t *g_content;
group_t *g_action;
struct {
int32_t id;
enum g_type type;
} active;
char text[DIALOGUE_TEXT];
uint32_t is_initiated : 1;
uint32_t needs_update : 1;
uint32_t needs_destroy: 1;
coordinates_t *p_coordinates;
} dialogue_t;
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 *app);
void dialogue_default_callback(callback_args_t *args);
void dialogue_init_active_id(dialogue_t *dialogue);
#endif
+153
View File
@@ -0,0 +1,153 @@
#include "file_list.h"
#include "../file_processor.h"
#include "../fs.h"
#include "app.h"
#include <ncurses.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void reset_file_list(ui_file_list_t *fl_ui);
void file_list_cb(callback_args_t *args) {
app_t *app = args->app;
ui_file_list_t *fui = app->query_args->file_list_ui;
int32_t key = *((int32_t *)args->data);
char query[256];
int32_t q_len = 0;
switch (key) {
case KEY_DOWN:
if (fui->current_idx < fui->current_count - 1) {
fui->current_idx++;
draw_file_list(fui);
} else if (fui->current_page < fui->pages) {
fl_clear(fui->start, fui->current);
app->query_args->state = S_FILE_LIST;
sprintf(query, "file list %u %u\n%n", fui->max_lines,
fui->current_page + 1, &q_len);
write(app->query_args->sd, query, q_len);
reset_file_list(fui);
}
break;
case KEY_UP:
if (fui->current_idx > 0) {
fui->current_idx--;
draw_file_list(fui);
} else if (fui->current_page > 1) {
fl_clear(fui->start, fui->current);
app->query_args->state = S_FILE_LIST;
sprintf(query, "file list %u %u\n%n", fui->max_lines,
fui->current_page - 1, &q_len);
write(app->query_args->sd, query, q_len);
reset_file_list(fui);
fui->activate_last = true;
}
break;
case '\n':
ui_file_select(app->file_args, app->query_args, fui->current_idx + 1);
break;
}
}
ui_file_list_t *init_file_list(WINDOW **win, WINDOW *const *info_win) {
ui_file_list_t *fl_ui = malloc(sizeof(ui_file_list_t));
init_widget(&(fl_ui->w), NULL, win, "");
WINDOW *parent_win = *(fl_ui->w.parent_win);
fl_ui->current_idx = 0;
fl_ui->current_page = 1;
fl_ui->pages = 1;
fl_ui->current_count = 0;
fl_ui->full_count = 0;
fl_ui->activate_last = false;
fl_ui->info_win = info_win;
fl_ui->max_lines = getmaxy(parent_win) - 3; /* 2+1 (bottom info line) */
return fl_ui;
}
void reset_file_list(ui_file_list_t *fl_ui) {
fl_ui->current_idx = 0;
fl_ui->current_page = 0;
fl_ui->pages = 0;
fl_ui->current_count = 0;
fl_ui->full_count = 0;
fl_ui->activate_last = false;
}
void draw_file_list(ui_file_list_t *fl_ui) {
int32_t sz_y, sz_x;
int32_t p_y, p_x;
WINDOW *parent_win = *(fl_ui->w.parent_win);
getmaxyx(parent_win, sz_y, sz_x);
int32_t sz_y_f = sz_y - 2; /* TODO: можно заменить на поле max_lines */
p_y = 1;
p_x = 1;
fl_item_t *el = *(fl_ui->start);
fl_item_t *active_el = *(fl_ui->start);
int32_t cur_el_idx = 0;
curs_set(false);
if (fl_ui->activate_last) {
fl_ui->current_idx = fl_ui->current_count - 1;
fl_ui->activate_last = false;
}
if (fl_ui->current_idx + 1 >= sz_y_f) {
p_y -= fl_ui->current_idx - sz_y_f + 2;
}
do {
if (p_y < 1) {
p_y++;
cur_el_idx++;
continue;
}
if (cur_el_idx == fl_ui->current_idx) {
wattrset(parent_win, A_BOLD | A_REVERSE);
active_el = el;
}
p_x = 1;
mvwprintw(parent_win, p_y, p_x, "%s%n", el->name, &p_x);
mvwprintw(parent_win, p_y, p_x + 1, "%*s", sz_x - p_x, "");
if (cur_el_idx == fl_ui->current_idx) {
wattroff(parent_win, A_BOLD | A_REVERSE);
}
p_y++;
cur_el_idx++;
} while ((el = el->next) != NULL && p_y < sz_y_f);
p_x = 1;
for (; p_y < sz_y_f; p_y++) {
mvwprintw(parent_win, p_y, p_x, "%*s", sz_x - 1, "");
}
char p_info[64];
int32_t p_len;
p_x = 1;
sprintf(p_info, "page: %u/%u files: %u left: %u%n", fl_ui->current_page,
fl_ui->pages, fl_ui->current_count, fl_ui->full_count, &p_len);
uint32_t l_pad = (sz_x - p_len) / 2;
wattrset(parent_win, A_BOLD);
mvwprintw(parent_win, p_y, p_x, "%*s%s%*s", l_pad, "", p_info, l_pad, "");
wattroff(parent_win, A_BOLD);
/* draw file info */
p_y = 1;
p_x = 1;
WINDOW *i_win = *fl_ui->info_win;
wclear(i_win);
char size_text[64];
size_to_text(active_el->size, size_text);
mvwprintw(i_win, p_y++, p_x, "Size: %s", size_text);
mvwprintw(i_win, p_y++, p_x, "Owner: %s", active_el->owner);
mvwprintw(i_win, p_y++, p_x, "Description: ");
print_multiline_text(i_win, active_el->description, sz_x, p_y, p_x, 0);
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef FILE_LIST_H
#define FILE_LIST_H
#include <ui-widget-core.h>
#include <stdint.h>
typedef struct {
widget_t w;
fl_item_t **current;
fl_item_t **start;
int32_t current_idx;
uint32_t current_count;
uint32_t full_count;
uint32_t pages;
uint32_t current_page;
uint32_t max_lines;
WINDOW *const* info_win;
uint32_t activate_last : 1;
} ui_file_list_t;
void draw_file_list(ui_file_list_t *fl_ui);
void redraw_file_list(ui_file_list_t *fl_ui);
ui_file_list_t *init_file_list(WINDOW **win, WINDOW *const* info_win);
void file_list_cb(callback_args_t *args);
#endif
+206
View File
@@ -0,0 +1,206 @@
#include "fs_file_list.h"
#include <dirent.h>
#include <errno.h>
#include <ncurses.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
void reset_file_list(ui_fs_file_list_t *fl_ui);
struct fl_args {
char *name;
u_char d_type;
};
static void fl_add(fs_fl_item_t **f_start, fs_fl_item_t **f_current,
struct fl_args *fargs) {
fs_fl_item_t *c_item = malloc(sizeof(fs_fl_item_t));
c_item->name = malloc(strlen(fargs->name) + 1);
strcpy(c_item->name, fargs->name);
c_item->next = NULL;
c_item->d_type = fargs->d_type;
if (*f_start == NULL) {
c_item->prev = NULL;
*f_start = c_item;
*f_current = c_item;
} else {
c_item->prev = *f_current;
(*f_current)->next = c_item;
*f_current = c_item;
}
}
static void fl_clear(fs_fl_item_t **start, fs_fl_item_t **arg_current) {
if (*start == NULL)
return;
fs_fl_item_t *next, *current;
current = *start;
do {
next = current->next;
free(current->name);
free(current);
} while ((current = next) != NULL);
*start = NULL;
*arg_current = NULL;
}
fs_fl_item_t *get_files_from_fs(char *path) {
DIR *dir;
struct dirent *dent;
char name[257];
struct fl_args f_args;
fs_fl_item_t *d_start = NULL, *d_current = NULL; /* directories */
fs_fl_item_t *f_start = NULL, *f_current = NULL; /* files */
dir = opendir(path);
if (!dir) {
return NULL;
errno = 1;
}
while ((dent = readdir(dir)) != NULL) {
if ((f_args.d_type = dent->d_type) == DT_DIR) {
if (!strcmp(dent->d_name, "."))
continue;
sprintf(name, "/%s", dent->d_name);
f_args.name = name;
fl_add(&d_start, &d_current, &f_args);
} else {
f_args.name = dent->d_name;
sprintf(name, "%s", dent->d_name);
fl_add(&f_start, &f_current, &f_args);
}
}
if (d_current != NULL)
d_current->next = f_start;
if (f_start != NULL)
f_start->prev = d_current;
return d_start;
}
void select_item(ui_fs_file_list_t *fui, int32_t *resp_data) {
char *bash_case = NULL;
char *selection = NULL;
size_t dp_current;
if (fui->current->d_type == DT_DIR) {
if (!strcmp("/..", fui->current->name)) {
bash_case = strrchr(fui->d_path, '/');
if (bash_case != NULL) {
*bash_case = '\0';
fl_clear(&(fui->start), &(fui->current));
fui->start = get_files_from_fs(fui->d_path);
}
} else {
dp_current = strlen(fui->d_path);
selection = fui->current->name + 1;
fui->d_path =
realloc(fui->d_path, dp_current + strlen(selection) + 2);
sprintf(fui->d_path, "%s/%s", fui->d_path, selection);
fl_clear(&(fui->start), &(fui->current));
fui->start = get_files_from_fs(fui->d_path);
}
fui->current = fui->start;
fui->current_idx = 0;
draw_fs_file_list(fui);
} else if (fui->current->d_type == DT_REG) {
*resp_data = 1;
}
}
void fs_file_list_cb(callback_args_t *args) {
ui_fs_file_list_t *fui = args->element;
int32_t key = *((int32_t *)args->data);
switch (key) {
case KEY_DOWN:
if (fui->current->next != NULL) {
fui->current = fui->current->next;
fui->current_idx++;
draw_fs_file_list(fui);
}
break;
case KEY_UP:
if (fui->current->prev != NULL) {
fui->current = fui->current->prev;
fui->current_idx--;
draw_fs_file_list(fui);
}
break;
case '\n':
select_item(fui, (int32_t *) args->resp_data);
break;
}
}
ui_fs_file_list_t *init_fs_file_list(WINDOW **win, widget_t *w_parent) {
ui_fs_file_list_t *fl_ui = malloc(sizeof(ui_fs_file_list_t));
WINDOW *win_par = *(w_parent->w_parent->parent_win);
init_widget(&(fl_ui->w), w_parent, win, "");
fl_ui->current_idx = 0;
fl_ui->info_win = NULL;
fl_ui->d_path = get_current_dir_name();
fl_ui->start = get_files_from_fs(fl_ui->d_path);
fl_ui->current = fl_ui->start;
fl_ui->w.callback = fs_file_list_cb;
fl_ui->w.x = getmaxx(win_par) / 10 * 8;
fl_ui->w.y = getmaxy(win_par) / 10 * 8;
return fl_ui;
}
void reset_fs_file_list(ui_fs_file_list_t *fl_ui) { fl_ui->current_idx = 0; }
void draw_fs_file_list(ui_fs_file_list_t *fl_ui) {
int32_t sz_y, sz_x;
int32_t p_y, p_x;
WINDOW *win = *(fl_ui->w.parent_win);
getmaxyx(win, sz_y, sz_x);
int32_t sz_y_f = sz_y - 2; // actual size (without box)
int32_t sz_x_f = sz_x - 2; // actual size (without box)
p_y = 1;
p_x = 1;
fs_fl_item_t *el = fl_ui->start;
if (fl_ui->current_idx + 1 >= sz_y_f) {
p_y -= fl_ui->current_idx - sz_y_f + 2;
}
wattrset(win, A_REVERSE); /* Match with modal background */
do {
if (p_y < 1) {
p_y++;
continue;
}
if (el == fl_ui->current) {
wattrset(win, COLOR_PAIR(3) | A_BOLD | A_REVERSE);
}
p_x = 1;
mvwprintw(win, p_y, p_x, "%s%n", el->name, &p_x);
mvwprintw(win, p_y, p_x + 1, "%*s", sz_x_f - p_x, "");
if (el == fl_ui->current) {
wattroff(win, COLOR_PAIR(3) | A_BOLD);
}
p_y++;
} while ((el = el->next) != NULL && p_y < sz_y_f);
p_x = 1;
for (; p_y < sz_y_f; p_y++) {
mvwprintw(win, p_y, p_x, "%*s", sz_x_f - 1, "");
}
wattroff(win, A_BOLD | A_REVERSE);
wattrset(win, COLOR_PAIR(0));
curs_set(false);
}
void destroy_fs_file_list(ui_fs_file_list_t *fui) {
fl_clear(&(fui->start), &(fui->current));
free(fui);
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef FS_FILE_LIST_H
#define FS_FILE_LIST_H
#include <ui-widget-core.h>
#include <ncurses.h>
#include <stdint.h>
#include <sys/types.h>
typedef struct fs_fl_item {
char *name;
struct fs_fl_item *next;
struct fs_fl_item *prev;
u_char d_type;
} fs_fl_item_t;
typedef struct {
widget_t w;
fs_fl_item_t *current;
fs_fl_item_t *start;
int32_t current_idx;
WINDOW *const* info_win;
char *d_path;
} ui_fs_file_list_t;
void draw_fs_file_list(ui_fs_file_list_t *fl_ui);
void redraw_fs_file_list(ui_fs_file_list_t *fl_ui);
void destroy_fs_file_list(ui_fs_file_list_t *fl_ui);
ui_fs_file_list_t *init_fs_file_list(WINDOW **win, widget_t *w_parent);
void fs_file_list_cb(callback_args_t *args);
void reset_fs_file_list(ui_fs_file_list_t *fl_ui);
#endif
+198
View File
@@ -0,0 +1,198 @@
#include "group.h"
#include "button.h"
#include "fs_file_list.h"
#include "input.h"
#include "progress_bar.h"
#include <ncurses.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#define MAKE_RESPONSE_M1(args, resp_data, response) \
if (args->resp_data != NULL) { \
*response = -1; \
}
void group_default_callback(callback_args_t *args) {
group_t *g = (group_t *)args->element;
int32_t key = *((int32_t *)args->data);
int32_t *response = (int32_t *)args->resp_data;
input_t *input;
widget_t *widget;
group_el_t *element_ptr;
int32_t element_idx = -1;
u_int32_t start_pos = 0;
callback_args_t new_args;
switch (key) {
case '\n': /* Enter */
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
*response = element_idx;
break;
case KEY_BACKSPACE:
case KEY_DL:
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
if (element_ptr->type == w_input) {
input = (input_t *)element_ptr->element;
if (input->value_len) {
if (input->cur_pos > 0) {
start_pos = input->value_len-- - input->cur_pos;
memmove(input->value + start_pos - 1, input->value + start_pos,
input->value_len - start_pos + 2);
} else {
input->value[--input->value_len] = '\0';
}
}
}
MAKE_RESPONSE_M1(args, resp_data, response);
break;
default:
FIND_ACTIVE_ELEMENT(g, args->active_id, element_ptr, element_idx);
if (element_ptr->type == w_input) {
input = (input_t *)element_ptr->element;
if (input->max_len > input->value_len) {
if (input->cur_pos > 0) {
start_pos = input->value_len++ - input->cur_pos;
memmove(input->value + start_pos + 1, input->value + start_pos,
input->value_len - start_pos);
input->value[start_pos] = key;
} else {
input->value[input->value_len++] = key;
input->value[input->value_len] = '\0';
}
}
} else {
widget = (widget_t *) element_ptr->element;
if (widget->callback != NULL) {
memccpy(&new_args, args, 1, sizeof(callback_args_t));
new_args.element = element_ptr->element;
widget->callback(&new_args);
break;
}
}
MAKE_RESPONSE_M1(args, resp_data, response);
break;
}
}
group_t *init_group(WINDOW **win, widget_t *w_parent, group_el_init_t *children,
enum g_direction direction) {
group_t *group = malloc(sizeof(group_t));
init_widget(&(group->w), w_parent, win, "");
/* count elements */
group->count = 0;
for (; children[group->count].type != w_end; group->count++)
;
group->w.w_parent = w_parent;
group->w.callback = group_default_callback;
if (group->count == 0) {
return group;
}
group->elements = calloc(group->count, sizeof(group_el_t));
group_el_t *elements = group->elements;
for (int32_t i = 0; i < group->count; i++) {
elements[i].type = children[i].type;
elements[i].is_default = children[i].is_default;
}
/* init child elements */
for (int32_t 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);
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,
children[i].is_hidden_value);
w = &(((input_t *)elements[i].element)->w);
break;
case w_progress:
elements[i].element = init_ui_progress_bar(win, &(group->w));
w = &(((ui_progress_bar_t *)elements[i].element)->w);
break;
case w_fs_file_list:
elements[i].element = init_fs_file_list(win, &(group->w));
w = &(((ui_progress_bar_t *)elements[i].element)->w);
break;
}
/* set dimensions */
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) {
group->first_id = w->id;
group->last_id = w->id;
} else {
group->last_id = w->id;
}
}
return group;
}
void draw_group(WINDOW *win, group_t *group, int32_t active_id,
widget_t *dialog_w) {
group_el_t *children = group->elements;
for (int i = 0; i < group->count; i++) {
group_el_t *el = &children[i];
switch (el->type) {
case w_button:
draw_button((button_t *)el->element, active_id);
break;
case w_box:
case w_group:
case w_end:
break;
case w_input:
draw_input((input_t *)el->element, active_id);
break;
case w_progress:
draw_ui_progress_bar((ui_progress_bar_t *)el->element);
break;
case w_fs_file_list:
draw_fs_file_list((ui_fs_file_list_t *)el->element);
break;
}
}
}
void destroy_group(group_t *group) {
group_el_t *children = group->elements;
for (int i = 0; i < group->count; i++) {
group_el_t *el = &children[i];
switch (el->type) {
case w_button:
destroy_button(el->element);
break;
case w_box:
case w_group:
case w_end:
break;
case w_input:
destroy_input(el->element);
break;
case w_progress:
destroy_ui_progress_bar(el->element);
break;
case w_fs_file_list:
destroy_fs_file_list(el->element);
break;
}
}
if (group->elements != NULL) {
free(group->elements);
}
free(group);
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef GROUP_H
#define GROUP_H
#include <stdint.h>
#include <ui-widget-core.h>
enum g_direction {
horizontal,
vertical,
};
typedef struct {
uint32_t id;
void *element;
enum w_type type;
uint32_t is_default : 1;
} group_el_t;
typedef struct {
enum w_type type;
uint32_t is_default : 1;
uint32_t is_hidden_value : 1;
char label[DIALOGUE_TITLE];
uint32_t length;
} group_el_init_t;
typedef struct {
widget_t w;
group_el_t *elements;
enum g_direction direction;
uint32_t count;
uint32_t first_id, last_id;
} 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,
enum g_direction dir);
void draw_group(WINDOW *win, group_t *group, int32_t active_id,
widget_t *dialog_w);
void destroy_group(group_t *group);
void group_default_callback(callback_args_t *args);
#endif
+74
View File
@@ -0,0 +1,74 @@
#include <ncurses.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "app.h"
#include <ui-widget-core.h>
#include "input.h"
input_t *init_input(WINDOW **win, widget_t *w_parent, char *label,
uint32_t length, uint32_t is_hidden_value) {
input_t *input = malloc(sizeof(input_t));
init_widget(&(input->w), w_parent, win, label);
input->is_disabled = 0;
input->w.y = 3; // with borders
input->w.x = length + 3; // with borders and extra space for the last element
uint32_t t_len = strlen(input->w.title) + 4; // with borders and space
if (input->w.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;
input->is_hidden = is_hidden_value;
input->cur_pos = 0;
return input;
}
int32_t draw_input(input_t *input, uint32_t active_id) {
const char stars[] = "*******************";
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;
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);
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);
}
if (input->is_hidden) {
mvwprintw(win, margin_y + 1, margin_x, "%.*s%*s", (int) input->value_len, stars,
input->w.x - input->value_len - 2, "");
} else {
mvwprintw(win, margin_y + 1, margin_x, "%s%*s", input->value,
input->w.x - input->value_len - 2, "");
}
input->w.cur.y = margin_y + 1;
input->w.cur.x = margin_x;
wattroff(win, A_BOLD | A_REVERSE);
return 0;
}
void destroy_input(input_t *btn) { free(btn); }
+22
View File
@@ -0,0 +1,22 @@
#ifndef INPUT_H
#define INPUT_H
#include "../main.h"
#include <ui-widget-core.h>
#include <stdint.h>
typedef struct {
widget_t w;
char value[INPUT_TEXT];
uint32_t cur_pos; /* is relative to the end of a string */
uint32_t value_len;
uint32_t max_len;
uint32_t is_disabled : 1;
uint32_t is_hidden : 1;
} input_t;
input_t *init_input(WINDOW **win, widget_t *w_parent, char *label,
uint32_t size, uint32_t is_hidden_value);
int32_t draw_input(input_t *input, uint32_t active_id);
void destroy_input(input_t *input);
#endif
+58
View File
@@ -0,0 +1,58 @@
#include "progress_bar.h"
#include "app.h"
#include <ncurses.h>
#include <stdint.h>
#include <stdlib.h>
ui_progress_bar_t *init_ui_progress_bar(WINDOW **win, widget_t *w_parent) {
WINDOW *win_par = *(w_parent->w_parent->parent_win);
ui_progress_bar_t *pb = malloc(sizeof(ui_progress_bar_t));
init_widget(&pb->w, w_parent, win, "");
pb->procent = 0;
pb->text[0] = '\0';
pb->w.y = 4;
pb->w.x = getmaxx(win_par) / 10 * 9;
return pb;
}
void draw_ui_progress_bar(ui_progress_bar_t *pb) {
WINDOW *win = *(pb->w.w_parent->parent_win);
uint32_t margin_y = pb->w.m_y + pb->w.w_parent->m_y;
uint32_t margin_x = pb->w.m_x + pb->w.w_parent->m_x + 1;
wattrset(win, COLOR_PAIR(modal_color_pair));
mvwhline(win, margin_y, margin_x, 0, pb->w.x - 1);
float procent = pb->procent;
procent /= 100;
uint32_t filled_num = procent * pb->w.x;
if (filled_num > 2) {
filled_num -= 2;
}
for (int i = 1; i < 3; i++) {
wattrset(win, COLOR_PAIR(1) | A_REVERSE);
mvwprintw(win, margin_y + i, margin_x + 1, "%*s", filled_num, "");
}
wattrset(win, COLOR_PAIR(modal_color_pair));
// bottom line
mvwhline(win, margin_y + 3, margin_x, 0, pb->w.x - 1);
// 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, 0, 1);
mvwvline(win, margin_y + 3, margin_x, ACS_LLCORNER, 1);
// right
mvwvline(win, margin_y, margin_x + pb->w.x - 2, ACS_URCORNER, 1);
mvwvline(win, margin_y + 1, margin_x + pb->w.x - 2, 0, 1);
mvwvline(win, margin_y + 2, margin_x + pb->w.x - 2, 0, 1);
mvwvline(win, margin_y + 3, margin_x + pb->w.x - 2, ACS_LRCORNER, 1);
}
void destroy_ui_progress_bar(void *_pb) {
ui_progress_bar_t *pb = (ui_progress_bar_t *)_pb;
free(pb);
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef PROGRESS_BAR_H
#define PROGRESS_BAR_H
#include <ui-widget-core.h>
typedef struct {
widget_t w;
uint32_t procent;
char text[24];
} ui_progress_bar_t;
void destroy_ui_progress_bar(void *_pb);
void draw_ui_progress_bar(ui_progress_bar_t *pb);
ui_progress_bar_t *init_ui_progress_bar(WINDOW **win, widget_t *w_parent);
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef WIDGET_H
#define WIDGET_H
#include "app.h"
#include "button.h"
#include "dialogue.h"
#include "file_list.h"
#include "fs_file_list.h"
#include "group.h"
#include "input.h"
#include "progress_bar.h"
#endif