CMake integration
This commit is contained in:
@@ -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")
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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); }
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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); }
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user