C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
ui_common.c
Go to the documentation of this file.
1#include "cm.h"
2#include "ui_backend.h"
3#include <fcntl.h>
4#include <iso646.h>
5#include <math.h>
6#ifdef UAL_UI
7#include "ui_ncurses_internal.h"
8#include <ncursesw/ncurses.h>
9#include <ncursesw/panel.h>
10#endif
11#ifdef NOTCURSES_UI
12#include "ui_notcurses_internal.h"
13#include <notcurses/notcurses.h>
14#endif
15#include <poll.h>
16#include <stdbool.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/ioctl.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <termios.h>
23#include <time.h>
24#include <unistd.h>
25#include <wchar.h>
26
27BorderWide bw;
28
32unsigned int cmd_key;
33bool f_sigwench = false;
34uint16_t win_attr;
35uint16_t box_attr;
37uint m_cols;
38uint m_begy = -1;
39uint m_begx = -1;
45char fn[MAXLEN];
46char em0[MAXLEN];
47char em1[MAXLEN];
48char em2[MAXLEN];
49char em3[MAXLEN];
50bool f_ncurses_open = false;
51bool f_notcurses_open = false;
52
53// NOTE: It should be safe to use ui_ctx as a global variable, as it is only
54// used for input handling and does not contain any state that would be modified
55// by multiple threads. However, if you plan to use this in a multi-threaded
56// environment, consider using thread-local storage or mutexes to protect access
57// to this structure.
58
59ui_context_t ui_ctx;
60
62double GRAY_GAMMA = 1.2; /**< Gamma correction. Set in .minitrc */
63double RED_GAMMA = 1.2;
64double GREEN_GAMMA = 1.2;
65double BLUE_GAMMA = 1.2;
66
67/** BOX WIDE UNICODE CODEPOINTS */
68const wchar_t *border_single = L"─│├┤┬┴┼┌┐└┘";
69const wchar_t *border_double = L"═║╠╣╦╩╬╔╗╚╝";
70const wchar_t *border_rounded = L"─│├┤┬┴┼╭╮╰╯";
71const wchar_t *border_heavy = L"━┃┣┫┳┻╋┏┓┗┛";
72const wchar_t *border_none = L" ";
73
74/** MISCELANEOUS UNICODE CODEPOINTS */
75const wchar_t *bw_rtl = L"\u256d"; /**< rounded top left */
76const wchar_t *bw_rtr = L"\u256e"; /**< rounded top right */
77const wchar_t *bw_rbl = L"\u2570"; /**< rounded bottom left */
78const wchar_t *bw_rbr = L"\u256f"; /**< rounded bottom right */
79const wchar_t *bw_sp = L"\x20"; /**< space */
80const wchar_t *bw_ra = L"\u2192"; /**< large right arrow */
81const wchar_t *bw_la = L"\u2190"; /**< large left arrow */
82const wchar_t *bw_ua = L"\u2191"; /**< large up arrow */
83const wchar_t *bw_da = L"\u2193"; /**< large down arrow */
84const wchar_t *bw_ran = L"\u276F"; /**< right_angle */
85const wchar_t *bw_lan = L"\u276E"; /**< left_angle */
86const wchar_t *bw_chk = L"\u2611"; /**< left_angle */
87const wchar_t *bw_h09 = L"\u23BD"; /**< horizontal line 9 */
88
89/** colors_text
90 @brief Color names for .minitrc overrides
91 @details These names are used in .minitrc to specify color overrides The
92 order of these names corresponds to the ColorsEnum values */
93char const colors_text[][10] = {
94 _("black"), _("red"), _("green"), _("yellow"), _("blue"), _("magenta"), _("cyan"),
95 _("white"), _("orange"), _("bg"), _("abg"), _("bblack"), _("bred"), _("bgreen"),
96 _("byellow"), _("bblue"), _("bcyan"), _("bmagenta"), _("bwhite"), _("borange"), ""};
97
98// -----------------------------------------------------------------------
99// Standard UiCells
100// -----------------------------------------------------------------------
101
106UiCell cell_nt;
110UiCell cell_box;
111UiCell cell_ind;
114UiCell cell_ln;
115UiCell cell_ran;
116UiCell cell_chk;
117UiCell cell_ls;
118UiCell cell_rs;
119UiCell cell_ts;
120UiCell cell_bs;
121UiCell cell_tl;
122UiCell cell_tr;
123UiCell cell_ho;
124UiCell cell_ve;
125UiCell cell_bl;
126UiCell cell_br;
127UiCell cell_lt;
128UiCell cell_rt;
129UiCell cell_tt;
130UiCell cell_bt;
131UiCell cell_cr;
132UiCell cell_sp;
133
134// -----------------------------------------------------------------------
135// Standard Color Pairs
136// -----------------------------------------------------------------------
137
138ushort cp_box; /**< border */
139ushort cp_ind; /**< indicator character */
140ushort cp_cmdln; /**< command line */
141ushort cp_title; /**< border title */
142ushort cp_nt; /**< normal text */
143ushort cp_nt_rev; /**< normal text reverse */
144ushort cp_nt_hl; /**< normal text highlight */
145ushort cp_nt_hl_rev; /**< normal text highlight reverse */
146ushort cp_ln; /**< line numbers */
147ushort cp_default; /**< default color pair */
148ushort cp_fill_char; /**< field fill characters */
149ushort cp_brackets; /**< field enclosure brackets */
150ushort cp_red; /**< red background - for testing */
151ushort cp_green; /**< green background - for testing */
152ushort cp_yellow; /**< yellow background - for testing */
153ushort cp_blue; /**< blue background - for testing */
154
155// -----------------------------------------------------------------------
156// Standard VGA Colors
157// -----------------------------------------------------------------------
158
159STDRGB std_color[] = {
160 {0, 0, 0},
161 {128, 0, 0},
162 {0, 128, 0},
163 {128, 128, 0},
164 {0, 0, 128},
165 {128, 0, 128},
166 {0, 128, 128},
167 {192, 192, 192},
168 {128, 128, 128},
169 {255, 0, 0},
170 {0, 255, 0},
171 {255, 255, 0},
172 {0, 0, 255},
173 {255, 0, 255},
174 {0, 255, 255},
175 {255, 255, 255}};
176
177bool ui_init_clr_palette(SIO *sio);
178//-------------------------------------------------------------------------
179// Initialization
180// -------------------------------------------------------------------------
181
182void ui_initialize_sio(SIO *sio) {
183 /** gamma correction values */
184 /** These are read from ~/.minitrc */
185 /** used when initializing colors */
186 ui->sio = sio;
192 //
193 // Initialize Standardized color pairs
194 //
211 //
212 // Initialize Standardized UiCells
213 //
216 mbstate_t mbstate;
217 memset(&mbstate, 0, sizeof(mbstate));
218 wchar_t brktl = sio->brackets[0];
220 wchar_t brktr = sio->brackets[1];
245}
246
247bool ui_init_clr_palette(SIO *sio) {
287 return true;
288}
289// -----------------------------------------------------------------------------
290// Multibyte, Wide Character (wchar_t), and Complex Character (cchar_t) Support
291// -----------------------------------------------------------------------------
292
293/** mbc_to_wc
294 @brief Convert a multibyte character to a wide character
295 @ingroup window_support
296 @param wc Output array for wide characters (size 2)
297 @param mbc Input multibyte character
298 @details This function converts a single multibyte character to a wide
299 character. It uses the mbrtowc function to perform the conversion and handles
300 any errors by setting the output to a question mark ('?') if the conversion
301 fails. The output array is null-terminated. */
302void ui_mbc_to_wc(wchar_t wc[2], const char mbc) {
303 wc[0] = wc[1] = L'\0';
304 mbstate_t state = {};
305 size_t len = mbrtowc(wc, &mbc, MB_CUR_MAX, &state);
306 if (len <= 0) {
307 wc[0] = L'?';
308 wc[1] = L'\0';
309 len = 1;
310 }
311}
312/** ui_mbstr_to_wcstr
313 @brief Convert a multibyte string to a wide character string
314 @ingroup window_support
315 @param mb_str Input multibyte string
316 @return Pointer to newly allocated wide character string, or nullptr on error
317 @details This function converts a null-terminated multibyte string to a wide
318 character string. It first calculates the required length for the wide
319 character string, allocates memory for it, and then performs the conversion.
320 The caller is responsible for freeing the allocated memory. If the conversion
321 fails, it returns nullptr. */
322wchar_t *ui_mbstr_to_wcstr(const char *mb_str) {
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)
327 return nullptr;
328 src_ptr = mb_str;
329 wmemset((wchar_t *)&state, 0, sizeof(state) / sizeof(wchar_t));
330 wchar_t *wc_str = malloc((wc_count + 1) * sizeof(wchar_t));
331 if (!wc_str)
332 return nullptr;
333 mbsrtowcs(wc_str, &src_ptr, wc_count + 1, &state);
334 return wc_str;
335}
336/** ui_mbstr_to_cellstr
337 @brief Convert multibyte string to complex character array
338 @ingroup UiChyron
339 @param cmplx_buf Output buffer for complex characters
340 @param str Input multibyte string
341 @param cell_base Base cell for attributes and color pair
342 @param p Pointer to current position in the output buffer, updated as
343 characters are added
344 @param atmost Maximum length of the output buffer
345 @return Number of bytes processed from the input string
346 @details This function converts a multibyte string to an array of complex
347 characters (cchar_t) that can be used with NCurses functions. It handles
348 multibyte characters and applies the attributes and color pair from the base
349 cell to each character. The p parameter is updated to reflect the current
350 position in the output buffer, and the function ensures that it does not exceed
351 the maximum length specified by atmost.
352*/
353/** ui_abend
354 @brief Handle abnormal termination of the program
355 @ingroup window_support
356 @param ec Exit code to return to the operating system
357 @param s Message describing the reason for termination
358 @details This function is called when the program encounters a critical error
359 that requires it to terminate. It performs necessary cleanup, restores terminal
360 settings, and outputs an error message to stderr before exiting with the
361 specified exit code. */
362void ui_abend(int ec, char *s) {
366 fprintf(stderr, _("\n\nABEND: %s (code: %d)\n"), s, ec);
367 exit(EXIT_FAILURE);
368}
369// -----------------------------------------------------------------------------
370// High Level Surface Instantiation
371// -----------------------------------------------------------------------------
372/** ui_tracked_sfc_box_com
373 @brief Create a new surface with a box window
374 @ingroup window_support
375 @param wlines Number of lines for the window
376 @param wcols Number of columns for the window
377 @param wbegy Starting Y position for the window
378 @param wbegx Starting X position for the window
379 @param wtitle Title for the window
380 @return 0 on success, -1 on error
381 @details This function creates a new surface and adds a box window to it.
382 It checks if the maximum number of surfaces has been exceeded and adjusts the
383 window size based on the screen size. The new surface is stored in the global
384 ui_surface array, and the surface pointer (sfc_ptr) is incremented. The window
385 is then rendered on the screen.
386 */
387int ui_tracked_sfc_box(uint wlines, uint wcols, uint wbegy, uint wbegx, const char *wtitle) {
388 if (sfc_ptr >= SFC_MAX) {
389 ui_log(ERROR, _("Maximum number of surfaces (%d) exceeded"), SFC_MAX);
390 exit(EXIT_FAILURE);
391 }
392 uint maxy, maxx;
393 ui_get_screen_size(&maxy, &maxx);
394 wlines = min(wlines, maxy);
395 wcols = min(wcols, maxx);
396 sfc_ptr++;
397 // -------------------> UI_win_box <-------------------
398 ui_surface[sfc_ptr] = ui_surface_box(nullptr, 0, wlines + 2, wcols + 2, wbegy, wbegx, wtitle);
399 UiSurface *sfc = ui_surface[sfc_ptr];
400 ui_surface_addwin(sfc, WIN, BOX, wlines, wcols, 1, 1);
402 return 0;
403}
404// -----------------------------------------------------------------------------
405// box_split_new
406// -----------------------------------------------------------------------------
407/** surface_split_box_win_new
408 @brief Create a new surface with a split box window
409 @ingroup window_support
410 @param wlines Number of lines for the main window
411 @param wcols Number of columns for the main window
412 @param split_y Y position for the split line
413 @param split_x X position for the split line (not implemented yet)
414 @param wbegy Starting Y position for the window
415 @param wbegx Starting X position for the window
416 @param wtitle Title for the window
417 @return 0 on success, -1 on error
418 @details This function creates a new surface and adds a split box window to it.
419 It checks if the maximum number of surfaces has been exceeded and adjusts the
420 window size based on the screen size. The new surface is stored in the global
421 ui_surface array, and the surface pointer (sfc_ptr) is incremented. The main
422 window and the split window are then rendered on the screen, with a separator
423 line drawn at the specified Y position.
424 */
425int ui_tracked_sfc_split_box(uint wlines, uint wcols, uint split_y, uint split_x, uint wbegy, uint wbegx, const char *wtitle) {
426 if (sfc_ptr >= SFC_MAX) {
427 ui_log(ERROR, _("Maximum number of surfaces (%d) exceeded"), SFC_MAX);
428 exit(EXIT_FAILURE);
429 }
430 if (wlines == 0 || wcols == 0) {
431 ui_log(ERROR, _("Invalid window size: lines=%d, cols=%d"), wlines, wcols);
432 return -1;
433 }
434 uint maxy, maxx;
435 ui_get_screen_size(&maxy, &maxx);
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);
438 return -1;
439 }
440 wlines = min(wlines, maxy);
441 wcols = min(wcols, maxx);
442 split_x = min(split_x, maxx); // not implemented yet
443 uint split_wlines = min(wlines + split_y + 1, maxy);
444 wcols = min(wcols, maxx);
445 sfc_ptr++;
446 // -------------------> surface_new <-------------------
447 ui_surface[sfc_ptr] = ui_surface_box(nullptr, 0, split_wlines + 2, wcols + 2, wbegy, wbegx, wtitle);
448 UiSurface *sfc = ui_surface[sfc_ptr];
449
450 ui_surface_addwin(sfc, WIN, BOX, wlines, wcols, 1, 1);
451 ui_border_ysplit(sfc, wlines + 1);
452 ui_surface_addwin(sfc, WIN2, BOX, 2, wcols, wlines + 2, 1);
454 return 0;
455}
456// -----------------------------------------------------------------------------
457// ui_cm_surface_destroy
458// -----------------------------------------------------------------------------
459/** ui_cm_destroy_surface
460 @brief Destroy the most recently created surface
461 @ingroup window_support
462 @return 0 on success, -1 if no surfaces exist
463 @details This function destroys the most recently created surface and decrements the surface pointer. It should be called when a surface is no longer needed to free up resources. If there are no surfaces to destroy, it returns -1.
464 @note The difference between this function and ui_surface_destroy() is that this function destroys the surface pointed to by the surface pointer (sfc_ptr) and decrements the surface pointer after destroying the surface.
465 */
466int ui_cm_surface_destroy(UiSurface *sfc) {
468 sfc_ptr--;
469 return 0;
470}
471// -----------------------------------------------------------------------------
472// ui_border_draw
473// -----------------------------------------------------------------------------
474int ui_border_draw(UiSurface *sfc) {
475 uint maxy = ui_getmaxy(sfc, BOX);
476 uint maxx = ui_getmaxx(sfc, BOX);
477 uint y = 0;
478 uint x = 0;
479 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_tl, 1);
480 for (x = 1; x < maxx - 1; x++)
481 ui_mvwadd_wchnstr(sfc, BOX, y, x, &cell_ho, 1);
482 ui_mvwadd_wchnstr(sfc, BOX, y, maxx - 1, &cell_tr, 1);
483 for (y = 1; y < maxy - 1; y++) {
484 ui_mvwadd_wchnstr(sfc, BOX, y, 0, &cell_ve, 1);
485 ui_mvwadd_wchnstr(sfc, BOX, y, maxx - 1, &cell_ve, 1);
486 }
487 ui_mvwadd_wchnstr(sfc, BOX, y, 0, &cell_bl, 1);
488 for (x = 1; x < maxx - 1; x++)
489 ui_mvwadd_wchnstr(sfc, BOX, y, x, &cell_ho, 1);
490 ui_mvwadd_wchnstr(sfc, BOX, y, maxx - 1, &cell_br, 1);
491 return 0;
492}
493/** ui_border-ysplit
494 @brief Draw a box with a separator line around the specified window
495 @ingroup window_support
496 @param box Pointer to the window to draw the box around
497 @param y Line number where the separator line should be drawn
498 @details This function draws a box around the specified window, similar to
499 border_draw(), but it also includes a horizontal separator line that divides the box
500 into two sections. The separator line is drawn at a fixed position (line 00,
501 page 00) and extends across the width of the box. Use this function when you
502 want to visually separate two sections within a window, such as for a header
503 and content area. */
504int ui_border_ysplit(UiSurface *sfc, uint y) {
505 uint maxx = ui_getmaxx(sfc, BOX);
506 ui_mvwadd_wchnstr(sfc, BOX, y, 0, &cell_lt, 1);
507 for (uint x = 1; x < maxx - 1; x++)
508 ui_mvwadd_wchnstr(sfc, BOX, y, x, &cell_ho, 1);
509 ui_mvwadd_wchnstr(sfc, BOX, y, maxx - 1, &cell_rt, 1);
510 return 0;
511}
512/** ui_border_ysplit_text
513 @brief Draw a box with a separator line and text around the specified window
514 @ingroup window_support
515 @param box Pointer to the window to draw the box around
516 @param text Text to display in the middle of the separator line
517 @param separator_line Line number where the separator line should be drawn
518 @details This function draws a box around the specified window, similar to
519 border_draw(), but it also includes a horizontal separator line that divides the box
520 into two sections. The separator line is drawn at the specified line number and
521 extends across the width of the box, with the provided text displayed in the
522 middle of the line. Use this function when you want to visually separate two
523 sections within a window and label the separator with descriptive text. */
524int ui_border_ysplit_text(UiSurface *sfc, char *text_in, uint separator_line) {
525 char text[MAXLEN];
526 uint maxx = ui_getmaxx(sfc, BOX);
527 uint l;
528 uint y = separator_line;
529 uint x = 0;
530 // Draw the horizontal line with text in the middle, so we start by drawing
531 // the left edge, then the text, then the right edge, and finally fill in the
532 // horizontal line on either side of the text.
533 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_lt, 1);
534 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_ho, 1);
535 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_rt, 1);
536 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_sp, 1);
537 strnz__cpy(text, text_in, maxx - 7);
538 wchar_t *text_wc;
539 text_wc = ui_mbstr_to_wcstr(text);
540 l = wcswidth(text_wc, wcslen(text_wc));
542 ui_mvwaddnwstr(sfc, BOX, y, x, text_wc, l);
543 x += l;
544 l = min(l, maxx - 7);
545 free(text_wc);
546 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_sp, 1);
547 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_lt, 1);
548 while (x < maxx - 1)
549 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_ho, 1);
550 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_rt, 1);
551 return 0;
552}
553/** border_title
554 @brief Draw a box with a title around the specified window
555 @ingroup window_support
556 @param box Pointer to the window to draw the box around
557 @param title Title text to display at the top of the box
558 @details This function draws a box around the specified window, similar to
559 border_draw(), but it also includes a title at the top of the box. The title
560 is displayed in the center of the top edge of the box, and the horizontal line
561 is drawn on either side of the title. Use this function when you want to
562 visually label a window with a title. */
563int ui_border_title(UiSurface *sfc, const char *title) {
564 if (!title || !*title)
565 return 0;
566 uint y = 0;
567 uint x = 0;
568 uint l;
569 uint maxx = ui_getmaxx(sfc, BOX);
570 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_tl, 1);
571 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_rt, 1);
572 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_sp, 1);
573 wchar_t *title_wc;
574 title_wc = ui_mbstr_to_wcstr(title);
575 l = wcswidth(title_wc, wcslen(title_wc));
576 l = min(l, maxx - 7);
578 ui_mvwaddnwstr(sfc, BOX, y, x, title_wc, l);
579 ui_bkgdset(sfc, BOX, &cell_box);
580 x += l;
581 free(title_wc);
582 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_sp, 1);
583 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_lt, 1);
584 while (x < maxx - 1) {
585 ui_mvwadd_wchnstr(sfc, BOX, y, x++, &cell_ho, 1);
586 }
587 return 0;
588}
589// -----------------------------------------------------------------------
590// Chyron API
591// -----------------------------------------------------------------------
592/** new_chyron
593 @brief Create new chyron structure
594 @ingroup UiChyron
595 @return pointer to new chyron structure
596 @details This function allocates memory for a new chyron structure and its
597 associated keys. It initializes the structure to zero and returns a pointer
598 to the newly created chyron. If memory allocation fails, it calls ui_abend() to
599 terminate the program with an error message.
600 */
601UiChyron *ui_new_chyron(UiSurface *sfc, ss_t w) {
602 UiChyron *chyron = (UiChyron *)calloc(1, sizeof(UiChyron));
603 if (!chyron) {
604 ui_abend(-1, _("calloc chyron failed"));
605 return nullptr;
606 }
607 chyron->sfc = sfc;
608 chyron->w = w;
609 for (int i = 0; i < CHYRON_KEYS; i++) {
610 chyron->key[i] = (UiChyronKey *)calloc(1, sizeof(UiChyronKey));
611 if (!chyron->key[i]) {
612 ui_abend(-1, _("calloc chyron->key[i] failed"));
613 return nullptr;
614 }
615 }
616 return chyron;
617}
618/** assign_chyron_win
619 @brief Assign surface and window to chyron structure
620 @ingroup UiChyron
621 @param chyron pointer to UiChyron structure
622 @param sfc pointer to UiSurface structure
623 @param win window index (WIN or BOX)
624 @param y line number for chyron display
625 @return 0 on success, -1 on error
626 @details This function assigns the specified surface and window to the chyron
627 structure. It also sets the line number for displaying the chyron. If the
628 input string y is "-", it sets the line number to the last line of the
629 surface. Otherwise, it converts the string y to an integer and sets it as the
630 line number, ensuring it does not exceed the maximum line number of the
631 surface.
632 @note Drop-down menus from the chyron will be added in the future
633 */
634int ui_assign_chyron_win(UiChyron *chyron, UiSurface *sfc, ss_t w, char *y) {
635 bool a_toi_error = false;
636 if (!sfc)
637 return -1;
638 chyron->sfc = sfc;
639 chyron->w = w;
640 if (*y == '-')
641 chyron->y = ui_getmaxy(sfc, w) - 1;
642 else {
643 chyron->y = a_toi(y, &a_toi_error);
644 if (a_toi_error)
645 return -1;
646 chyron->y = min(chyron->y, ui_getmaxy(sfc, w) - 1);
647 }
648 return 0;
649}
650/** destroy_chyron
651 @brief Destroy UiChyron structure
652 @ingroup UiChyron
653 @param chyron pointer to UiChyron structure
654 @return nullptr
655 */
656UiChyron *ui_destroy_chyron(UiChyron *chyron) {
657 uint i;
658
659 if (!chyron)
660 return nullptr;
661 for (i = 0; i < CHYRON_KEYS; i++) {
662 if (chyron->key[i]) {
663 free(chyron->key[i]);
664 chyron->key[i] = nullptr;
665 }
666 }
667 free(chyron);
668 chyron = nullptr;
669 return chyron;
670}
671/** is_set_chyron_key
672 @brief Check if function key label is set
673 @ingroup UiChyron
674 @param chyron structure
675 @param k Function key index (0-19)
676 @return true if set, false if not set */
677bool ui_is_set_chyron_key(UiChyron *chyron, uint k) {
678 if (chyron->key[k]->text[0] != '\0')
679 return true;
680 else
681 return false;
682}
683/** set_chyron_key
684 @brief Set chyron key with color pair (cp)
685 @ingroup UiChyron
686 @param chyron structure
687 @param k chyron key index (0-19)
688 @param s chyron key label
689 @param kc chyron key code
690 @param cell_base color pair for chyron key label
691 @details This function is like set_chyron_key, except it includes a color
692 pair numbers */
693void ui_set_chyron_key_cb(UiChyron *chyron, uint k, char *s, uint kc, UiCell cell_base) {
694 if (*s != '\0')
695 ssnprintf(chyron->key[k]->text, CHYRON_KEY_MAXLEN - 1, "%s", s);
696 else
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;
701}
702/** set_chyron_key
703 @brief Set chyron key with default color pair (cp_nt_rev)
704 @ingroup UiChyron
705 @param chyron structure
706 @param k chyron key index (0-19)
707 @param s chyron key label
708 @param kc chyron key code
709 @details This function sets the label and keycode for a function key in the
710 chyron structure. It uses the default color pair cp_nt_rev for the key
711 label. If the input string s is not empty, it copies the string into the
712 chyron key's text field. If the input string is empty, it sets the first
713 character of the text field to '\0' to indicate that the key is not set.
714 The keycode is stored in the chyron key's keycode field, and the color pair
715 index is set to cp_nt_rev.
716 */
717void ui_set_chyron_key(UiChyron *chyron, uint k, char *s, uint kc) {
718 if (*s != '\0')
719 ssnprintf(chyron->key[k]->text, CHYRON_KEY_MAXLEN - 1, "%s", s);
720 else
721 chyron->key[k]->text[0] = '\0';
722 chyron->key[k]->keycode = kc;
723 chyron->key[k]->active = true;
724 chyron->key[k]->cell_base = cell_nt_rev;
725}
726/** unset_chyron_key
727 @brief Unset chyron key
728 @ingroup UiChyron
729 @param chyron structure
730 @param k chyron_key index
731*/
732void ui_unset_chyron_key(UiChyron *chyron, uint k) {
733 chyron->key[k]->text[0] = '\0';
734}
735/** activate_chyron_key
736 @brief Activate chyron key
737 @ingroup UiChyron
738 @param chyron structure
739 @param k chyron_key index
740*/
741void ui_activate_chyron_key(UiChyron *chyron, uint k) {
742 chyron->key[k]->active = true;
743}
744/** deactivate_chyron_key
745 @brief Deactivate chyron key
746 @ingroup UiChyron
747 @param chyron structure
748 @param k chyron_key index
749*/
750void ui_activate_all_chyron_keys(UiChyron *chyron) {
751 for (int k = 0; k < CHYRON_KEYS; k++)
752 chyron->key[k]->active = true;
753}
754/** deactivate_chyron_key
755 @brief Deactivate chyron key
756 @ingroup UiChyron
757 @param chyron structure
758 @param k chyron_key index
759*/
760void ui_deactivate_chyron_key(UiChyron *chyron, uint k) {
761 chyron->key[k]->active = false;
762}
763/** deactivate_all_chyron_keys
764 @brief Deactivate all chyron keys
765 @ingroup UiChyron
766 @param chyron structure
767*/
768void ui_deactivate_all_chyron_keys(UiChyron *chyron) {
769 for (int k = 0; k < CHYRON_KEYS; k++)
770 chyron->key[k]->active = false;
771}
772/** compile_chyron
773 @brief construct the chyron string from the chyron structure
774 @ingroup UiChyron
775 @param chyron
776 @details The chyron string is constructed by concatenating the labels of the
777 set keys, separated by _(" | "). The end_pos values for each key are set to
778 determine the zones for mouse clicks. When a mouse click occurs, the
779 get_chyron_key function uses the end_pos values to determine which key was
780 clicked based on the X position of the click.
781*/
782void ui_compile_chyron(UiChyron *chyron) {
783 uint end_pos = 0;
784 uint k = 0;
785 uint pos = 0;
786 UiCell cell_base = cell_nt_rev;
787 UiCell *cx;
788 char tmp_str[MAXLEN];
789 while (k < CHYRON_KEYS) {
790 if (chyron->key[k]->text[0] == '\0' || !chyron->key[k]->active) {
791 k++;
792 continue;
793 }
794 cell_base = chyron->key[k]->cell_base;
795 if (end_pos == 0) {
796 cx = chyron->cmplx_buf;
797 ui_mbstr_to_cellstr(chyron->sfc, chyron->w,
798 cx,
799 " ",
800 &cell_base,
801 &pos,
802 MAXLEN - 1);
803 } else {
804 ui_mbstr_to_cellstr(chyron->sfc, chyron->w,
805 chyron->cmplx_buf,
806 "|",
807 &cell_base,
808 &pos,
809 MAXLEN - 1);
810 }
811 cx = chyron->cmplx_buf;
812 ui_mbstr_to_cellstr(chyron->sfc, chyron->w, cx, chyron->key[k]->text, &cell_base, &pos, MAXLEN - 1);
813 end_pos = pos;
814 chyron->l = end_pos;
815 chyron->key[k]->end_pos = end_pos;
816 ssnprintf(tmp_str, MAXLEN - 1, _("k=%d, text=%s, end_pos=%d"), k,
817 chyron->key[k]->text, chyron->key[k]->end_pos);
818 k++;
819 }
820 ui_mbstr_to_cellstr(chyron->sfc, chyron->w, chyron->cmplx_buf, " ", &cell_base, &pos, MAXLEN - 1);
821 chyron->l = end_pos;
822}
823/** display_chyron
824 * @brief Display chyron on the specified line and column of the surface
825 @ingroup UiChyron
826 @param sfc Pointer to the UiSurface structure
827 @param w Window index (WIN or BOX)
828 @param chyron Pointer to the UiChyron structure
829 @param line Line number where the chyron should be displayed
830 @param col Column number where the chyron should start
831 @details This function displays the compiled chyron string on the specified
832 line and column of the given surface. It first moves the cursor to the
833 specified position, clears to the end of the line, and then writes the chyron
834 string. Finally, it moves the cursor back to the specified column for user
835 input.
836 */
837void ui_display_chyron(UiSurface *sfc, ss_t w, UiChyron *chyron, uint line, uint col) {
838 chyron->y = line;
839 ui_wmove(sfc, w, line, 0);
840 ui_wclrtoeol(sfc, w);
841 ui_wmove(sfc, w, line, 0);
842 ui_mvwadd_wchstr(sfc, w, line, 0, chyron->cmplx_buf);
843 ui_wmove(sfc, w, line, col);
844 return;
845}
846/** get_chyron_key
847 @brief Get keycode from chyron
848 @ingroup UiChyron
849 @param chyron structure
850 @param x Mouse X position
851 @return Keycode
852 @details This function uses the end_pos values set in compile_chyron
853 to determine which key was clicked.
854 The chyron functions provide xwgetch() with a mechanism to translate
855 mouse click positions into key codes based on the labels set in the chyron
856 structure. When a mouse click occurs, xwgetch() can call get_chyron_key()
857 with the X position of the click to determine which function key was clicked,
858 allowing for dynamic and customizable function key behavior in the chyron
859 area of the interface.
860*/
861int ui_get_chyron_key(UiChyron *chyron, uint x) {
862 uint i = 0;
863 uint k = -1;
864 while (i < CHYRON_KEYS - 1) {
865 if (chyron->key[i]->text[0] != '\0' && chyron->key[i]->active)
866 if (chyron->key[i]->end_pos >= x) {
867 k = i;
868 break;
869 }
870 i++;
871 }
872 return chyron->key[k]->keycode;
873}
874// -----------------------------------------------------------------------
875// Color format translations
876// -----------------------------------------------------------------------
877/** ui_rgb_to_xterm256_idx
878 @brief Convert RGB color to XTerm 256 color index
879 @ingroup color_management
880 @param rgb RGB color
881 @return XTerm 256 color index
882 @details This function converts an RGB color to the nearest XTerm 256 color
883 index. It first checks if the color is a shade of gray, and if so, it uses
884 the gray ramp. Otherwise, it calculates the nearest color in the 6x6x6 color
885 cube. */
887 if (rgb->r == rgb->g && rgb->g == rgb->b) {
888 if (rgb->r < 8)
889 return 16;
890 if (rgb->r > 248)
891 return 231;
892 return ((rgb->r - 8) / 10) + 231;
893 } else {
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;
898 }
899}
900/** ui_xterm256_idx_to_rgb
901 @brief Convert XTerm 256 color index to RGB
902 @ingroup color_management
903 @param idx XTerm 256 color index
904 @return RGB color
905 @details This function converts an XTerm 256 color index to an RGB color. It
906 first checks if the index is in the standard 16 colors, then checks if it's
907 in the 6x6x6 color cube, and finally checks if it's in the gray ramp. */
909 /** Convert XTerm 256 color index to RGB
910 @param idx - XTerm 256 color index
911 @return RGB struct */
912 RGB rgb;
913 if (idx > 255)
914 idx = 255;
915 rgb.r = rgb.g = rgb.b = 0;
916 if (idx < 16) {
917 rgb.r = std_color[idx].r;
918 rgb.g = std_color[idx].g;
919 rgb.b = std_color[idx].b;
920 } else if (idx >= 16 && idx <= 231) {
921 idx -= 16;
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;
928 }
929 return rgb;
930}
931
932/** ui_apply_gamma
933 @brief Apply gamma correction to RGB color
934 @ingroup color_management
935 @param rgb Pointer to RGB color
936 @details This function modifies the RGB color in place. It applies gamma
937 correction to the RGB color based on the gamma values set in the SIO struct.
938 If the color is a shade of gray, it applies the gray gamma correction.
939 Otherwise, it applies the individual red, green, and blue gamma corrections.
940 */
941void ui_apply_gamma(RGB *rgb) {
942 if (rgb->r == rgb->g && rgb->r == rgb->b) {
943 if (GRAY_GAMMA > 0.0f && GRAY_GAMMA != 1.0f) {
944 rgb->r = (int)(pow((rgb->r / 255.0f), 1.0f / GRAY_GAMMA) * 255.0f);
945 rgb->g = rgb->r;
946 rgb->b = rgb->r;
947 }
948 return;
949 }
950 if (rgb->r != 0 && RED_GAMMA > 0.0f && RED_GAMMA != 1.0f)
951 rgb->r = (int)(pow((rgb->r / 255.0f), 1.0f / RED_GAMMA) * 255.0f);
952 if (rgb->g != 0 && GREEN_GAMMA > 0.0f && GREEN_GAMMA != 1.0f)
953 rgb->g = (int)(pow((rgb->g / 255.0f), 1.0f / GREEN_GAMMA) * 255.0f);
954 if (rgb->b != 0 && BLUE_GAMMA > 0.0f && BLUE_GAMMA != 1.0f)
955 rgb->b = (int)(pow((rgb->b / 255.0f), 1.0f / BLUE_GAMMA) * 255.0f);
956}
957// -----------------------------------------------------------------------
958// Error Handling
959// -----------------------------------------------------------------------
960/**
961 * @defgroup error_handling Error Handling
962 @brief Display Error messages
963 */
964/** ui_answer_yn
965 @brief Accept a single letter answer
966 @ingroup error_handling
967 @param msg0 First error message line
968 @param msg1 Second error message line
969 @param msg2 Third error message line
970 @param msg3 Fourth error message line
971 @return Key code of user command */
972int ui_answer_yn(char *msg0, char *msg1, char *msg2, char *msg3) {
973 char title[MAXLEN];
974 uint line, pos, msg_l, msg0_l, msg1_l, msg2_l, msg3_l;
975
977 fprintf(stderr, _("\n\n%s\n%s\n%s\n%s\n\n"), msg0, msg1, msg2, msg3);
978 return 1;
979 }
980 uint maxy, maxx;
981 ui_get_screen_size(&maxy, &maxx);
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;
993 strnz__cpy(title, _("Notification"), MAXLEN - 1);
994 if (ui_tracked_sfc_box(5, msg_l, line, pos, title)) {
995 ssnprintf(title, MAXLEN - 1, _("ui_tracked_sfc_box(%d, %d, %d, %d, %s) failed"), 5,
996 msg_l + 2, line, pos, title);
997 ui_abend(-1, title);
998 }
999 UiSurface *sfc = ui_surface[sfc_ptr];
1000 UiChyron *chyron = ui_new_chyron(sfc, WIN);
1001 ui_set_chyron_key(chyron, 1, _("F1 Help"), UIKEY_F01);
1002 ui_set_chyron_key(chyron, 2, _("N - No"), 'n');
1003 ui_set_chyron_key(chyron, 3, _("Y - Yes"), 'y');
1004 ui_compile_chyron(chyron);
1005 UiEvent event;
1006 ui_draw_text(sfc, WIN, 0, 1, msg0);
1007 ui_draw_text(sfc, WIN, 1, 1, msg1);
1008 ui_draw_text(sfc, WIN, 2, 1, msg2);
1009 ui_draw_text(sfc, WIN, 3, 1, msg3);
1010 ui_display_chyron(sfc, WIN, chyron, 4, chyron->l + 1);
1011 do {
1013 event.y = event.x = -1;
1014 cmd_key = ui_get_event(sfc, WIN, chyron, &event, -1);
1015 if (cmd_key == UIKEY_F01 || cmd_key == 'N' || cmd_key == 'n' || cmd_key == 'Y' || cmd_key == 'y')
1016 break;
1017 } while (1);
1019 ui_destroy_chyron(chyron);
1020 return (cmd_key);
1021}
1022// -----------------------------------------------------------------------
1023// Multiplexed Input
1024// -----------------------------------------------------------------------
1025/** ui_timeout_prompt
1026 @brief Display a timeout prompt window or print to stderr
1027 @ingroup error_handling
1028 @param msg0 First message line
1029 @param msg1 Second message line
1030 @param timeout_ms Timeout in milliseconds
1031 @param timeout_secs Timeout in seconds to add if F10 is pressed
1032 @return Key code of user command */
1033int ui_timeout_prompt(char *msg0, char *msg1, uint timeout_ms, uint timeout_secs) {
1034 char title[MAXLEN];
1035 uint line, pos, msg_l, msg0_l, msg1_l;
1037 fprintf(stderr, "\n\n%s\n", msg0);
1038 fprintf(stderr, "%s\n", msg1);
1039 return 1;
1040 }
1041 uint maxy, maxx;
1042 ui_get_screen_size(&maxy, &maxx);
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);
1048
1049 pos = ((maxx - msg_l) - 4) / 2;
1050 line = (maxy - 6) / 2;
1051 strnz__cpy(title, _("Notification"), MAXLEN - 1);
1052 if (ui_tracked_sfc_box(5, msg_l, line, pos, title)) {
1053 ssnprintf(title, MAXLEN - 1, _("ui_tracked_sfc_box(%d, %d, %d, %d, %s) failed"), 5,
1054 msg_l + 2, line, pos, title);
1055 ui_abend(-1, title);
1056 }
1057 UiSurface *sfc = ui_surface[sfc_ptr];
1058 UiChyron *chyron = ui_new_chyron(sfc, WIN);
1059 ui_set_chyron_key(chyron, 1, _("F1 Help"), UIKEY_F01);
1060 ui_set_chyron_key(chyron, 9, _("F9 Cancel"), UIKEY_F09);
1061 ui_set_chyron_key(chyron, 10, _("F10 Continue"), UIKEY_F10);
1062 ui_compile_chyron(chyron);
1063 UiEvent event;
1064 ui_draw_text(sfc, WIN, 0, 1, msg0);
1065 ui_draw_text(sfc, WIN, 1, 1, msg1);
1066 ssnprintf(em3, MAXLEN - 1, _("Timeout in %d seconds"), timeout_ms / 1000);
1067 ui_draw_text(sfc, WIN, 3, 1, em3);
1068 ui_display_chyron(sfc, WIN, chyron, 4, chyron->l + 1);
1069 do {
1070 event.y = event.x = -1;
1071 cmd_key = ui_get_event(sfc, WIN, chyron, &event, 1000);
1072 if (cmd_key == UIKEY_F09 || cmd_key == 'q' || cmd_key == 'Q' || cmd_key == UIKEY_STREAM_DATA)
1073 break;
1074 if (cmd_key == UIKEY_F10)
1075 timeout_ms += timeout_secs * 1000;
1076 else
1077 timeout_ms -= 1000;
1078 ui_update_timeout_prompt(sfc, WIN, timeout_ms);
1079 } while (timeout_ms > 0);
1081 ui_destroy_chyron(chyron);
1083 return cmd_key;
1084}
1085/** ui_update_timeout_prompt
1086 @brief Update the timeout prompt with the remaining time
1087 @ingroup error_handling
1088 @param sfc Pointer to the UiSurface structure
1089 @param w Window index (WIN or BOX)
1090 @param timeout_ms Remaining timeout in milliseconds
1091 @return 0 on success, 1 if not in a curses environment
1092 @details This function updates the timeout prompt displayed on the specified
1093 surface and window with the remaining time in seconds. If not in a curses
1094 environment, it prints the timeout message to stderr.
1095 */
1096int ui_update_timeout_prompt(UiSurface *sfc, ss_t w, uint timeout_ms) {
1098 fprintf(stderr, _("Timeout in %d seconds\n"), timeout_ms / 1000);
1099 return 1;
1100 }
1101 ssnprintf(em3, MAXLEN - 1, _("%d seconds"), timeout_ms / 1000);
1102 ui_draw_text(sfc, w, 3, 12, em3);
1103 ui_wclrtoeol(sfc, w);
1105 return 0;
1106}
1107/** ui_register_read_fd
1108 @brief Register an external file descriptor for polling
1109 @ingroup error_handling
1110 @param fd File descriptor to register
1111 @param token_id Token ID associated with the file descriptor
1112 @details This function registers an external file descriptor for polling. It
1113 adds the file descriptor and its associated token ID to the list of registered
1114 external file descriptors. If the maximum number of registered file descriptors
1115 is reached, it does not register the new file descriptor.
1116 */
1117void ui_register_read_fd(int fd, int token_id) {
1118 char tmp_str[MAXLEN];
1120 ui_ctx.ext_fds[ui_ctx.ext_nfds] = (ext_fd_reg_t){fd, token_id};
1122 ssnprintf(tmp_str, MAXLEN - 1, "ui_ctx.ext_nfds = %ld", ui_ctx.ext_nfds);
1123 }
1124}
1125/** ui_unregister_read_fd
1126 @brief Unregister an external file descriptor from polling
1127 @ingroup error_handling
1128 @param fd File descriptor to unregister
1129 @details This function unregisters an external file descriptor from polling.
1130 It removes the file descriptor and its associated token ID from the list of
1131 registered external file descriptors. If the file descriptor is not found in
1132 the list, it does nothing.
1133 */
1135 for (nfds_t i = 0; i < ui_ctx.ext_nfds; i++) {
1136 if (ui_ctx.ext_fds[i].fd == fd) {
1139 break;
1140 }
1141 }
1142}
1143/** ui_poll_reg_read_fd
1144 @brief Poll for input on registered external files
1145 @ingroup error_handling
1146 @param timeout_ms Timeout in milliseconds
1147 @return Token ID of the external file that has input, or 0 if no input
1148 @details This function polls for input on registered external files. It uses
1149 the poll() system call to wait for input on the file descriptors of the
1150 registered external files. If input is available, it returns the token ID of
1151 the external file that has input. If no input is available within the
1152 specified timeout, it returns 0. If an error occurs during polling, it
1153 returns -1.
1154 */
1155int ui_poll_reg_read_fd(int timeout_ms) {
1156 if (timeout_ms <= 0)
1157 return 0;
1158 // ------------------------------------------------------------
1159 // Poll for input on registered external files
1160 // ------------------------------------------------------------
1161 int token_id = 0;
1162 int reg_idx;
1163 nfds_t nfds = 0;
1164 nfds_t ext_start_idx = ui_ctx.ext_nfds;
1165 struct pollfd fds[1 + MAX_EXT_FDS];
1166 memset(fds, 0, sizeof(fds));
1167 for (nfds_t i = 0; i < ui_ctx.ext_nfds; i++) {
1168 fds[nfds].fd = ui_ctx.ext_fds[i].fd;
1169 fds[nfds].events = POLLIN; // also POLLERR | POLLHUP | POLLNVAL
1170 nfds++;
1171 }
1172 int poll_rc = poll(fds, nfds, timeout_ms);
1173 if (poll_rc < 0) {
1174 if (errno == EINTR)
1175 return 0;
1176 return -1;
1177 }
1178 if (poll_rc == 0)
1179 return 0;
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;
1183 token_id = ui_ctx.ext_fds[reg_idx].token_id;
1184 return token_id;
1185 }
1186 }
1187 return 0;
1188}
1189// -----------------------------------------------------------------------
1190// Error handling
1191// -----------------------------------------------------------------------
1192/** ui_display_error
1193 @brief Display an error message window or print to stderr
1194 @ingroup error_handling
1195 @param msg0 First error message line
1196 @param msg1 Second error message line
1197 @param msg2 Third error message line
1198 @param msg3 Fourth error message line
1199 @return Key code of user command */
1200int ui_display_error(char *msg0, char *msg1, char *msg2, char *msg3) {
1201 char title[MAXLEN];
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);
1208 return 1;
1209 }
1210 uint maxy, maxx;
1211 ui_get_screen_size(&maxy, &maxx);
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);
1221
1222 pos = ((maxx - msg_l) - 4) / 2;
1223 line = (maxy - 6) / 2;
1224 strnz__cpy(title, _("Notification"), MAXLEN - 1);
1225 if (ui_tracked_sfc_box(5, msg_l, line, pos, title)) {
1226 ssnprintf(title, MAXLEN - 1, _("ui_tracked_sfc_box(%d, %d, %d, %d, %s) failed"), 5,
1227 msg_l + 2, line, pos, title);
1228 ui_abend(-1, title);
1229 }
1230 UiSurface *sfc = ui_surface[sfc_ptr];
1231 UiChyron *chyron = ui_new_chyron(sfc, WIN);
1232 ui_set_chyron_key(chyron, 1, _("F1 Help"), UIKEY_F01);
1233 ui_set_chyron_key(chyron, 9, _("F9 Cancel"), UIKEY_F09);
1234 ui_set_chyron_key(chyron, 10, _("F10 Continue"), UIKEY_F10);
1235 ui_compile_chyron(chyron);
1236 UiEvent event;
1237 ui_draw_text(sfc, WIN, 0, 1, msg0);
1238 ui_draw_text(sfc, WIN, 1, 1, msg1);
1239 ui_draw_text(sfc, WIN, 2, 1, msg2);
1240 ui_draw_text(sfc, WIN, 3, 1, msg3);
1241 ui_display_chyron(sfc, WIN, chyron, 4, chyron->l + 1);
1242 do {
1243 event.y = event.x = -1;
1244 cmd_key = ui_get_event(sfc, WIN, chyron, &event, -1);
1245 if (cmd_key == UIKEY_F09 || cmd_key == UIKEY_F10 || cmd_key == 'q' || cmd_key == 'Q')
1246 break;
1247 } while (1);
1249 ui_destroy_chyron(chyron);
1250 return (cmd_key);
1251}
1252/** ui_perror
1253 @brief Display a simple error message window or print to stderr
1254 @ingroup error_handling
1255 @param emsg_str Error message string
1256 @return Key code of user command */
1257int ui_perror(char *emsg_str) {
1258 char emsg[MAXLEN];
1259 unsigned in_key;
1260 uint line, pos, cols;
1261 char title[MAXLEN];
1262 char tmp_str[MAXLEN];
1263 bool f_xwgetch = true;
1264 if (emsg_str[0] == '␛' && emsg_str[1] == 'w') {
1265 emsg_str += 2;
1266 f_xwgetch = false;
1267 }
1268 strnz__cpy(emsg, emsg_str, 79);
1270 fprintf(stderr, "\n%s\n", emsg);
1271 return 1;
1272 }
1273 uint maxy, maxx;
1274 ui_get_screen_size(&maxy, &maxx);
1275 cols = strnz(emsg, maxx - 4);
1276 cols = max(cols, 50);
1277 pos = (maxx - cols - 4) / 2;
1278 line = (maxy - 4) / 2;
1279 strnz__cpy(title, _("Notification"), MAXLEN - 1);
1280 if (ui_tracked_sfc_box(2, cols, line, pos, title)) {
1281 ssnprintf(tmp_str, MAXLEN - 1, _("ui_tracked_sfc_box(%d, %d, %d, %d, %s, %b) failed"),
1282 4, line, line, pos, title);
1283 ui_log(ERROR, "%s", tmp_str);
1284 exit(EXIT_FAILURE);
1285 }
1286 UiSurface *sfc = ui_surface[sfc_ptr];
1287 UiChyron *chyron = ui_new_chyron(sfc, WIN);
1288 ui_set_chyron_key(chyron, 1, _("F1 Help"), UIKEY_F01);
1289 ui_set_chyron_key(chyron, 9, _("F9 Cancel"), UIKEY_F09);
1290 ui_set_chyron_key(chyron, 10, _("F10 Continue"), UIKEY_F10);
1291 ui_compile_chyron(chyron);
1292 UiEvent event;
1293 ui_draw_text(sfc, WIN, 0, 1, emsg_str);
1294 ui_display_chyron(sfc, WIN, chyron, 1, chyron->l + 1);
1295 if (f_xwgetch) {
1296 event.y = event.x = -1;
1297 in_key = ui_get_event(sfc, WIN, chyron, &event, -1);
1298 } else {
1299 in_key = UIKEY_F10;
1300 }
1301 ui_destroy_chyron(chyron);
1303 return (in_key);
1304}
1305/** ui_action_disposition
1306 @brief Display a simple action disposition message window or print to stderr
1307 @ingroup error_handling
1308 @param title Window title
1309 @param action_str Action description string
1310 @return true if successful */
1311bool ui_action_disposition(char *title, char *action_str) {
1312 uint len;
1313 uint line, col;
1314
1316 fprintf(stderr, "\n%s\n", title);
1317 fprintf(stderr, "%s\n", action_str);
1318 return true;
1319 }
1320 len = max(strlen(title), strlen(action_str));
1321 uint maxy, maxx;
1322 ui_get_screen_size(&maxy, &maxx);
1323 col = (maxx - len - 4) / 2;
1324 line = (maxy - 4) / 2;
1325 if (ui_tracked_sfc_box(2, len, line, col, title)) {
1326 ssnprintf(em0, MAXLEN - 1, _("ui_tracked_sfc_box(%d, %d, %d, %d, %s) failed"), 4,
1327 line, line, col, title);
1329 }
1330 UiSurface *sfc = ui_surface[sfc_ptr];
1331 UiChyron *chyron = ui_new_chyron(sfc, WIN);
1332 ui_set_chyron_key(chyron, 10, _("F10 Continue"), UIKEY_F10);
1333 ui_compile_chyron(chyron);
1334 UiEvent event;
1335 ui_draw_text(sfc, WIN, 0, 1, action_str);
1336 ui_display_chyron(sfc, WIN, chyron, 1, 0);
1337 event.y = event.x = -1;
1338 cmd_key = ui_get_event(sfc, WIN, chyron, &event, -1);
1340 ui_destroy_chyron(chyron);
1341 return true;
1342}
1343// -----------------------------------------------------------------------
1344// Logging
1345// -----------------------------------------------------------------------
1346/** ui_iso8601_timestamp
1347 @brief Generate an ISO 8601 timestamp string
1348 @ingroup logging
1349 @param buf Buffer to store the timestamp string
1350 @param n Size of the buffer
1351 @param local If true, use local time; if false, use UTC
1352 @return Pointer to the buffer containing the timestamp string */
1353char *ui_iso8601_timestamp(char *buf, size_t n, bool local) {
1354 if (buf == NULL)
1355 return NULL;
1356 time_t t = time(NULL);
1357 struct tm *tp = local ? localtime(&t) : gmtime(&t);
1358 if (local) {
1359 strftime(buf, n, _("%Y-%m-%dT%H:%M:%S%z"), tp);
1360 } else {
1361 strftime(buf, n, _("%Y-%m-%dT%H:%M:%SZ"), tp);
1362 }
1363 return buf;
1364}
1365#define AS_STRING(NAME) #NAME,
1366const char *subsfc_s[] = {
1367 SUB_SURFACE_LIST(AS_STRING)};
1368const char *ui_sub_surface_str(ss_t w) {
1369 if (w < BOX || w >= SUB_SFC_MAX)
1370 return _("unknown");
1371 return subsfc_s[w];
1372}
1373#define AS_STRING(NAME) #NAME,
1374const char *const ui_log_level_s[] = {
1375 LOG_LEVEL_LIST(AS_STRING)};
1376// ANSI Color Strings for UiLog
1377const char *const ui_logcolor[] = {
1378 [FATAL] = "\033[1;31m", // Bold Red
1379 [ERROR] = "\033[0;31m", // Regular Red
1380 [WARN] = "\033[0;33m", // Yellow
1381 [INFO] = "\033[0;32m", // Green
1382 [VERBOSE] = "\033[0;36m", // Cyan
1383 [DEBUG] = "\033[0;34m", // Blue
1384 [SILENT] = _("SILENT"),
1385};
1386
1387FILE *ui_log_fp = NULL;
1388char ui_log_file_name[MAXLEN] = "/tmp/ui.log"; // default log file
1389const char *const ui_logcolor[];
1390UiLogLevel ui_min_log_level = INFO;
1391bool ui_timestamp_local = true; // default to local time for timestamps
1393/** ui_open_log
1394 @brief Open the log file for writing
1395 @ingroup logging
1396 @return FILE pointer to the opened log file */
1398 if (!ui_log_fp) {
1399 if (strlen(ui_log_file_name) == 0)
1400 strnz__cpy(ui_log_file_name, "/tmp/ui_default.log", MAXLEN - 1);
1401 ui_log_fp = fopen(ui_log_file_name, "w");
1402 if (!ui_log_fp) {
1403 ssnprintf(em0, MAXLEN - 1, _("Failed to open log file: %s"), ui_log_file_name);
1404 ssnprintf(em1, MAXLEN - 1, _("Error: %s"), strerror(errno));
1405 ssnprintf(em2, MAXLEN - 1, "%s: line: %d", __FILE__, __LINE__ - 4);
1406 ssnprintf(em3, MAXLEN - 1, _("remedy: delete %s and try again"), ui_log_file_name);
1407 fprintf(stderr, "%s\n%s\n%s\n%s\n", em0, em1, em2, em3);
1408 exit(EXIT_FAILURE);
1409 }
1410 setvbuf(ui_log_fp, NULL, _IOLBF, BUFSIZ);
1411 }
1412 char ttyname[MAXLEN];
1413 char cmenu_user[MAXLEN];
1414 char *p = getenv(_("USER"));
1415 strnz__cpy(cmenu_user, p, MAXLEN - 1);
1416 if (ttyname_r(STDERR_FILENO, ttyname, sizeof(ttyname)) == 0)
1417 strnz__cpy(em0, ttyname, MAXLEN - 1);
1418 ssnprintf(em0, MAXLEN - 1, _("Ui_Log started by user '%s' on terminal '%s'"), cmenu_user, ttyname);
1419 ui_log(INFO, "%s:", em0);
1420 return ui_log_fp;
1421}
1422/* -------------------------------------------------------------------------
1423 Formatting
1424 ------------------------------------------------------------------------- */
1425/** parse_ansi
1426 @brief Parse ANSI escape sequences for color and attributes
1427 @ingroup formatting
1428 @param ansi_str ANSI escape sequence string
1429 @param attr Pointer to attribute variable to be updated
1430 @param cpx Pointer to color pair index to be updated
1431 @details This function parses an ANSI escape sequence string (e.g., _("\033[31;1m"))
1432 and updates the provided attribute and color pair index accordingly. It handles
1433 standard colors, extended colors, and text attributes like bold, underline, etc.
1434 */
1435void ui_parse_ansi(char *ansi_str, attr_t *attr, uint *cpx) {
1436 char *tok;
1437 char t0, t1;
1438 char tstr[3];
1439 uint len, x_idx;
1440 uint fg, bg;
1441 uint _fg_clr, _bg_clr;
1442 uint fg_clr, bg_clr;
1443 char *ansi_p = ansi_str + 2;
1444 ui_pair_content(*cpx, &_fg_clr, &_bg_clr);
1445 fg = fg_clr = (uint)_fg_clr;
1446 bg = bg_clr = (uint)_bg_clr;
1447 RGB rgb;
1448 tok = strtok((char *)ansi_p, ";m");
1449 bool a_toi_error = false;
1450 while (1) {
1451 if (tok == nullptr || *tok == '\0')
1452 break;
1453 len = strlen(tok);
1454 if (len == 2) {
1455 t0 = tok[0];
1456 t1 = tok[1];
1457 if (t0 == '3' || t0 == '4') {
1458 if (t1 == '8') {
1459 tok = strtok(nullptr, ";m");
1460 if (tok != nullptr) {
1461 if (*tok == '5') {
1462 tok = strtok(nullptr, ";m");
1463 if (tok != nullptr) {
1464 x_idx = a_toi(tok, &a_toi_error);
1465 rgb = ui_xterm256_idx_to_rgb(x_idx);
1466 }
1467 } else if (*tok == '2') {
1468 tok = strtok(nullptr, ";m");
1469 rgb.r = a_toi(tok, &a_toi_error);
1470 tok = strtok(nullptr, ";m");
1471 rgb.g = a_toi(tok, &a_toi_error);
1472 tok = strtok(nullptr, ";m");
1473 rgb.b = a_toi(tok, &a_toi_error);
1474 }
1475 }
1476 if (t0 == '3')
1477 fg_clr = ui_color_from_rgb(&rgb);
1478 else if (t0 == '4')
1479 bg_clr = ui_color_from_rgb(&rgb);
1480 } else if (t1 == '9') {
1481 if (t0 == '3')
1482 fg_clr = CLR_NT_FG;
1483 else if (t0 == '4')
1484 bg_clr = CLR_NT_BG;
1485 } else if (t1 >= '0' && t1 <= '7') {
1486 if (t0 == '3') {
1487 tstr[0] = t1;
1488 tstr[1] = '\0';
1489 x_idx = a_toi(tstr, &a_toi_error);
1490 rgb = ui_xterm256_idx_to_rgb(x_idx);
1491 fg_clr = ui_color_from_rgb(&rgb);
1492 } else if (t0 == '4') {
1493 tstr[0] = t1;
1494 tstr[1] = '\0';
1495 x_idx = a_toi(tstr, &a_toi_error);
1496 rgb = ui_xterm256_idx_to_rgb(x_idx);
1497 bg_clr = ui_color_from_rgb(&rgb);
1498 }
1499 }
1500 } else if (t0 == '0') {
1501 *tok = t1;
1502 len = 1;
1503 }
1504 }
1505 if (len == 1) {
1506 if (*tok == '0') {
1507 *attr = WA_NORMAL;
1508 fg_clr = CLR_NT_FG;
1509 bg_clr = CLR_NT_BG;
1510 } else {
1511 switch (a_toi(tok, &a_toi_error)) {
1512 case 1:
1513 *attr |= WA_BOLD;
1514 break;
1515 case 2:
1516 *attr |= WA_DIM;
1517 break;
1518 case 3:
1519 *attr |= WA_ITALIC;
1520 break;
1521 case 4:
1522 *attr |= WA_UNDERLINE;
1523 break;
1524 case 5:
1525 *attr |= WA_BLINK;
1526 break;
1527 case 7:
1528 *attr |= WA_REVERSE;
1529 break;
1530 case 8:
1531 *attr |= WA_INVIS;
1532 break;
1533 default:
1534 break;
1535 }
1536 }
1537 } else if (len == 0) {
1538 *attr = WA_NORMAL;
1539 fg_clr = CLR_NT_FG;
1540 bg_clr = CLR_NT_BG;
1541 }
1542 tok = strtok(nullptr, ";m");
1543 }
1544 if (!a_toi_error && (fg_clr != fg || bg_clr != bg))
1545 *cpx = ui_add_pair(fg_clr, bg_clr);
1546 return;
1547}
int stdout_fd
Definition ui_common.c:61
char fn[MAXLEN]
Definition ui_common.c:45
uint src_line
Definition ui_common.c:43
int exit_code
Definition ui_common.c:31
#define min(x, y)
min macro evaluates two expressions, returning least result
Definition cm.h:104
uint16_t win_attr
Definition ui_common.c:34
int stdin_fd
Definition ui_common.c:61
char * src_name
Definition ui_common.c:44
int stderr_fd
Definition ui_common.c:61
#define max(a, b)
max macro evaluates two expressions, returning greatest result.
Definition cm.h:97
int ui_border_draw(UiSurface *sfc)
Definition ui_common.c:474
#define bw_ho
Definition ui_backend.h:581
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.
Definition ui_ncurses.c:395
const wchar_t * border_none
Definition ui_common.c:72
const wchar_t * bw_sp
Definition ui_common.c:79
#define SUB_SURFACE_LIST(X)
Definition ui_backend.h:36
UiCell cell_sp
Definition ui_common.c:132
void ui_render()
Render the UI by updating panels and refreshing the display.
Definition ui_ncurses.c:884
UiCell cell_ve
Definition ui_common.c:124
ushort cp_nt
Definition ui_common.c:142
UiCell cell_tr
Definition ui_common.c:122
UiCell cell_nt
Definition ui_common.c:106
char const colors_text[][10]
Color names for .minitrc overrides.
Definition ui_common.c:93
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.
Definition ui_common.c:425
const wchar_t * bw_ran
Definition ui_common.c:84
UiCell cell_ls
Definition ui_common.c:117
UiCell cell_nt_hl_rev
Definition ui_common.c:109
bool f_ncurses_open
Definition ui_common.c:50
char em1[MAXLEN]
Definition ui_common.c:47
UiCell cell_bt
Definition ui_common.c:130
UiCell cell_br
Definition ui_common.c:126
const wchar_t * bw_rbr
Definition ui_common.c:78
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
ushort cp_green
Definition ui_common.c:151
const wchar_t * bw_ua
Definition ui_common.c:82
UiCell cell_tl
Definition ui_common.c:121
ushort cp_red
Definition ui_common.c:150
int ui_wmove(UiSurface *s, ss_t w, uint y, uint x)
Move the cursor to a specified position within a UiSurface.
Definition ui_ncurses.c:653
ushort cp_box
Definition ui_common.c:138
char em2[MAXLEN]
Definition ui_common.c:48
#define MAX_EXT_FDS
Definition ui_backend.h:131
ushort cp_blue
Definition ui_common.c:153
UiCell cell_ln
Definition ui_common.c:114
#define bw_tr
Definition ui_backend.h:589
ui_context_t ui_ctx
Definition ui_common.c:59
const char * ui_sub_surface_str(ss_t w)
Definition ui_common.c:1368
const wchar_t * bw_chk
Definition ui_common.c:86
BorderWide bw
Definition ui_common.c:27
#define CHYRON_KEYS
Definition ui_backend.h:50
UiCell cell_ts
Definition ui_common.c:119
const wchar_t * bw_rtl
Definition ui_common.c:75
ushort cp_nt_hl
Definition ui_common.c:144
int ui_cm_surface_destroy(UiSurface *sfc)
Destroy the most recently created surface.
Definition ui_common.c:466
const wchar_t * bw_rtr
Definition ui_common.c:76
#define bw_lt
Definition ui_backend.h:583
const wchar_t * bw_lan
Definition ui_common.c:85
ushort cp_fill_char
Definition ui_common.c:148
UiCell cell_tt
Definition ui_common.c:129
void ui_surface_destroy(UiSurface *s)
Destroy a UiSurface, cleaning up its windows and panels.
Definition ui_ncurses.c:468
UiCell cell_bs
Definition ui_common.c:120
@ SUB_SFC_MAX
Definition ui_backend.h:47
ushort cp_brackets
Definition ui_common.c:149
#define bw_br
Definition ui_backend.h:591
const wchar_t * bw_ra
Definition ui_common.c:80
int ui_border_title(UiSurface *sfc, const char *title)
Draw a box with a title around the specified window.
Definition ui_common.c:563
ushort cp_yellow
Definition ui_common.c:152
UiCell cell_ho
Definition ui_common.c:123
const wchar_t * border_double
Definition ui_common.c:69
UiCell cell_rs
Definition ui_common.c:118
int ui_getmaxy(UiSurface *s, ss_t w)
Get the maximum number of lines (rows) of a UiSurface.
Definition ui_ncurses.c:701
#define bw_bl
Definition ui_backend.h:590
const wchar_t * bw_h09
Definition ui_common.c:87
UiCell cell_default
Definition ui_common.c:102
int click_x
Definition ui_common.c:30
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.
Definition ui_ncurses.c:288
#define CHYRON_KEY_MAXLEN
Definition ui_backend.h:49
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.
Definition ui_common.c:524
const wchar_t * border_single
Definition ui_common.c:68
void ui_get_screen_size(uint *lines, uint *cols)
Get the current screen size (number of lines and columns).
Definition ui_ncurses.c:722
ushort cp_nt_hl_rev
Definition ui_common.c:145
ushort cp_default
Definition ui_common.c:147
void ui_shutdown()
Shutdown the UI runtime, cleaning up resources and freeing memory.
Definition ui_ncurses.c:418
UiCell cell_nt_hl
Definition ui_common.c:108
ushort cp_nt_rev
Definition ui_common.c:143
char em3[MAXLEN]
Definition ui_common.c:49
ushort cp_title
Definition ui_common.c:141
int ui_border_ysplit(UiSurface *sfc, uint y)
Draw a box with a separator line around the specified window.
Definition ui_common.c:504
UiCell cell_lt
Definition ui_common.c:127
#define LOG_LEVEL_LIST(X)
Definition ui_backend.h:69
void ui_initialize_sio(SIO *sio)
Definition ui_common.c:182
@ CLR_CMDLN_BG
Definition ui_backend.h:536
@ CLR_FILL_CHAR_BG
Definition ui_backend.h:532
@ CLR_BOX_BG
Definition ui_backend.h:526
@ CLR_FILL_CHAR_FG
Definition ui_backend.h:531
@ CLR_FG
Definition ui_backend.h:523
@ CLR_RED
Definition ui_backend.h:507
@ CLR_NT_FG
Definition ui_backend.h:537
@ CLR_BRACKETS_FG
Definition ui_backend.h:529
@ CLR_YELLOW
Definition ui_backend.h:509
@ CLR_IND_FG
Definition ui_backend.h:527
@ CLR_BCYAN
Definition ui_backend.h:520
@ CLR_TITLE_FG
Definition ui_backend.h:545
@ CLR_WHITE
Definition ui_backend.h:513
@ CLR_MAGENTA
Definition ui_backend.h:511
@ CLR_BRACKETS_BG
Definition ui_backend.h:530
@ CLR_NT_REV_BG
Definition ui_backend.h:540
@ CLR_BLACK
Definition ui_backend.h:506
@ CLR_BWHITE
Definition ui_backend.h:521
@ CLR_LN_BG
Definition ui_backend.h:534
@ CLR_NT_HL_REV_BG
Definition ui_backend.h:544
@ CLR_BBLACK
Definition ui_backend.h:514
@ CLR_LN_FG
Definition ui_backend.h:533
@ CLR_NT_HL_FG
Definition ui_backend.h:541
@ CLR_BBLUE
Definition ui_backend.h:518
@ CLR_BGREEN
Definition ui_backend.h:516
@ CLR_BYELLOW
Definition ui_backend.h:517
@ CLR_BMAGENTA
Definition ui_backend.h:519
@ CLR_BORANGE
Definition ui_backend.h:522
@ CLR_NT_HL_BG
Definition ui_backend.h:542
@ CLR_NT_HL_REV_FG
Definition ui_backend.h:543
@ CLR_BG
Definition ui_backend.h:524
@ CLR_BOX_FG
Definition ui_backend.h:525
@ CLR_NT_BG
Definition ui_backend.h:538
@ CLR_TITLE_BG
Definition ui_backend.h:546
@ CLR_BRED
Definition ui_backend.h:515
@ CLR_NCOLORS
Definition ui_backend.h:547
@ CLR_BLUE
Definition ui_backend.h:510
@ CLR_IND_BG
Definition ui_backend.h:528
@ CLR_GREEN
Definition ui_backend.h:508
@ CLR_CMDLN_FG
Definition ui_backend.h:535
@ CLR_NT_REV_FG
Definition ui_backend.h:539
@ CLR_CYAN
Definition ui_backend.h:512
int sfc_ptr
Definition ui_ncurses.c:42
int ui_curs_set(int visibility)
Set the visibility of the cursor.
Definition ui_ncurses.c:840
UiCell cell_brktl
Definition ui_common.c:104
#define bw_tt
Definition ui_backend.h:585
UiCell cell_cr
Definition ui_common.c:131
UiCell cell_title
Definition ui_common.c:113
int click_y
Definition ui_common.c:29
#define bw_cr
Definition ui_backend.h:587
const wchar_t * bw_la
Definition ui_common.c:81
char em0[MAXLEN]
Definition ui_common.c:46
UiCell cell_ind
Definition ui_common.c:111
int ui_tracked_sfc_box(uint wlines, uint wcols, uint wbegy, uint wbegx, const char *wtitle)
Create a new surface with a box window.
Definition ui_common.c:387
UiCell cell_ran
Definition ui_common.c:115
#define bw_bt
Definition ui_backend.h:586
int ui_getmaxx(UiSurface *s, ss_t w)
Get the maximum number of columns of a UiSurface.
Definition ui_ncurses.c:712
#define bw_ve
Definition ui_backend.h:582
const wchar_t * border_heavy
Definition ui_common.c:71
bool f_notcurses_open
Definition ui_common.c:51
const wchar_t * border_rounded
Definition ui_common.c:70
UiCell cell_cmdln
Definition ui_common.c:112
int ui_wclrtoeol(UiSurface *s, ss_t w)
Clear to the end of the line in a surface window.
const wchar_t * bw_da
Definition ui_common.c:83
#define bw_rt
Definition ui_backend.h:584
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.
Definition ui_ncurses.c:941
UiCell cell_brktr
Definition ui_common.c:105
ushort cp_ind
Definition ui_common.c:139
UiCell cell_fill_char
Definition ui_common.c:103
UiCell cell_box
Definition ui_common.c:110
UiCell cell_rt
Definition ui_common.c:128
#define SFC_MAX
Definition ui_backend.h:197
const wchar_t * bw_rbl
Definition ui_common.c:77
UiCell cell_bl
Definition ui_common.c:125
UiCell cell_chk
Definition ui_common.c:116
UiCell cell_nt_rev
Definition ui_common.c:107
#define bw_tl
Definition ui_backend.h:588
#define BUFSIZ
Definition view.h:38
#define UIKEY_STREAM_DATA
#define UIKEY_F09
#define UIKEY_F01
#define UIKEY_F10
#define WA_NORMAL
#define WA_BLINK
#define WA_ITALIC
#define WA_DIM
#define WA_INVIS
#define WA_BOLD
#define WA_REVERSE
#define WA_UNDERLINE
int ui_get_event(UiSurface *s, ss_t w, UiChyron *chyron, UiEvent *ev, int timeout_ms)
Read input events.
uint16_t box_attr
Definition ui_common.c:35
unsigned int cmd_key
Definition ui_common.c:32
void ui_unset_chyron_key(UiChyron *chyron, uint k)
Unset chyron key.
Definition ui_common.c:732
uint m_begx
Definition ui_common.c:39
void ui_set_chyron_key(UiChyron *chyron, uint k, char *s, uint kc)
Set chyron key with default color pair (cp_nt_rev).
Definition ui_common.c:717
bool ui_timestamp_local
Definition ui_common.c:1391
void ui_deactivate_all_chyron_keys(UiChyron *chyron)
Deactivate all chyron keys.
Definition ui_common.c:768
int pipe_in
Definition ui_common.c:61
bool f_sigwench
Definition ui_common.c:33
char ui_log_file_name[MAXLEN]
Definition ui_common.c:1388
int tty_fd
Definition ui_common.c:61
FILE * ui_open_log()
Open the log file for writing.
Definition ui_common.c:1397
wchar_t * ui_mbstr_to_wcstr(const char *mb_str)
Convert a multibyte string to a wide character string.
Definition ui_common.c:322
UiChyron * ui_new_chyron(UiSurface *sfc, ss_t w)
Create new chyron structure.
Definition ui_common.c:601
uint m_lines
Definition ui_common.c:36
char * ui_iso8601_timestamp(char *buf, size_t n, bool local)
Generate an ISO 8601 timestamp string.
Definition ui_common.c:1353
const char *const ui_log_level_s[]
Definition ui_common.c:1374
RGB ui_xterm256_idx_to_rgb(uint idx)
Convert XTerm 256 color index to RGB.
Definition ui_common.c:908
double BLUE_GAMMA
Definition ui_common.c:65
void ui_activate_chyron_key(UiChyron *chyron, uint k)
Activate chyron key.
Definition ui_common.c:741
ushort cp_cmdln
Definition ui_common.c:140
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.
Definition ui_common.c:837
STDRGB std_color[]
Definition ui_common.c:159
uint mouse_support
Definition ui_common.c:40
void ui_set_chyron_key_cb(UiChyron *chyron, uint k, char *s, uint kc, UiCell cell_base)
Set chyron key with color pair (cp).
Definition ui_common.c:693
int ui_assign_chyron_win(UiChyron *chyron, UiSurface *sfc, ss_t w, char *y)
Assign surface and window to chyron structure.
Definition ui_common.c:634
bool ui_init_clr_palette(SIO *sio)
Definition ui_common.c:247
uint m_cols
Definition ui_common.c:37
bool ui_is_set_chyron_key(UiChyron *chyron, uint k)
Check if function key label is set.
Definition ui_common.c:677
UiLogLevel ui_min_log_level
Definition ui_common.c:1390
ushort cp_ln
Definition ui_common.c:146
void ui_abend(int ec, char *s)
Convert multibyte string to complex character array.
Definition ui_common.c:362
const char * subsfc_s[]
Definition ui_common.c:1366
void ui_parse_ansi(char *ansi_str, attr_t *attr, uint *cpx)
Parse ANSI escape sequences for color and attributes.
Definition ui_common.c:1435
UiChyron * ui_destroy_chyron(UiChyron *chyron)
Destroy UiChyron structure.
Definition ui_common.c:656
uint m_begy
Definition ui_common.c:38
int ui_get_chyron_key(UiChyron *chyron, uint x)
Get keycode from chyron.
Definition ui_common.c:861
double GRAY_GAMMA
Definition ui_common.c:62
void ui_mbc_to_wc(wchar_t wc[2], const char mbc)
Convert a multibyte character to a wide character.
Definition ui_common.c:302
double RED_GAMMA
Definition ui_common.c:63
void ui_deactivate_chyron_key(UiChyron *chyron, uint k)
Deactivate chyron key.
Definition ui_common.c:760
const char *const ui_logcolor[]
Definition ui_common.c:1377
void ui_apply_gamma(RGB *rgb)
Apply gamma correction to RGB color.
Definition ui_common.c:941
void ui_activate_all_chyron_keys(UiChyron *chyron)
Deactivate chyron key.
Definition ui_common.c:750
char ui_timestamp[32]
Definition ui_common.c:1392
uint ui_rgb_to_xterm256_idx(RGB *rgb)
Convert RGB color to XTerm 256 color index.
Definition ui_common.c:886
int pipe_out
Definition ui_common.c:61
double GREEN_GAMMA
Definition ui_common.c:64
void ui_compile_chyron(UiChyron *chyron)
construct the chyron string from the chyron structure
Definition ui_common.c:782
FILE * ui_log_fp
Definition ui_common.c:1387
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]
Definition ui_ncurses.c:40
UiRuntime * ui
Definition ui_ncurses.c:39
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.
Definition ui_ncurses.c:101
uint ui_color_cnt
Definition ui_ncurses.c:43
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.
#define MAXLEN
Definition curskeys.c:15
#define _(String)
Definition amort.c:23
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition whence.c:291
size_t strnz(char *, size_t)
terminates string at New Line, Carriage Return, or max_len
Definition futil.c:599
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:390
int a_toi(char *, bool *)
a safer alternative to atoi() for converting ASCII strings to integers.
Definition futil.c:784
bool restore_shell_tioctl()
restore_shell_tioctl() - restore shell terminal settings
Definition scriou.c:57
void sig_dfl_mode()
Set signal handlers to default behavior.
Definition sig.c:41
int ui_perror(char *emsg_str)
Display a simple error message window or print to stderr.
Definition ui_common.c:1257
void ui_unregister_read_fd(int fd)
Unregister an external file descriptor from polling.
Definition ui_common.c:1134
void ui_register_read_fd(int fd, int token_id)
Register an external file descriptor for polling.
Definition ui_common.c:1117
int ui_timeout_prompt(char *msg0, char *msg1, uint timeout_ms, uint timeout_secs)
Display a timeout prompt window or print to stderr.
Definition ui_common.c:1033
int ui_update_timeout_prompt(UiSurface *sfc, ss_t w, uint timeout_ms)
Update the timeout prompt with the remaining time.
Definition ui_common.c:1096
int ui_poll_reg_read_fd(int timeout_ms)
Poll for input on registered external files.
Definition ui_common.c:1155
bool ui_action_disposition(char *title, char *action_str)
Display a simple action disposition message window or print to stderr.
Definition ui_common.c:1311
int ui_answer_yn(char *msg0, char *msg1, char *msg2, char *msg3)
Accept a single letter answer.
Definition ui_common.c:972
int ui_display_error(char *msg0, char *msg1, char *msg2, char *msg3)
Display an error message window or print to stderr.
Definition ui_common.c:1200
nfds_t ext_nfds
Definition ui_backend.h:144
ext_fd_reg_t ext_fds[MAX_EXT_FDS]
Definition ui_backend.h:143
uint32_t ran_bg
Definition ui_backend.h:740
double green_gamma
Definition ui_backend.h:693
uint32_t ln_bg
Definition ui_backend.h:726
double blue_gamma
Definition ui_backend.h:694
char brackets[3]
Definition ui_backend.h:753
uint32_t magenta
Definition ui_backend.h:701
uint32_t cmdln_bg
Definition ui_backend.h:728
uint32_t cmdln_fg
Definition ui_backend.h:727
uint32_t nt_hl_rev_fg
Definition ui_backend.h:735
uint32_t ran_fg
Definition ui_backend.h:739
uint32_t bgreen
Definition ui_backend.h:707
double red_gamma
Definition ui_backend.h:692
uint32_t green
Definition ui_backend.h:698
uint32_t nt_fg
Definition ui_backend.h:729
uint32_t yellow
Definition ui_backend.h:699
uint32_t fill_char_fg
Definition ui_backend.h:723
uint32_t box_fg
Definition ui_backend.h:717
uint32_t ln_fg
Definition ui_backend.h:725
uint32_t ind_bg
Definition ui_backend.h:720
uint32_t bmagenta
Definition ui_backend.h:710
uint32_t ind_fg
Definition ui_backend.h:719
uint32_t byellow
Definition ui_backend.h:708
uint32_t bblue
Definition ui_backend.h:709
uint32_t borange
Definition ui_backend.h:713
uint32_t title_bg
Definition ui_backend.h:738
uint32_t fg
Definition ui_backend.h:715
uint32_t cyan
Definition ui_backend.h:702
uint32_t bblack
Definition ui_backend.h:705
uint32_t red
Definition ui_backend.h:697
uint32_t nt_hl_rev_bg
Definition ui_backend.h:736
uint32_t title_fg
Definition ui_backend.h:737
uint32_t bred
Definition ui_backend.h:706
uint32_t fill_char_bg
Definition ui_backend.h:724
uint32_t black
Definition ui_backend.h:696
uint32_t nt_rev_bg
Definition ui_backend.h:732
uint32_t brackets_bg
Definition ui_backend.h:722
uint32_t bcyan
Definition ui_backend.h:711
uint32_t nt_bg
Definition ui_backend.h:730
uint32_t blue
Definition ui_backend.h:700
uint32_t brackets_fg
Definition ui_backend.h:721
uint32_t white
Definition ui_backend.h:703
uint32_t box_bg
Definition ui_backend.h:718
uint32_t nt_hl_fg
Definition ui_backend.h:733
uint32_t bwhite
Definition ui_backend.h:712
uint32_t nt_rev_fg
Definition ui_backend.h:731
double gray_gamma
Definition ui_backend.h:695
uint32_t nt_hl_bg
Definition ui_backend.h:734
uint32_t bg
Definition ui_backend.h:716