Compare commits
10
Commits
cc6039b974
...
0744a2cbaa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0744a2cbaa
|
||
|
|
4be4bb926a
|
||
|
|
ae81b806eb
|
||
|
|
1ce2cccf59
|
||
|
|
4aca8fb5a4
|
||
|
|
10442f3101
|
||
|
|
cc179e1b72
|
||
|
|
8c87c46c46
|
||
|
|
ba9631a513
|
||
|
|
cd83bc4b16
|
@@ -1,10 +1,14 @@
|
||||
# TODO:
|
||||
|
||||
## Current:
|
||||
- [ ] Rewrite cancel download. Use packages and check every time for a confirmation to continue download
|
||||
- [ ] File upload multiline description (window)
|
||||
- [ ] Separate common structures in the common.h
|
||||
- [ ] Sorting in the file list
|
||||
- [ ] Cancel upload/download
|
||||
- [ ] Resume download
|
||||
- [ ] Separate common structures in the common.h
|
||||
- [x] Show download/upload progress in percentages
|
||||
- [x] Break line automatically in modal widgets
|
||||
- [x] Cancel upload/download
|
||||
- [x] Input: fix non-Latin letters
|
||||
- [x] Get rid of unsigned integers
|
||||
- [x] Check registration / enter server name again
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ void app_draw_modal(app_t *app) {
|
||||
case S_PRINT_SERVER_MESSAGE:
|
||||
m_server_message_init(app);
|
||||
break;
|
||||
case S_FILE_DOWNLOAD:
|
||||
case S_DOWNLOAD_FILE:
|
||||
m_load_pr_init(app, false);
|
||||
break;
|
||||
case S_UPLOAD_FILE:
|
||||
|
||||
+135
-106
@@ -101,62 +101,100 @@ int32_t ui_file_select(file_args_t *f_args, query_args_t *q_args, int32_t idx) {
|
||||
return -2;
|
||||
}
|
||||
server_send_string(q_args, "file download [%s]\n", f_selected->name);
|
||||
q_args->state = S_FILE_DOWNLOAD;
|
||||
q_args->state = S_DOWNLOAD_FILE;
|
||||
|
||||
q_args->file = malloc(sizeof(p_file_t));
|
||||
q_args->file->name = f_selected->name;
|
||||
q_args->file->rest = f_selected->size;
|
||||
q_args->file->size = f_selected->size;
|
||||
q_args->file->package_rest = PACKAGE_SIZE;
|
||||
q_args->file->signal = sig_continue;
|
||||
q_args->file->it_count = 0;
|
||||
q_args->file->fd = f_args->file_d;
|
||||
|
||||
q_args->file->it_interval =
|
||||
(f_selected->size / INBUFSIZE / 100); /* every 1% */
|
||||
if (q_args->file->it_interval == 0)
|
||||
q_args->file->it_interval = 1;
|
||||
|
||||
free(file_path);
|
||||
return OK;
|
||||
}
|
||||
|
||||
#define file_download_receive_after(qlen, q_args, f_args, d, pb) \
|
||||
{ \
|
||||
if (qlen) { \
|
||||
q_args->file->it_count++; \
|
||||
q_args->file->package_rest -= qlen; \
|
||||
if (!(q_args->file->it_count % q_args->file->it_interval)) { \
|
||||
pb->percentage = progress; \
|
||||
d->needs_update = true; \
|
||||
} else { \
|
||||
q_args->buf_used = 0; \
|
||||
} \
|
||||
if (q_args->file->rest < qlen) { \
|
||||
q_args->file->rest = 0; \
|
||||
} else { \
|
||||
q_args->file->rest -= qlen; \
|
||||
} \
|
||||
if (q_args->file->rest == 0) { \
|
||||
q_args->file->it_count = 0; \
|
||||
q_args->file->it_interval = 0; \
|
||||
f_selected->size = 0; \
|
||||
close(f_args->file_d); \
|
||||
d->needs_destroy = true; \
|
||||
sprintf(answer, "File %s is downloaded from the server!", \
|
||||
f_selected->name); \
|
||||
q_args->notification = malloc(strlen(answer) + 1); \
|
||||
strcpy(q_args->notification, answer); \
|
||||
free(f_selected->name); \
|
||||
server_send_string(q_args, "file list %d %d\n%n", fui->max_lines, \
|
||||
fui->current_page, &a_len); \
|
||||
q_args->state = S_FILE_LIST; \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/* TODO: revise */
|
||||
void file_download(file_args_t *f_args, query_args_t *q_args) {
|
||||
fl_item_t *f_selected = &(f_args->f_selected);
|
||||
static int32_t it_count = 0;
|
||||
static size_t it_interval = 0;
|
||||
|
||||
if (it_interval == 0) {
|
||||
it_interval = (f_selected->size / INBUFSIZE / 100) * 5; /* every 1% */
|
||||
if (it_interval == 0)
|
||||
it_interval = 1;
|
||||
}
|
||||
char answer[256];
|
||||
|
||||
static size_t size_rest = 0;
|
||||
int32_t progress = (f_selected->size - size_rest) * 100 / f_selected->size;
|
||||
int32_t progress =
|
||||
(f_selected->size - q_args->file->rest) * 100 / f_selected->size;
|
||||
w_pgb_ui_t *pb = (w_pgb_ui_t *)q_args->progress_bar;
|
||||
w_dialogue_t *d = (w_dialogue_t *)q_args->active_dialogue;
|
||||
w_ui_file_list_t *fui = (w_ui_file_list_t *)q_args->main_ui->ui;
|
||||
int32_t a_len = 0;
|
||||
int32_t qlen;
|
||||
|
||||
if (size_rest == 0)
|
||||
size_rest = f_selected->size;
|
||||
int32_t qlen = write(f_args->file_d, q_args->buf, q_args->buf_used);
|
||||
if (qlen) {
|
||||
it_count++;
|
||||
if (!(it_count % it_interval)) {
|
||||
pb->procent = progress;
|
||||
d->needs_update = true;
|
||||
} else {
|
||||
q_args->buf_used = 0;
|
||||
}
|
||||
if (size_rest < qlen) {
|
||||
size_rest = 0;
|
||||
} else {
|
||||
size_rest -= qlen;
|
||||
}
|
||||
if (size_rest == 0) {
|
||||
it_count = 0;
|
||||
it_interval = 0;
|
||||
f_selected->size = 0;
|
||||
close(f_args->file_d);
|
||||
int write_len = q_args->buf_used;
|
||||
|
||||
if (q_args->file->package_rest <= q_args->buf_used) {
|
||||
write_len = q_args->file->package_rest;
|
||||
qlen = write(f_args->file_d, q_args->buf, write_len);
|
||||
file_download_receive_after(qlen, q_args, f_args, d, pb)
|
||||
if (q_args->file->signal == sig_continue) {
|
||||
server_send_string(q_args, "continue %d\n", PACKAGE_SIZE * 10);
|
||||
if (q_args->file->package_rest == 0) {
|
||||
q_args->file->package_rest = PACKAGE_SIZE * 10;
|
||||
return;
|
||||
}
|
||||
int buf_offset = q_args->file->package_rest;
|
||||
write_len = q_args->buf_used - q_args->file->package_rest;
|
||||
qlen = write(f_args->file_d, q_args->buf + buf_offset, write_len);
|
||||
q_args->file->package_rest = PACKAGE_SIZE * 10;
|
||||
file_download_receive_after(qlen, q_args, f_args, d, pb);
|
||||
} else if (q_args->file->signal == sig_cancel) {
|
||||
server_send_string(q_args, "cancel\n");
|
||||
FILE_CLEAN(q_args->file);
|
||||
d->needs_destroy = true;
|
||||
sprintf(answer, "File %s is downloaded from the server!",
|
||||
f_selected->name);
|
||||
q_args->notification = malloc(strlen(answer) + 1);
|
||||
strcpy(q_args->notification, answer);
|
||||
free(f_selected->name);
|
||||
server_send_string(q_args, "file list %d %d\n%n", fui->max_lines,
|
||||
fui->current_page, &a_len);
|
||||
q_args->state = S_FILE_LIST;
|
||||
}
|
||||
return;
|
||||
}
|
||||
qlen = write(f_args->file_d, q_args->buf, write_len);
|
||||
file_download_receive_after(qlen, q_args, f_args, d, pb)
|
||||
}
|
||||
|
||||
int32_t file_upload_open(char *dpath, char *fname, query_args_t *q_args) {
|
||||
@@ -191,91 +229,82 @@ int32_t file_upload_start(query_args_t *q_args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define file_upload_send(send_len, package_rest, buf_indent) \
|
||||
{ \
|
||||
if (q_args->buf_used > 0) { \
|
||||
int wlen = write(q_args->sd, q_args->buf + buf_indent, send_len); \
|
||||
if (q_args->buf_used != wlen) { \
|
||||
/* TODO: ошибка */ \
|
||||
/* reset function before exit */ \
|
||||
it_count = 0; \
|
||||
it_interval = 0; \
|
||||
package_rest = 0; \
|
||||
ret = -1; \
|
||||
} else { \
|
||||
it_count++; \
|
||||
if (!(it_count % it_interval)) { \
|
||||
pb->percentage = progress; \
|
||||
d->needs_update = true; \
|
||||
} \
|
||||
q_args->file->rest -= wlen; \
|
||||
package_rest -= wlen; \
|
||||
q_args->buf_used -= send_len; \
|
||||
ret = 0; \
|
||||
} \
|
||||
} else { \
|
||||
/* reset function before exit */ \
|
||||
it_count = 0; \
|
||||
it_interval = 0; \
|
||||
package_rest = 0; \
|
||||
ret = 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
int32_t file_upload(query_args_t *q_args) {
|
||||
static int32_t it_count = 0;
|
||||
static size_t it_interval = 0;
|
||||
static int package_rest = 0;
|
||||
int ret = 0;
|
||||
int buf_indent = 0;
|
||||
int send_len = q_args->buf_used;
|
||||
|
||||
int32_t progress =
|
||||
(q_args->file->size - q_args->file->rest) * 100 / q_args->file->size;
|
||||
w_pgb_ui_t *pb = (w_pgb_ui_t *)q_args->progress_bar;
|
||||
w_dialogue_t *d = (w_dialogue_t *)q_args->active_dialogue;
|
||||
if (it_interval == 0) {
|
||||
it_interval = (q_args->file->size / INBUFSIZE / 100) * 5; /* every 1% */
|
||||
if (it_interval == 0)
|
||||
it_interval = 1;
|
||||
}
|
||||
int32_t progress =
|
||||
(q_args->file->size - q_args->file->rest) * 100 / q_args->file->size;
|
||||
w_pgb_ui_t *pb = (w_pgb_ui_t *)q_args->progress_bar;
|
||||
w_dialogue_t *d = (w_dialogue_t *)q_args->active_dialogue;
|
||||
|
||||
if (package_rest == 0) {
|
||||
if (package_rest < send_len) {
|
||||
if (package_rest > 0) {
|
||||
send_len -= package_rest;
|
||||
buf_indent = package_rest;
|
||||
file_upload_send(package_rest, package_rest, 0);
|
||||
if (ret) {
|
||||
/* TODO: error case */
|
||||
}
|
||||
}
|
||||
|
||||
package_rest = PACKAGE_SIZE;
|
||||
|
||||
s_file_pd_t fpd = {.signal = q_args->file->signal,
|
||||
.package_size = package_rest};
|
||||
write(q_args->sd, &fpd, sizeof(s_file_pd_t));
|
||||
if (q_args->file->signal == sig_cancel) {
|
||||
/* reset function before exit */
|
||||
it_count = 0;
|
||||
it_interval = 0;
|
||||
return -2;
|
||||
}
|
||||
package_rest = PACKAGE_SIZE;
|
||||
s_file_pd_t fpd = {.signal = q_args->file->signal,
|
||||
.package_size = package_rest};
|
||||
write(q_args->sd, &fpd, sizeof(s_file_pd_t));
|
||||
} else if (package_rest < send_len) {
|
||||
send_len = package_rest;
|
||||
}
|
||||
|
||||
if (q_args->buf_used > 0) {
|
||||
int wlen = write(q_args->sd, q_args->buf, send_len);
|
||||
if (q_args->buf_used != wlen) {
|
||||
/* TODO: ошибка */
|
||||
/* reset function before exit */
|
||||
it_count = 0;
|
||||
it_interval = 0;
|
||||
package_rest = 0;
|
||||
return -1;
|
||||
} else {
|
||||
it_count++;
|
||||
if (!(it_count % it_interval)) {
|
||||
pb->procent = progress;
|
||||
d->needs_update = true;
|
||||
}
|
||||
q_args->file->rest -= wlen;
|
||||
package_rest -= wlen;
|
||||
if (package_rest == 0) {
|
||||
if (q_args->file->signal == sig_cancel) {
|
||||
/* reset function before exit */
|
||||
it_count = 0;
|
||||
it_interval = 0;
|
||||
return -2;
|
||||
}
|
||||
package_rest = PACKAGE_SIZE;
|
||||
s_file_pd_t fpd = {.signal = q_args->file->signal,
|
||||
.package_size = package_rest};
|
||||
write(q_args->sd, &fpd, sizeof(s_file_pd_t));
|
||||
/* send the rest */
|
||||
if (q_args->buf_used > send_len) {
|
||||
wlen = write(q_args->sd, q_args->buf + send_len,
|
||||
q_args->buf_used - send_len);
|
||||
if (q_args->buf_used != wlen) {
|
||||
/* TODO: ошибка */
|
||||
/* reset function before exit */
|
||||
it_count = 0;
|
||||
it_interval = 0;
|
||||
package_rest = 0;
|
||||
return -1;
|
||||
}
|
||||
q_args->file->rest -= wlen;
|
||||
package_rest -= wlen;
|
||||
}
|
||||
}
|
||||
q_args->buf[0] = 0;
|
||||
q_args->buf_used = 0;
|
||||
}
|
||||
} else {
|
||||
/* reset function before exit */
|
||||
it_count = 0;
|
||||
it_interval = 0;
|
||||
package_rest = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
file_upload_send(send_len, package_rest, buf_indent);
|
||||
|
||||
q_args->buf[0] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void clear_file_in_query(query_args_t *q_args) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "main.h"
|
||||
#include "../app.h"
|
||||
#include "alert.h"
|
||||
#include "connection.h"
|
||||
#include "file_list.h"
|
||||
#include "query.h"
|
||||
|
||||
+5
-2
@@ -42,7 +42,7 @@ enum state {
|
||||
S_FILE_LIST,
|
||||
S_WAIT_PASS,
|
||||
/* S_FILE_SELECT, */
|
||||
S_FILE_DOWNLOAD,
|
||||
S_DOWNLOAD_FILE,
|
||||
S_UPLOAD_PARAMS,
|
||||
S_UPLOAD_FILE,
|
||||
/* S_UPLOAD_FILE_SELECT, */
|
||||
@@ -73,6 +73,9 @@ typedef struct p_file {
|
||||
char *description;
|
||||
size_t size;
|
||||
size_t rest;
|
||||
size_t package_rest;
|
||||
int32_t it_count;
|
||||
size_t it_interval;
|
||||
enum package_signal signal;
|
||||
int fd;
|
||||
} p_file_t;
|
||||
@@ -105,7 +108,7 @@ typedef struct main_window {
|
||||
void *ui; /* structure which describes window UI */
|
||||
int32_t (*cb_b_press)(void *app, void *args); /* callback on button press */
|
||||
void (*cb_ui_refresh)(void *app); /* refresh callback */
|
||||
void (*reset)(void *app); /* function to reset the state of the window */
|
||||
void (*reset)(void *app); /* function to reset the state of the window */
|
||||
draw_f_t *draw;
|
||||
struct action_key *b_keys;
|
||||
int32_t b_keys_len;
|
||||
|
||||
+25
-1
@@ -1,17 +1,41 @@
|
||||
#include "../server.h"
|
||||
#include "../windows/file_list.h"
|
||||
#include "alert.h"
|
||||
#include "dialogue.h"
|
||||
#include "group.h"
|
||||
#include "utils.h"
|
||||
#include <ncursesw/ncurses.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <widget.h>
|
||||
|
||||
void dwn_pr_modal_cb(w_cb_args_t *args) {
|
||||
/* only cancel action */
|
||||
int32_t key = *((int32_t *)args->data);
|
||||
|
||||
if (key != '\n') {
|
||||
return;
|
||||
}
|
||||
|
||||
app_t *app = args->app;
|
||||
app->query_args->file->signal = sig_cancel;
|
||||
w_dialogue_t *d = &(app->modal);
|
||||
/* TODO: forward actual file name */
|
||||
if (app->query_args->state == S_UPLOAD_FILE) {
|
||||
bool response = w_bool_ask("Cancel file upload", "Yes", "No", false,
|
||||
"You're going to cancel upload\n Are you sure?");
|
||||
if (response) {
|
||||
app->query_args->file->signal = sig_cancel;
|
||||
}
|
||||
} else if (app->query_args->state == S_DOWNLOAD_FILE) {
|
||||
w_ui_file_list_t *fui = (w_ui_file_list_t *)app->query_args->main_ui->ui;
|
||||
bool response =
|
||||
w_bool_ask("Cancel file download", "Yes", "No", false,
|
||||
"You're going to cancel download\n Are you sure?");
|
||||
if (response) {
|
||||
app->query_args->file->signal = sig_cancel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w_dialogue_t *m_load_pr_init(app_t *app, bool is_upload) {
|
||||
|
||||
+3
-10
@@ -45,13 +45,6 @@ int32_t process_user_input(app_t *app, w_cb_args_t *d_args);
|
||||
app_destroy(app, exit_code); \
|
||||
}
|
||||
|
||||
#define FILE_CLEAN(app) \
|
||||
if (app->query_args->file != NULL) { \
|
||||
FREE_MLC(app->query_args->file->name); \
|
||||
FREE_MLC(app->query_args->file->path); \
|
||||
FREE_MLC(app->query_args->file); \
|
||||
}
|
||||
|
||||
void query_loop(app_t *app) {
|
||||
query_args_t *query_args = app->query_args;
|
||||
fd_set readfds;
|
||||
@@ -183,14 +176,14 @@ int process_query(app_t *app) {
|
||||
case S_FILE_LIST:
|
||||
file_list(file_args, query_args);
|
||||
break;
|
||||
case S_FILE_DOWNLOAD:
|
||||
case S_DOWNLOAD_FILE:
|
||||
file_download(file_args, query_args);
|
||||
break;
|
||||
case S_UPLOAD_REQUESTED:
|
||||
if (!file_upload_start(query_args)) {
|
||||
query_args->state = S_UPLOAD_FILE;
|
||||
} else {
|
||||
FILE_CLEAN(app);
|
||||
FILE_CLEAN(app->query_args->file);
|
||||
query_args->state = WAIT_CLIENT;
|
||||
}
|
||||
break;
|
||||
@@ -205,7 +198,7 @@ int process_query(app_t *app) {
|
||||
/* cancel case */
|
||||
w_notification("Alert", dc_alert, "File %s didn't upload!",
|
||||
query_args->file->name);
|
||||
FILE_CLEAN(app);
|
||||
FILE_CLEAN(app->query_args->file);
|
||||
w_dialogue_t *d = &(app->modal);
|
||||
d->needs_destroy = true;
|
||||
query_args->state = WAIT_CLIENT;
|
||||
|
||||
+3
-3
@@ -28,19 +28,19 @@ const char *u_utf8_wind_n(const char *s, int n) {
|
||||
|
||||
int32_t u_utf8_convert_to_wide(const char *utf8_str,
|
||||
wchar_t **restrict wide_str,
|
||||
size_t *restrict len) {
|
||||
size_t *restrict o_len) {
|
||||
// Step 1: Convert UTF-8 (MBCS) to wchar_t (wide)
|
||||
size_t wide_len =
|
||||
u_utf8_code_points_count(utf8_str); // Get required length (-1 on error)
|
||||
if (wide_len == (size_t)-1) {
|
||||
*len = 0;
|
||||
*o_len = 0;
|
||||
perror("mbstowcs failed");
|
||||
return 1;
|
||||
}
|
||||
*wide_str =
|
||||
malloc((wide_len + 1) * sizeof(wchar_t)); // +1 for null terminator
|
||||
mbstowcs(*wide_str, utf8_str, wide_len + 1); // Perform conversion
|
||||
*len = wide_len;
|
||||
*o_len = wide_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
const char *u_utf8_wind_n(const char *s, int n);
|
||||
size_t u_utf8_code_points_count(const char *s);
|
||||
int32_t u_utf8_convert_to_wide(const char *utf8_str, wchar_t **restrict wide_str,
|
||||
size_t *restrict len);
|
||||
size_t *restrict o_len);
|
||||
int32_t u_utf8_curs_printw(WINDOW *win, int32_t *y, int32_t *x, const char* utf8_str, int max_len, bool multiline);
|
||||
|
||||
#endif
|
||||
@@ -9,4 +9,12 @@
|
||||
free(arg); \
|
||||
arg = NULL; \
|
||||
}
|
||||
|
||||
#define FILE_CLEAN(file) \
|
||||
if (file != NULL) { \
|
||||
FREE_MLC(file->name); \
|
||||
FREE_MLC(file->path); \
|
||||
FREE_MLC(file); \
|
||||
file = NULL; \
|
||||
}
|
||||
#endif
|
||||
+95
-3
@@ -1,4 +1,6 @@
|
||||
#include "alert.h"
|
||||
#include "dialogue.h"
|
||||
#include "widget_core.h"
|
||||
#include <ncursesw/ncurses.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
@@ -15,10 +17,12 @@ void alert_cb(w_cb_args_t *args) {
|
||||
|
||||
void w_alert_init(app_t *_app) { app = _app; }
|
||||
|
||||
void w_alert(const char *message) { w_notification("Alert", dc_alert, message); }
|
||||
void w_alert(const char *message) {
|
||||
w_notification("Alert", dc_alert, message);
|
||||
}
|
||||
|
||||
void w_notification(const char *title, enum w_dialogue_color_scheme color,
|
||||
const char *f_message, ...) {
|
||||
const char *f_message, ...) {
|
||||
if (app == NULL)
|
||||
return;
|
||||
|
||||
@@ -36,7 +40,7 @@ void w_notification(const char *title, enum w_dialogue_color_scheme color,
|
||||
d->w.callback = alert_cb;
|
||||
d->g_content = NULL;
|
||||
d->g_action = w_group_init(&(d->win), &(d->w), actions, &(d->id_map),
|
||||
horizontal, g_action);
|
||||
horizontal, g_action);
|
||||
|
||||
w_dialogue_init_active_id(d);
|
||||
d->color_scheme = color;
|
||||
@@ -59,3 +63,91 @@ void w_notification(const char *title, enum w_dialogue_color_scheme color,
|
||||
app->modal.needs_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
int w_bool_callback(app_t *app, w_dialogue_t *dialogue, int32_t key) {
|
||||
w_cb_args_t args;
|
||||
args.app = app;
|
||||
args.active_el = dialogue;
|
||||
args.element = dialogue;
|
||||
int _key = key;
|
||||
args.data = (void *)&_key;
|
||||
w_dialogue_callback_default(&args);
|
||||
if (args.resp_data.code == cbrp_val) {
|
||||
switch (args.resp_data.val.val.num) {
|
||||
case 1:
|
||||
return 1;
|
||||
case 2:
|
||||
return 2;
|
||||
default:
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_bool_ask(const char *title, const char *text_y_btn,
|
||||
const char *text_n_btn, bool yes_default, const char *f_message,
|
||||
...) {
|
||||
|
||||
va_list args;
|
||||
va_start(args, f_message);
|
||||
|
||||
if (app == NULL)
|
||||
return -1;
|
||||
|
||||
void *callback = app->active_callback;
|
||||
|
||||
w_group_el_init_t actions[] = {{.type = w_button, .val.num = 1}, /* YES */
|
||||
{.type = w_button, .val.num = 2}, /* NO */
|
||||
{.type = w_end}};
|
||||
|
||||
strcpy(actions[0].label, text_y_btn);
|
||||
strcpy(actions[1].label, text_n_btn);
|
||||
|
||||
w_dialogue_t *d = malloc(sizeof(w_dialogue_t));
|
||||
|
||||
w_dialogue_vinit(d, title, &(app->coordinates), f_message, &args);
|
||||
|
||||
d->w.callback = alert_cb;
|
||||
d->g_content = NULL;
|
||||
d->g_action = w_group_init(&(d->win), &(d->w), actions, &(d->id_map),
|
||||
horizontal, g_action);
|
||||
|
||||
if (yes_default) {
|
||||
d->active_el = d->g_action->elements;
|
||||
} else {
|
||||
d->active_el = d->g_action->elements + 1;
|
||||
}
|
||||
|
||||
w_dialogue_draw(d);
|
||||
wrefresh(d->win);
|
||||
int c = 0;
|
||||
|
||||
bool response = false;
|
||||
|
||||
while ((c = wgetch(app->win))) {
|
||||
int ret = w_bool_callback(app, d, c);
|
||||
switch (ret) {
|
||||
case 1:
|
||||
response = true;
|
||||
goto break_while;
|
||||
case 2:
|
||||
goto break_while;
|
||||
}
|
||||
w_dialogue_draw(d);
|
||||
wrefresh(d->win);
|
||||
}
|
||||
|
||||
break_while:
|
||||
|
||||
w_group_destroy(d->g_action);
|
||||
delwin(d->win);
|
||||
free(d);
|
||||
app->active_callback = callback;
|
||||
app_refresh(app);
|
||||
if (app->modal.win != NULL) {
|
||||
app->modal.needs_update = true;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
+3
-1
@@ -7,6 +7,8 @@
|
||||
void w_alert_init(app_t *app);
|
||||
void w_alert(const char *message);
|
||||
void w_notification(const char *title, enum w_dialogue_color_scheme color,
|
||||
const char *f_message, ...);
|
||||
const char *f_message, ...);
|
||||
int w_bool_ask(const char *title, const char *yes_button,
|
||||
const char *no_button, bool yes_default, const char *f_message, ...);
|
||||
|
||||
#endif
|
||||
+14
-6
@@ -1,11 +1,14 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/* Copyright (c) 2026 Oleksandr Zhylin */
|
||||
#include <ncursesw/ncurses.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <wchar.h>
|
||||
#include <widget.h>
|
||||
#include <widget_core.h>
|
||||
|
||||
@@ -60,7 +63,7 @@ static void decr_active_id(w_dialogue_t *d) {
|
||||
}
|
||||
|
||||
static void case_callback(w_cb_args_t *args, w_cb_args_t *new_args) {
|
||||
w_dialogue_t *d = (void *)args->element;
|
||||
w_dialogue_t *d = args->element;
|
||||
/* run callback function */
|
||||
if (d->active_el->g_type == g_content) {
|
||||
new_args->element = d->g_content;
|
||||
@@ -74,7 +77,7 @@ static void case_callback(w_cb_args_t *args, w_cb_args_t *new_args) {
|
||||
}
|
||||
|
||||
void w_dialogue_callback_default(w_cb_args_t *args) {
|
||||
w_dialogue_t *d = (void *)args->element;
|
||||
w_dialogue_t *d = args->element;
|
||||
int32_t key = *((int32_t *)args->data);
|
||||
w_cb_args_t new_args;
|
||||
memcpy(&new_args, args, sizeof(w_cb_args_t));
|
||||
@@ -237,7 +240,11 @@ int32_t w_dialogue_draw(w_dialogue_t *d) {
|
||||
/* analyze text content */
|
||||
int32_t line_count = 0;
|
||||
int32_t line_max_len = 0;
|
||||
line_max_len = w_get_max_line_len(d->text, &line_count);
|
||||
wchar_t *main_text_wide = malloc(sizeof(wchar_t) * strlen(d->text));
|
||||
size_t mwt_len;
|
||||
u_utf8_convert_to_wide(d->text, &main_text_wide, &mwt_len);
|
||||
line_count = w_text_divide_by_lines(
|
||||
main_text_wide, mwt_len, d->p_coordinates->max_x * 0.77, &line_max_len);
|
||||
y += line_count;
|
||||
y += 2; /* margin for text */
|
||||
|
||||
@@ -246,8 +253,8 @@ int32_t w_dialogue_draw(w_dialogue_t *d) {
|
||||
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 */
|
||||
x += 2; /* when uses box */
|
||||
y += 2; /* when uses box */
|
||||
|
||||
d->w.sz.x = x;
|
||||
d->w.sz.y = y;
|
||||
@@ -283,7 +290,8 @@ int32_t w_dialogue_draw(w_dialogue_t *d) {
|
||||
/* text */
|
||||
wattroff(d->win, A_BOLD);
|
||||
/* mvwhline(d->win, d->w.sz.y - 3, 1, 0, d->w.sz.x - 2); */
|
||||
w_print_multiline_text(d->win, d->text, d->w.sz.x, 2, 1, PMT_ALIGN_CENTER);
|
||||
w_print_multiline_text_wide(d->win, main_text_wide, mwt_len, line_max_len,
|
||||
d->w.sz.x, 2, 0, PMT_ALIGN_CENTER);
|
||||
wattroff(d->win, A_REVERSE);
|
||||
|
||||
if (d->g_content != NULL) {
|
||||
|
||||
@@ -11,7 +11,7 @@ w_pgb_ui_t *w_pgb_ui_init(WINDOW **win, w_t *w_parent) {
|
||||
WINDOW *win_par = *(w_parent->w_parent->parent_win);
|
||||
w_pgb_ui_t *pb = malloc(sizeof(w_pgb_ui_t));
|
||||
w_init(&pb->w, w_parent, win, "");
|
||||
pb->procent = 0;
|
||||
pb->percentage = 0;
|
||||
pb->text[0] = '\0';
|
||||
pb->w.sz.y = 4;
|
||||
pb->w.sz.x = getmaxx(win_par) / 10 * 9;
|
||||
@@ -25,17 +25,23 @@ void w_pgb_ui_draw(w_pgb_ui_t *pb) {
|
||||
|
||||
wattrset(win, COLOR_PAIR(modal_color_pair));
|
||||
|
||||
/* top line */
|
||||
mvwhline(win, margin_y, margin_x, 0, pb->w.sz.x - 1);
|
||||
|
||||
float procent = pb->procent;
|
||||
procent /= 100;
|
||||
int32_t filled_num = procent * pb->w.sz.x;
|
||||
int center = pb->w.sz.x / 2 - 3;
|
||||
|
||||
mvwprintw(win, margin_y, margin_x + center, "| %d%% |", pb->percentage);
|
||||
|
||||
float percentage = pb->percentage;
|
||||
percentage /= 100;
|
||||
int32_t filled_num = percentage * pb->w.sz.x;
|
||||
if (filled_num > 2) {
|
||||
filled_num -= 2;
|
||||
}
|
||||
|
||||
for (int i = 1; i < 3; i++) {
|
||||
wattrset(win, COLOR_PAIR(1) | A_REVERSE);
|
||||
wattrset(win, COLOR_PAIR(1) | A_REVERSE);
|
||||
|
||||
for (int i = 1; i < 3; i++) { /* two lines */
|
||||
mvwprintw(win, margin_y + i, margin_x + 1, "%*s", filled_num, "");
|
||||
}
|
||||
|
||||
@@ -43,12 +49,12 @@ void w_pgb_ui_draw(w_pgb_ui_t *pb) {
|
||||
|
||||
// bottom line
|
||||
mvwhline(win, margin_y + 3, margin_x, 0, pb->w.sz.x - 1);
|
||||
// left
|
||||
// left corners
|
||||
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
|
||||
// right corners
|
||||
mvwvline(win, margin_y, margin_x + pb->w.sz.x - 2, ACS_URCORNER, 1);
|
||||
mvwvline(win, margin_y + 1, margin_x + pb->w.sz.x - 2, 0, 1);
|
||||
mvwvline(win, margin_y + 2, margin_x + pb->w.sz.x - 2, 0, 1);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
typedef struct {
|
||||
w_t w;
|
||||
int32_t procent;
|
||||
int32_t percentage;
|
||||
char text[24];
|
||||
} w_pgb_ui_t;
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
#include "widget_core.h"
|
||||
#include "../main.h"
|
||||
#include <ncursesw/ncurses.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <utils.h>
|
||||
#include <wchar.h>
|
||||
|
||||
extern int32_t m_id;
|
||||
|
||||
@@ -59,6 +61,49 @@ int32_t w_get_max_line_len(const char *text, int32_t *line_count) {
|
||||
}
|
||||
}
|
||||
|
||||
/* returns number of lines */
|
||||
int32_t w_text_divide_by_lines(wchar_t *restrict text, size_t src_len,
|
||||
int max_x, int *max_len) {
|
||||
int cl_pos = 0;
|
||||
int last_space = -1; /* space position in the current line */
|
||||
int lines_num = 1;
|
||||
|
||||
for (int i = 0; text[i] != '\0'; i++, cl_pos++) {
|
||||
switch (text[i]) {
|
||||
case ' ': /* space symbol */
|
||||
last_space = i;
|
||||
break;
|
||||
case '\n':
|
||||
if (cl_pos > *max_len) {
|
||||
*max_len = cl_pos;
|
||||
}
|
||||
last_space = -1;
|
||||
cl_pos = 0;
|
||||
lines_num++;
|
||||
break;
|
||||
default:
|
||||
if (cl_pos > max_x) {
|
||||
if (last_space > 0) {
|
||||
int line_size = last_space - (i - cl_pos);
|
||||
if (line_size > *max_len) {
|
||||
*max_len = line_size;
|
||||
}
|
||||
text[last_space] = '\n';
|
||||
i = last_space;
|
||||
last_space = -1;
|
||||
cl_pos = 0;
|
||||
lines_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cl_pos--;
|
||||
if (cl_pos > *max_len) { /* for the last line */
|
||||
*max_len = cl_pos;
|
||||
}
|
||||
return lines_num;
|
||||
}
|
||||
|
||||
/* #define PRINT_TEXT(win, l_buf, text, i, c_line_len, win_width, line_v_pos, \
|
||||
attrs) \
|
||||
strncpy(l_buf, text + i - c_line_len, c_line_len); \
|
||||
@@ -72,7 +117,7 @@ int32_t w_get_max_line_len(const char *text, int32_t *line_count) {
|
||||
}
|
||||
*/
|
||||
|
||||
void PRINT_TEXT(WINDOW *win, char *l_buf, char *text, int32_t i,
|
||||
void line_print(WINDOW *win, char *l_buf, char *text, int32_t i,
|
||||
int32_t c_line_len, int32_t win_width, int32_t line_v_pos,
|
||||
int32_t attrs, int32_t x, int32_t max_line_len) {
|
||||
int32_t utf8len = 0;
|
||||
@@ -90,9 +135,27 @@ void PRINT_TEXT(WINDOW *win, char *l_buf, char *text, int32_t i,
|
||||
}
|
||||
}
|
||||
|
||||
void wline_print(WINDOW *win, wchar_t *w_text, int32_t i, int32_t c_line_len,
|
||||
int32_t win_width, int32_t y, int32_t attrs, int32_t x,
|
||||
int32_t max_line_len) {
|
||||
wchar_t l_buf[DIALOGUE_TEXT];
|
||||
int32_t b_len = c_line_len * sizeof(wchar_t);
|
||||
memcpy(l_buf, w_text + i - c_line_len, b_len);
|
||||
l_buf[c_line_len] = '\0';
|
||||
if ((attrs & PMT_ALIGN_CENTER) == PMT_ALIGN_CENTER) {
|
||||
int32_t _x = x + (win_width - c_line_len) / 2;
|
||||
mvwaddnwstr(win, y, _x, l_buf, c_line_len);
|
||||
} else if (attrs & PMT_POS_CENTER) {
|
||||
int32_t _x = x + (win_width - max_line_len) / 2;
|
||||
mvwaddnwstr(win, y, _x, l_buf, c_line_len);
|
||||
} else {
|
||||
mvwaddnwstr(win, y, x, l_buf, c_line_len);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t w_print_multiline_text(WINDOW *win, const char *_text,
|
||||
const int32_t win_width, const int32_t y,
|
||||
const int32_t x, const int16_t attrs) {
|
||||
const int32_t win_width, const int32_t y,
|
||||
const int32_t x, const int16_t attrs) {
|
||||
|
||||
int16_t line_v_pos = y;
|
||||
int32_t c_line_len = 0;
|
||||
@@ -126,17 +189,64 @@ int32_t w_print_multiline_text(WINDOW *win, const char *_text,
|
||||
|
||||
for (; text[i]; i++, c_line_len++) {
|
||||
if (text[i] == '\n') {
|
||||
PRINT_TEXT(win, l_buf, text, i, c_line_len, win_width, line_v_pos, attrs,
|
||||
line_print(win, l_buf, text, i, c_line_len, win_width, line_v_pos, attrs,
|
||||
x, m_line_len);
|
||||
c_line_len = -1;
|
||||
line_v_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_TEXT(win, l_buf, text, i, c_line_len, win_width, line_v_pos, attrs, x,
|
||||
line_print(win, l_buf, text, i, c_line_len, win_width, line_v_pos, attrs, x,
|
||||
m_line_len);
|
||||
|
||||
free(text);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t w_print_multiline_text_wide(WINDOW *win, const wchar_t *_text,
|
||||
size_t text_len, int32_t max_line_size,
|
||||
const int32_t win_width, const int32_t y,
|
||||
const int32_t x, const int16_t attrs) {
|
||||
|
||||
int16_t line_v_pos = y;
|
||||
int32_t c_line_len = 0;
|
||||
int32_t i = 0;
|
||||
int text_bytes_size = sizeof(wchar_t) * (text_len + 1);
|
||||
wchar_t *text = malloc(text_bytes_size);
|
||||
mempcpy(text, _text, text_bytes_size);
|
||||
|
||||
int l_size = 0;
|
||||
for (int m = 0; text[m] != '\0'; m++) {
|
||||
if (text[m] != '\n') {
|
||||
if (l_size >= win_width) {
|
||||
int j = m;
|
||||
while (text[j] != ' ') {
|
||||
j--;
|
||||
}
|
||||
text[j] = '\n';
|
||||
l_size = 0;
|
||||
} else {
|
||||
l_size++;
|
||||
}
|
||||
} else {
|
||||
l_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (; text[i]; i++, c_line_len++) {
|
||||
if (text[i] == '\n') {
|
||||
wline_print(win, text, i, c_line_len, win_width, line_v_pos, attrs, x,
|
||||
max_line_size);
|
||||
c_line_len = -1;
|
||||
line_v_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
wline_print(win, text, i, c_line_len, win_width, line_v_pos, attrs, x,
|
||||
max_line_size);
|
||||
|
||||
free(text);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -59,8 +59,8 @@ enum w_cbrp_code {
|
||||
|
||||
/* widget callback response data */
|
||||
typedef struct {
|
||||
enum w_cbrp_code code;
|
||||
struct w_val_t val;
|
||||
enum w_cbrp_code code;
|
||||
struct w_val_t val;
|
||||
} w_cbrp_data;
|
||||
|
||||
typedef struct {
|
||||
@@ -103,10 +103,16 @@ enum w_pmt_attrs {
|
||||
PMT_ALIGN_CENTER = 03,
|
||||
};
|
||||
|
||||
void w_init(w_t *w, w_t *w_parent, WINDOW **win, char *title);
|
||||
int32_t w_get_max_line_len(const char *text, int32_t *line_count);
|
||||
int32_t w_print_multiline_text(WINDOW *win, const char *text,
|
||||
const int32_t win_width, const int32_t y,
|
||||
const int32_t x, const int16_t attrs);
|
||||
void w_init(w_t *w, w_t *w_parent, WINDOW **win, char *title);
|
||||
int32_t w_get_max_line_len(const char *text, int32_t *line_count);
|
||||
int32_t w_print_multiline_text(WINDOW *win, const char *text,
|
||||
const int32_t win_width, const int32_t y,
|
||||
const int32_t x, const int16_t attrs);
|
||||
int32_t w_print_multiline_text_wide(WINDOW *win, const wchar_t *_text,
|
||||
size_t text_len, int32_t max_line_size, const int32_t win_width,
|
||||
const int32_t y, const int32_t x,
|
||||
const int16_t attrs);
|
||||
int32_t w_text_divide_by_lines(wchar_t *restrict text, size_t src_len,
|
||||
int max_x, int *max_len);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user