7#include "ui_ncurses_internal.h"
8#include <ncursesw/ncurses.h>
9#include <ncursesw/panel.h>
12#include "ui_notcurses_internal.h"
13#include <notcurses/notcurses.h>
80const wchar_t *
bw_ra = L"\u2192";
81const wchar_t *
bw_la = L"\u2190";
82const wchar_t *
bw_ua = L"\u2191";
83const wchar_t *
bw_da = L"\u2193";
90
91
92
94 _(
"black"),
_(
"red"),
_(
"green"),
_(
"yellow"),
_(
"blue"),
_(
"magenta"),
_(
"cyan"),
95 _(
"white"),
_(
"orange"),
_(
"bg"),
_(
"abg"),
_(
"bblack"),
_(
"bred"),
_(
"bgreen"),
96 _(
"byellow"),
_(
"bblue"),
_(
"bcyan"),
_(
"bmagenta"),
_(
"bwhite"),
_(
"borange"),
""};
217 memset(&mbstate, 0,
sizeof(mbstate));
294
295
296
297
298
299
300
301
303 wc[0] = wc[1] = L'\0';
304 mbstate_t state = {};
305 size_t len = mbrtowc(wc, &mbc, MB_CUR_MAX, &state);
313
314
315
316
317
318
319
320
321
323 const char *src_ptr = mb_str;
324 mbstate_t state = {};
325 size_t wc_count = mbsrtowcs(NULL, &src_ptr, 0, &state);
326 if (wc_count == (size_t)-1)
329 wmemset((wchar_t *)&state, 0,
sizeof(state) /
sizeof(wchar_t));
330 wchar_t *wc_str = malloc((wc_count + 1) *
sizeof(wchar_t));
333 mbsrtowcs(wc_str, &src_ptr, wc_count + 1, &state);
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
354
355
356
357
358
359
360
361
366 fprintf(stderr,
_(
"\n\nABEND: %s (code: %d)\n"), s, ec);
373
374
375
376
377
378
379
380
381
382
383
384
385
386
389 ui_log(ERROR,
_(
"Maximum number of surfaces (%d) exceeded"), SFC_MAX);
394 wlines =
min(wlines, maxy);
395 wcols =
min(wcols, maxx);
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
427 ui_log(ERROR,
_(
"Maximum number of surfaces (%d) exceeded"), SFC_MAX);
430 if (wlines == 0 || wcols == 0) {
431 ui_log(ERROR,
_(
"Invalid window size: lines=%d, cols=%d"), wlines, wcols);
436 if (wbegy > maxy || wbegx > maxx) {
437 ui_log(ERROR,
_(
"Invalid window position: wbegy=%d, wbegx=%d, wlines=%d, wcols=%d"), wbegy, wbegx, wlines, wcols);
440 wlines =
min(wlines, maxy);
441 wcols =
min(wcols, maxx);
442 split_x =
min(split_x, maxx);
443 uint split_wlines =
min(wlines + split_y + 1, maxy);
444 wcols =
min(wcols, maxx);
460
461
462
463
464
465
480 for (x = 1; x < maxx - 1; x++)
483 for (y = 1; y < maxy - 1; y++) {
488 for (x = 1; x < maxx - 1; x++)
494
495
496
497
498
499
500
501
502
503
507 for (uint x = 1; x < maxx - 1; x++)
513
514
515
516
517
518
519
520
521
522
523
528 uint y = separator_line;
540 l = wcswidth(text_wc, wcslen(text_wc));
544 l =
min(l, maxx - 7);
554
555
556
557
558
559
560
561
562
564 if (!title || !*title)
575 l = wcswidth(title_wc, wcslen(title_wc));
576 l =
min(l, maxx - 7);
584 while (x < maxx - 1) {
593
594
595
596
597
598
599
600
602 UiChyron *chyron = (UiChyron *)calloc(1,
sizeof(UiChyron));
610 chyron->key[i] = (UiChyronKey *)calloc(1,
sizeof(UiChyronKey));
611 if (!chyron->key[i]) {
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
635 bool a_toi_error =
false;
651
652
653
654
655
662 if (chyron->key[i]) {
663 free(chyron->key[i]);
664 chyron->key[i] =
nullptr;
672
673
674
675
676
678 if (chyron->key[k]->text[0] !=
'\0')
684
685
686
687
688
689
690
691
692
697 chyron->key[k]->text[0] =
'\0';
698 chyron->key[k]->keycode = kc;
699 chyron->key[k]->active =
true;
700 chyron->key[k]->cell_base = cell_base;
703
704
705
706
707
708
709
710
711
712
713
714
715
716
721 chyron->key[k]->text[0] =
'\0';
722 chyron->key[k]->keycode = kc;
723 chyron->key[k]->active =
true;
727
728
729
730
731
733 chyron->key[k]->text[0] =
'\0';
736
737
738
739
740
742 chyron->key[k]->active =
true;
745
746
747
748
749
752 chyron->key[k]->active =
true;
755
756
757
758
759
761 chyron->key[k]->active =
false;
764
765
766
767
770 chyron->key[k]->active =
false;
773
774
775
776
777
778
779
780
781
790 if (chyron->key[k]->text[0] ==
'\0' || !chyron->key[k]->active) {
794 cell_base = chyron->key[k]->cell_base;
796 cx = chyron->cmplx_buf;
797 ui_mbstr_to_cellstr(chyron->sfc, chyron->w,
804 ui_mbstr_to_cellstr(chyron->sfc, chyron->w,
811 cx = chyron->cmplx_buf;
812 ui_mbstr_to_cellstr(chyron->sfc, chyron->w, cx, chyron->key[k]->text, &cell_base, &pos,
MAXLEN - 1);
815 chyron->key[k]->end_pos = end_pos;
817 chyron->key[k]->text
, chyron->key[k]->end_pos
);
820 ui_mbstr_to_cellstr(chyron->sfc, chyron->w, chyron->cmplx_buf,
" ", &cell_base, &pos,
MAXLEN - 1);
824
825
826
827
828
829
830
831
832
833
834
835
836
847
848
849
850
851
852
853
854
855
856
857
858
859
860
865 if (chyron->key[i]->text[0] !=
'\0' && chyron->key[i]->active)
866 if (chyron->key[i]->end_pos >= x) {
872 return chyron->key[k]->keycode;
878
879
880
881
882
883
884
885
887 if (rgb->r == rgb->g && rgb->g == rgb->b) {
892 return ((rgb->r - 8) / 10) + 231;
894 uint r_index = (rgb->r < 45) ? 0 : (rgb->r - 60) / 40 + 1;
895 uint g_index = (rgb->g < 45) ? 0 : (rgb->g - 60) / 40 + 1;
896 uint b_index = (rgb->b < 45) ? 0 : (rgb->b - 60) / 40 + 1;
897 return 16 + (36 * r_index) + (6 * g_index) + b_index;
901
902
903
904
905
906
907
910
911
915 rgb.r = rgb.g = rgb.b = 0;
920 }
else if (idx >= 16 && idx <= 231) {
922 rgb.r = (idx / 36) % 6 * 51;
923 rgb.g = (idx / 6) % 6 * 51;
924 rgb.b = (idx % 6) * 51;
925 }
else if (idx >= 232 && idx <= 255) {
926 uint gray = (idx - 232) * 11;
927 rgb.r = rgb.g = rgb.b = gray;
933
934
935
936
937
938
939
940
942 if (rgb->r == rgb->g && rgb->r == rgb->b) {
944 rgb->r = (
int)(pow((rgb->r / 255.0f), 1.0f /
GRAY_GAMMA) * 255.0f);
951 rgb->r = (
int)(pow((rgb->r / 255.0f), 1.0f /
RED_GAMMA) * 255.0f);
953 rgb->g = (
int)(pow((rgb->g / 255.0f), 1.0f /
GREEN_GAMMA) * 255.0f);
955 rgb->b = (
int)(pow((rgb->b / 255.0f), 1.0f /
BLUE_GAMMA) * 255.0f);
961
962
963
965
966
967
968
969
970
971
974 uint line, pos, msg_l, msg0_l, msg1_l, msg2_l, msg3_l;
977 fprintf(stderr,
_(
"\n\n%s\n%s\n%s\n%s\n\n"), msg0, msg1, msg2, msg3);
982 msg0_l = strlen(msg0);
983 msg1_l = strlen(msg1);
984 msg2_l = strlen(msg2);
985 msg3_l = strlen(msg3);
986 msg_l =
max(msg0_l, msg1_l);
987 msg_l =
max(msg_l, msg2_l);
988 msg_l =
max(msg_l, msg3_l);
989 msg_l =
max(msg_l, 50);
990 msg_l =
min(msg_l, maxx - 4);
991 pos = ((maxx - msg_l) - 4) / 2;
992 line = (maxy - 6) / 2;
996 msg_l + 2
, line
, pos
, title
);
1013 event
.y = event
.x = -1;
1026
1027
1028
1029
1030
1031
1032
1035 uint line, pos, msg_l, msg0_l, msg1_l;
1037 fprintf(stderr,
"\n\n%s\n", msg0);
1038 fprintf(stderr,
"%s\n", msg1);
1043 msg0_l = strlen(msg0);
1044 msg1_l = strlen(msg1);
1045 msg_l =
max(msg0_l, msg1_l);
1046 msg_l =
max(msg_l, 50);
1047 msg_l =
min(msg_l, maxx - 4);
1049 pos = ((maxx - msg_l) - 4) / 2;
1050 line = (maxy - 6) / 2;
1054 msg_l + 2
, line
, pos
, title
);
1070 event
.y = event
.x = -1;
1075 timeout_ms += timeout_secs * 1000;
1079 }
while (timeout_ms > 0);
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1098 fprintf(stderr,
_(
"Timeout in %d seconds\n"), timeout_ms / 1000);
1108
1109
1110
1111
1112
1113
1114
1115
1116
1126
1127
1128
1129
1130
1131
1132
1133
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1156 if (timeout_ms <= 0)
1166 memset(fds, 0,
sizeof(fds));
1169 fds[nfds].events = POLLIN;
1172 int poll_rc = poll(fds, nfds, timeout_ms);
1180 for (nfds_t i = ext_start_idx; i < nfds; i++) {
1181 if (fds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
1182 reg_idx = i - ext_start_idx;
1193
1194
1195
1196
1197
1198
1199
1202 uint line, pos, msg_l, msg0_l, msg1_l, msg2_l, msg3_l;
1204 fprintf(stderr,
"\n\n%s\n", msg0);
1205 fprintf(stderr,
"%s\n", msg1);
1206 fprintf(stderr,
"%s\n", msg2);
1207 fprintf(stderr,
"%s\n\n", msg3);
1212 msg0_l = strlen(msg0);
1213 msg1_l = strlen(msg1);
1214 msg2_l = strlen(msg2);
1215 msg3_l = strlen(msg3);
1216 msg_l =
max(msg0_l, msg1_l);
1217 msg_l =
max(msg_l, msg2_l);
1218 msg_l =
max(msg_l, msg3_l);
1219 msg_l =
max(msg_l, 50);
1220 msg_l =
min(msg_l, maxx - 4);
1222 pos = ((maxx - msg_l) - 4) / 2;
1223 line = (maxy - 6) / 2;
1227 msg_l + 2
, line
, pos
, title
);
1243 event
.y = event
.x = -1;
1253
1254
1255
1256
1260 uint line, pos, cols;
1263 bool f_xwgetch =
true;
1264 if (emsg_str[0] ==
'␛' && emsg_str[1] ==
'w') {
1270 fprintf(stderr,
"\n%s\n", emsg);
1276 cols =
max(cols, 50);
1277 pos = (maxx - cols - 4) / 2;
1278 line = (maxy - 4) / 2;
1282 4
, line
, line
, pos
, title
);
1283 ui_log(ERROR,
"%s", tmp_str);
1296 event
.y = event
.x = -1;
1306
1307
1308
1309
1310
1316 fprintf(stderr,
"\n%s\n", title);
1317 fprintf(stderr,
"%s\n", action_str);
1320 len =
max(strlen(title), strlen(action_str));
1323 col = (maxx - len - 4) / 2;
1324 line = (maxy - 4) / 2;
1327 line
, line
, col
, title
);
1337 event
.y = event
.x = -1;
1347
1348
1349
1350
1351
1352
1356 time_t t = time(NULL);
1357 struct tm *tp = local ? localtime(&t) : gmtime(&t);
1359 strftime(buf, n,
_(
"%Y-%m-%dT%H:%M:%S%z"), tp);
1361 strftime(buf, n,
_(
"%Y-%m-%dT%H:%M:%SZ"), tp);
1365#define AS_STRING(NAME) #NAME,
1370 return _(
"unknown");
1373#define AS_STRING(NAME) #NAME,
1378 [FATAL] =
"\033[1;31m",
1379 [ERROR] =
"\033[0;31m",
1380 [WARN] =
"\033[0;33m",
1381 [INFO] =
"\033[0;32m",
1382 [VERBOSE] =
"\033[0;36m",
1383 [DEBUG] =
"\033[0;34m",
1384 [SILENT] =
_(
"SILENT"),
1394
1395
1396
1407 fprintf(stderr,
"%s\n%s\n%s\n%s\n",
em0,
em1,
em2,
em3);
1414 char *p = getenv(
_(
"USER"));
1416 if (ttyname_r(STDERR_FILENO, ttyname,
sizeof(ttyname)) == 0)
1419 ui_log(INFO,
"%s:",
em0);
1423
1424
1426
1427
1428
1429
1430
1431
1432
1433
1434
1441 uint _fg_clr, _bg_clr;
1442 uint fg_clr, bg_clr;
1443 char *ansi_p = ansi_str + 2;
1445 fg = fg_clr = (uint)_fg_clr;
1446 bg = bg_clr = (uint)_bg_clr;
1448 tok = strtok((
char *)ansi_p,
";m");
1449 bool a_toi_error =
false;
1451 if (tok ==
nullptr || *tok ==
'\0')
1457 if (t0 ==
'3' || t0 ==
'4') {
1459 tok = strtok(
nullptr,
";m");
1460 if (tok !=
nullptr) {
1462 tok = strtok(
nullptr,
";m");
1463 if (tok !=
nullptr) {
1467 }
else if (*tok ==
'2') {
1468 tok = strtok(
nullptr,
";m");
1470 tok = strtok(
nullptr,
";m");
1472 tok = strtok(
nullptr,
";m");
1480 }
else if (t1 ==
'9') {
1485 }
else if (t1 >=
'0' && t1 <=
'7') {
1492 }
else if (t0 ==
'4') {
1500 }
else if (t0 ==
'0') {
1511 switch (
a_toi(tok
, &a_toi_error
)) {
1537 }
else if (len == 0) {
1542 tok = strtok(
nullptr,
";m");
1544 if (!a_toi_error && (fg_clr != fg || bg_clr != bg))
#define min(x, y)
min macro evaluates two expressions, returning least result
#define max(a, b)
max macro evaluates two expressions, returning greatest result.
int ui_border_draw(UiSurface *sfc)
int ui_surface_addwin(UiSurface *s, ss_t w, uint p, uint lines, uint cols, uint y, uint x)
Add a new window to the specified UiSurface.
const wchar_t * border_none
#define SUB_SURFACE_LIST(X)
void ui_render()
Render the UI by updating panels and refreshing the display.
char const colors_text[][10]
Color names for .minitrc overrides.
int ui_tracked_sfc_split_box(uint wlines, uint wcols, uint split_y, uint split_x, uint wbegy, uint wbegx, const char *wtitle)
Create a new surface with a split box window.
int ui_draw_text(UiSurface *s, ss_t w, uint y, uint x, const char *text)
on specified window, move to y, x, add string
int ui_wmove(UiSurface *s, ss_t w, uint y, uint x)
Move the cursor to a specified position within a UiSurface.
const char * ui_sub_surface_str(ss_t w)
int ui_cm_surface_destroy(UiSurface *sfc)
Destroy the most recently created surface.
void ui_surface_destroy(UiSurface *s)
Destroy a UiSurface, cleaning up its windows and panels.
int ui_border_title(UiSurface *sfc, const char *title)
Draw a box with a title around the specified window.
const wchar_t * border_double
int ui_getmaxy(UiSurface *s, ss_t w)
Get the maximum number of lines (rows) of a UiSurface.
UiSurface * ui_surface_box(UiSurface *parent, uint p, uint lines, uint cols, uint y, uint x, const char *title)
Create a new UI surface with a border box and optional title.
#define CHYRON_KEY_MAXLEN
int ui_border_ysplit_text(UiSurface *sfc, char *text, uint separator_line)
Draw a box with a separator line and text around the specified window.
const wchar_t * border_single
void ui_get_screen_size(uint *lines, uint *cols)
Get the current screen size (number of lines and columns).
void ui_shutdown()
Shutdown the UI runtime, cleaning up resources and freeing memory.
int ui_border_ysplit(UiSurface *sfc, uint y)
Draw a box with a separator line around the specified window.
#define LOG_LEVEL_LIST(X)
void ui_initialize_sio(SIO *sio)
int ui_curs_set(int visibility)
Set the visibility of the cursor.
int ui_tracked_sfc_box(uint wlines, uint wcols, uint wbegy, uint wbegx, const char *wtitle)
Create a new surface with a box window.
int ui_getmaxx(UiSurface *s, ss_t w)
Get the maximum number of columns of a UiSurface.
const wchar_t * border_heavy
const wchar_t * border_rounded
int ui_wclrtoeol(UiSurface *s, ss_t w)
Clear to the end of the line in a surface window.
int ui_bkgdset(UiSurface *s, ss_t w, const UiCell *cell)
Set the background for new content to be written to a specific window within a UiSurface.
#define UIKEY_STREAM_DATA
int ui_get_event(UiSurface *s, ss_t w, UiChyron *chyron, UiEvent *ev, int timeout_ms)
Read input events.
void ui_unset_chyron_key(UiChyron *chyron, uint k)
Unset chyron key.
void ui_set_chyron_key(UiChyron *chyron, uint k, char *s, uint kc)
Set chyron key with default color pair (cp_nt_rev).
void ui_deactivate_all_chyron_keys(UiChyron *chyron)
Deactivate all chyron keys.
char ui_log_file_name[MAXLEN]
FILE * ui_open_log()
Open the log file for writing.
wchar_t * ui_mbstr_to_wcstr(const char *mb_str)
Convert a multibyte string to a wide character string.
UiChyron * ui_new_chyron(UiSurface *sfc, ss_t w)
Create new chyron structure.
char * ui_iso8601_timestamp(char *buf, size_t n, bool local)
Generate an ISO 8601 timestamp string.
const char *const ui_log_level_s[]
RGB ui_xterm256_idx_to_rgb(uint idx)
Convert XTerm 256 color index to RGB.
void ui_activate_chyron_key(UiChyron *chyron, uint k)
Activate chyron key.
void ui_display_chyron(UiSurface *sfc, ss_t w, UiChyron *chyron, uint line, uint col)
Display chyron on the specified line and column of the surface.
void ui_set_chyron_key_cb(UiChyron *chyron, uint k, char *s, uint kc, UiCell cell_base)
Set chyron key with color pair (cp).
int ui_assign_chyron_win(UiChyron *chyron, UiSurface *sfc, ss_t w, char *y)
Assign surface and window to chyron structure.
bool ui_init_clr_palette(SIO *sio)
bool ui_is_set_chyron_key(UiChyron *chyron, uint k)
Check if function key label is set.
UiLogLevel ui_min_log_level
void ui_abend(int ec, char *s)
Convert multibyte string to complex character array.
void ui_parse_ansi(char *ansi_str, attr_t *attr, uint *cpx)
Parse ANSI escape sequences for color and attributes.
UiChyron * ui_destroy_chyron(UiChyron *chyron)
Destroy UiChyron structure.
int ui_get_chyron_key(UiChyron *chyron, uint x)
Get keycode from chyron.
void ui_mbc_to_wc(wchar_t wc[2], const char mbc)
Convert a multibyte character to a wide character.
void ui_deactivate_chyron_key(UiChyron *chyron, uint k)
Deactivate chyron key.
const char *const ui_logcolor[]
void ui_apply_gamma(RGB *rgb)
Apply gamma correction to RGB color.
void ui_activate_all_chyron_keys(UiChyron *chyron)
Deactivate chyron key.
uint ui_rgb_to_xterm256_idx(RGB *rgb)
Convert RGB color to XTerm 256 color index.
void ui_compile_chyron(UiChyron *chyron)
construct the chyron string from the chyron structure
int ui_pair_content(uint pair, uint *fg, uint *bg)
Get the foreground and background colors of a specified color pair.
uint ui_add_pair(uint fg, uint bg)
Add a new color pair to the UI, or retrieve the index of an existing pair.
UiSurface * ui_surface[UI_SFC_MAX]
UiCell ui_cell_from_ucp(const wchar_t *ucp, const uint32_t *fg, const uint32_t *bg)
Convert a Unicode code point to a curses UiCell with specified foreground and background colors.
int ui_color_from_rgb(RGB *rgb)
Convert RGB to curses color index, adding new color if necessary.
int ui_chg_color(uint16_t color_idx, uint32_t *color)
Change the RGB color value for a given color index.
int ui_mvwadd_wchnstr(UiSurface *s, ss_t w, uint y, uint x, const UiCell *cmplx_buf, uint n)
Draw a complex character string at a specific position in a surface window, with a maximum length.
int ui_mvwaddnwstr(UiSurface *s, ss_t w, uint y, uint x, const wchar_t *wstr, int m)
Draw a wide-character string at a specific position in a surface window, with a maximum length.
int ui_mvwadd_wchstr(UiSurface *s, ss_t w, uint y, uint x, const UiCell *cmplx_buf)
Draw a complex character string at a specific position in a surface window.
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
size_t strnz(char *, size_t)
terminates string at New Line, Carriage Return, or max_len
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
int a_toi(char *, bool *)
a safer alternative to atoi() for converting ASCII strings to integers.
bool restore_shell_tioctl()
restore_shell_tioctl() - restore shell terminal settings
void sig_dfl_mode()
Set signal handlers to default behavior.
int ui_perror(char *emsg_str)
Display a simple error message window or print to stderr.
void ui_unregister_read_fd(int fd)
Unregister an external file descriptor from polling.
void ui_register_read_fd(int fd, int token_id)
Register an external file descriptor for polling.
int ui_timeout_prompt(char *msg0, char *msg1, uint timeout_ms, uint timeout_secs)
Display a timeout prompt window or print to stderr.
int ui_update_timeout_prompt(UiSurface *sfc, ss_t w, uint timeout_ms)
Update the timeout prompt with the remaining time.
int ui_poll_reg_read_fd(int timeout_ms)
Poll for input on registered external files.
bool ui_action_disposition(char *title, char *action_str)
Display a simple action disposition message window or print to stderr.
int ui_answer_yn(char *msg0, char *msg1, char *msg2, char *msg3)
Accept a single letter answer.
int ui_display_error(char *msg0, char *msg1, char *msg2, char *msg3)
Display an error message window or print to stderr.
ext_fd_reg_t ext_fds[MAX_EXT_FDS]