C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
dwin.c
Go to the documentation of this file.
1/** @file dwin.c
2 @brief Window support for C-Menu - EXPERIMENTAL
3 @details This file contains functions for managing NCurses windows and color
4 settings for the Chyron structure for function key labels and mouse click
5 handling. This file is a work in progress and may be subject to change as the
6 C-Menu project evolves. Generally, don't try to use it yet unless you want
7 complete the half-done code modifications.
8 @author Bill Waller
9 Copyright (c) 2025
10 MIT License
11 billxwaller@gmail.com
12 @date 2026-02-09
13 */
14
15/** @defgroup window_support Window Support
16 @brief Manage NCurses windows and color settings
17 */
18
19#include <cm.h>
20#include <errno.h>
21#include <math.h>
22#include <stdbool.h>
23#include <stdlib.h>
24#include <string.h>
25#include <termios.h>
26#include <unistd.h>
27#include <wait.h>
28#include <wchar.h>
29#define NC true
30
31bool open_curses(SIO *);
32bool init_clr_palette(SIO *);
33void destroy_curses();
34int box_new(int, int, int, int, char *, bool);
35int box2_new(int, int, int, int, char *, bool);
36void cbox(WINDOW *);
37void cbox2(WINDOW *);
38int win_new(int, int, int, int);
39void win_redraw(WINDOW *);
40void win_resize(int, int, char *);
41WINDOW *win_del();
42void restore_wins();
43void win_init_attrs();
44void mvwaddstr_fill(WINDOW *, int, int, char *, int);
45void abend(int, char *);
46int nf_error(int, char *);
47int Perror(char *);
50
51void list_colors();
52int clr_name_to_idx(char *);
53void init_hex_clr(int, char *);
54RGB hex_clr_str_to_rgb(char *);
55RGB xterm256_idx_to_rgb(int);
56int rgb_to_curses_clr(RGB *);
57int rgb_to_xterm256_idx(RGB *);
58void apply_gamma(RGB *);
59
60Chyron *new_chyron();
61void set_chyron_key(Chyron *, int, char *, int);
62void set_chyron_key_cp(Chyron *, int, char *, int, int);
63bool is_set_chyron_key(Chyron *, int);
64void unset_chyron_key(Chyron *, int);
65void compile_chyron(Chyron *);
66int get_chyron_key(Chyron *, int);
67Chyron *destroy_chyron(Chyron *chyron);
68Chyron *wait_mk_chyron();
69
70int mb_to_cc(cchar_t *, char *, attr_t, int, int *, int);
71
72int wait_continue(WINDOW *, Chyron *, int);
73bool wait_destroy(Chyron *);
74int xwgetch(WINDOW *, Chyron *, int);
75cchar_t mkccc(int, attr_t, char *);
76
77WINDOW *mouse_win;
78WINDOW *wait_mk_win(Chyron *, char *);
79SCREEN *screen;
80SIO *sio; /**< Global pointer to SIO struct for terminal and color settings */
81
82/** StdColors
83 @details Standard 16 colors for xterm256 color conversions These colors can
84 be overridden in ".minitrc" */
85RGB StdColors[16] = {
86 {0, 0, 0}, {128, 0, 0}, {0, 128, 0}, {128, 128, 0}, {0, 0, 128}, {128, 0, 128}, {0, 128, 128}, {192, 192, 192}, {128, 128, 128}, {255, 0, 0}, {0, 255, 0}, {255, 255, 0}, {0, 0, 255}, {255, 0, 255}, {0, 255, 255}, {255, 255, 255}};
87/** colors_text
88 @brief Color names for .minitrc overrides
89 @details These names are used in .minitrc to specify color overrides The
90 order of these names corresponds to the ColorsEnum values */
91char const colors_text[][10] = {
92 "black", "red", "green", "yellow", "blue", "magenta", "cyan",
93 "white", "orange", "bg", "abg", "bblack", "bred", "bgreen",
94 "byellow", "bblue", "bcyan", "bmagenta", "bwhite", "borange", ""};
95
96const wchar_t bw_ho = BW_HO; /**< horizontal line */
97const wchar_t bw_ve = BW_VE; /**< vertical line */
98const wchar_t bw_tl = BW_RTL; /**< top left corner */
99const wchar_t bw_tr = BW_RTR; /**< top right corner */
100const wchar_t bw_bl = BW_RBL; /**< bottom left corner */
101const wchar_t bw_br = BW_RBR; /**< bottom right corner */
102const wchar_t bw_lt = BW_LT; /**< left tee */
103const wchar_t bw_rt = BW_RT; /**< right tee */
104const wchar_t bw_sp = BW_SP; /**< tee space */
105const wchar_t bw_ra = BW_RA; /**< right arrow */
106const wchar_t bw_la = BW_LA; /**< right arrow */
107const wchar_t bw_ua = BW_UA; /**< right arrow */
108const wchar_t bw_da = BW_DA; /**< right arrow */
109const wchar_t bw_ran = BW_RAN; /**< right angle */
110const wchar_t bw_lan = BW_LAN; /**< right angle */
111
113 1.2; /**< Gamma correction value for gray colors. Set in .minitrc */
114double RED_GAMMA =
115 1.2; /**< Gamma correction value for red colors. Set in .minitrc */
117 1.2; /**< Gamma correction value for green colors. Set in .minitrc */
119 1.2; /**< Gamma correction value for blue colors. Set in .minitrc */
120
121WINDOW *win;
126unsigned int cmd_key;
127bool f_sigwench = false;
133int m_begy = -1;
134int m_begx = -1;
140char fn[MAXLEN];
153int clr_cnt = 0;
156cchar_t CCC_NORM;
157cchar_t CCC_WIN;
158cchar_t CCC_BG;
159cchar_t CCC_BOX;
160cchar_t CCC_NT;
163cchar_t CCC_NT_HL;
164cchar_t CCC_LN;
165cchar_t CCC_BRKTL;
166cchar_t CCC_BRKTR;
167/** Global file/pipe numbers */
170
171/** @brief Initialize window attributes
172 @ingroup window_support
173 @details This function initializes color pairs for the window
174 cp_norm, cp_win, and cp_box are global variables
175 */
176void win_init_attrs() { return; }
177
178/** open_curses
179 @brief Initialize NCurses and color settings
180 @ingroup window_support
181 @param sio Pointer to SIO struct with terminal and color settings
182 @return true if successful, false if error
183 @details This function initializes NCurses and sets up color pairs based on
184 the settings in the SIO struct. It also applies gamma correction to colors.
185 Use this function to initialize NCurses if you don't want NCurses to receive
186 data from the stdin pipe
187 @code
188 1. saves stdin and stdout file descriptors in SIO
189 2. opens a terminal device for NCurses screen IO
190 3. replaces STDERR_FILENO with terminal file descriptor
191 @endcode */
192bool open_curses(SIO *sio) {
193 char tmp_str[MAXLEN];
194 char emsg0[MAXLEN];
195
196 if (ttyname_r(STDERR_FILENO, sio->tty_name, sizeof(sio->tty_name)) != 0) {
197 strerror_r(errno, tmp_str, MAXLEN - 1);
198 strnz__cpy(emsg0, "ttyname_r failed ", MAXLEN - 1);
199 strnz__cat(emsg0, tmp_str, MAXLEN - 1);
200 fprintf(stderr, "%s\n", tmp_str);
201 exit(0);
202 }
203 /** open the terminal device for reading and writing */
204 ncurses_fp = fopen(sio->tty_name, "r+");
205 if (ncurses_fp == nullptr) {
206 strerror_r(errno, tmp_str, MAXLEN - 1);
207 strnz__cpy(emsg0, "fopen(sio->tty_name) failed ", MAXLEN - 1);
208 strnz__cat(emsg0, tmp_str, MAXLEN - 1);
209 fprintf(stderr, "%s\n", tmp_str);
210 exit(0);
211 }
212 /** We use SCREEN and newterm because this allows us to */
213 /** specify the terminal FILE */
214 screen = newterm(nullptr, ncurses_fp, ncurses_fp);
215 if (screen == nullptr) {
216 strerror_r(errno, tmp_str, MAXLEN - 1);
217 strnz__cpy(emsg0, "newterm failed ", MAXLEN - 1);
218 strnz__cat(emsg0, tmp_str, MAXLEN - 1);
219 fprintf(stderr, "%s\n", tmp_str);
220 exit(0);
221 }
222 set_term(screen);
223 f_curses_open = true;
224 if (!has_colors()) {
226 abend(-1, "Terminal color support required");
227 }
228 start_color();
229 if (!can_change_color()) {
231 fprintf(stderr, "Terminal cannot change colors\n");
232 fprintf(stderr, "Check TERM environment variable\n");
233 fprintf(stderr, "Check terminfo for missing \"ccc\"\n");
234 abend(-1, "fatal error");
235 }
237 /** Set gamma correction values */
238 /** These are read from ~/.minitrc */
239 /** We need these values when initializing colors */
244
245 // cp_ variables are indices for ncurses color pairs, created with get_clr_pair function. These color pairs are used to set the foreground and background colors for different elements of the interface, such as windows, text, and boxes. By defining these color pair indices as global variables, we can easily reference them throughout the code when applying colors to various parts of the interface using NCurses functions that accept color pair indices.
254 // CCC_ variables are cchar_t versions of the color pairs, created with mkccc function for use in NCurses functions that require cchar_t attributes. These are used to set the background color of windows and other elements in the interface. By creating these cchar_t variables, we can easily apply the desired color pairs to various parts of the interface using NCurses functions that accept cchar_t attributes.
255 CCC_NORM = mkccc(cp_norm, WA_NORMAL, " ");
256 CCC_WIN = mkccc(cp_win, WA_NORMAL, " ");
257 CCC_NT = mkccc(cp_nt, WA_NORMAL, " ");
258 CCC_NT_REV = mkccc(cp_nt_rev, WA_NORMAL, " ");
259 CCC_NT_HL_REV = mkccc(cp_nt_hl_rev, WA_NORMAL, " ");
260 CCC_NT_HL = mkccc(cp_nt_hl, WA_NORMAL, " ");
261 CCC_BOX = mkccc(cp_box, WA_NORMAL, " ");
262 CCC_LN = mkccc(cp_ln, WA_NORMAL, " ");
263 noecho();
264 keypad(stdscr, true);
265 idlok(stdscr, false);
266 idcok(stdscr, false);
267 wbkgrndset(stdscr, &CCC_NT);
268#ifdef DEBUG_IMMEDOK
269 immedok(stdscr, true);
270#endif
271 win_ptr = -1;
272 return sio;
273}
274/** @defgroup color_management Color Management
275 @brief Conversion of Color Data Types and Management of Colors and Color
276 Pairs
277 */
278/** get_clr_pair
279 @brief Get color pair index for foreground and background colors
280 @ingroup color_management
281 @param fg Foreground color index
282 @param bg Background color index
283 @return Color pair index */
284int get_clr_pair(int fg, int bg) {
285 int rc, i, pfg, pbg;
286 for (i = 1; i < clr_pair_cnt; i++) {
287 extended_pair_content(i, &pfg, &pbg);
288 if (pfg == fg && pbg == bg)
289 return i;
290 }
291 if (i >= COLOR_PAIRS) {
292 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__ - 1);
293 ssnprintf(em1, MAXLEN - 1, "NCurses COLOR_PAIRS (%d) exceeded (%d)",
294 COLOR_PAIRS, i);
295 strerror_r(errno, em2, MAXLEN);
297 return (EXIT_FAILURE);
298 }
299 if (i < COLOR_PAIRS) {
300 rc = init_extended_pair(i, fg, bg);
301 if (rc == ERR)
302 return ERR;
303 }
304 if (i < COLOR_PAIRS)
305 clr_pair_cnt++;
306 return i;
307}
308/** rgb_to_curses_clr
309 @brief Get color index for RGB color
310 @ingroup color_management
311 @param rgb RGB color
312 @return NCurses color index
313 @details Curses uses 0-1000 for RGB values. If the color does not exist, it
314 is created along with a new color index */
315int rgb_to_curses_clr(RGB *rgb) {
316 int i;
317 int r, g, b;
318 apply_gamma(rgb);
319 rgb->r = (rgb->r * 1000) / 255;
320 rgb->g = (rgb->g * 1000) / 255;
321 rgb->b = (rgb->b * 1000) / 255;
322 for (i = 0; i < clr_cnt; i++) {
323 extended_color_content(i, &r, &g, &b);
324 if (rgb->r == r && rgb->g == g && rgb->b == b) {
325 return i;
326 }
327 }
328 if (i < COLORS) {
329 init_extended_color(i, rgb->r, rgb->g, rgb->b);
330 clr_cnt++;
331 return clr_cnt - 1;
332 }
333 return ERR;
334}
335/** rgb_to_xterm256_idx
336 @brief Convert RGB color to XTerm 256 color index
337 @ingroup color_management
338 @param rgb RGB color
339 @return XTerm 256 color index
340 @details This function converts an RGB color to the nearest XTerm 256 color
341 index. It first checks if the color is a shade of gray, and if so, it uses
342 the gray ramp. Otherwise, it calculates the nearest color in the 6x6x6 color
343 cube. */
344int rgb_to_xterm256_idx(RGB *rgb) {
345 if (rgb->r == rgb->g && rgb->g == rgb->b) {
346 if (rgb->r < 8)
347 return 16;
348 if (rgb->r > 248)
349 return 231;
350 return ((rgb->r - 8) / 10) + 231;
351 } else {
352 int r_index = (rgb->r < 45) ? 0 : (rgb->r - 60) / 40 + 1;
353 int g_index = (rgb->g < 45) ? 0 : (rgb->g - 60) / 40 + 1;
354 int b_index = (rgb->b < 45) ? 0 : (rgb->b - 60) / 40 + 1;
355 return 16 + (36 * r_index) + (6 * g_index) + b_index;
356 }
357}
358/** xterm256_idx_to_rgb
359 @brief Convert XTerm 256 color index to RGB color
360 @ingroup color_management
361 @param idx XTerm 256 color index
362 @return RGB color
363 @details This function converts an XTerm 256 color index to an RGB color. It
364 first checks if the index is in the standard 16 colors, then checks if it's
365 in the 6x6x6 color cube, and finally checks if it's in the gray ramp. */
367 /** Convert XTerm 256 color index to RGB
368 @param idx - XTerm 256 color index
369 @return RGB struct */
370 RGB rgb;
371 if (idx > 255)
372 idx = 255;
373 if (idx < 0)
374 idx = 0;
375 rgb.r = rgb.g = rgb.b = 0;
376 if (idx < 16) {
377 rgb.r = StdColors[idx].r;
378 rgb.g = StdColors[idx].g;
379 rgb.b = StdColors[idx].b;
380 } else if (idx >= 16 && idx <= 231) {
381 idx -= 16;
382 rgb.r = (idx / 36) % 6 * 51;
383 rgb.g = (idx / 6) % 6 * 51;
384 rgb.b = (idx % 6) * 51;
385 } else if (idx >= 232 && idx <= 255) {
386 int gray = (idx - 232) * 11;
387 rgb.r = rgb.g = rgb.b = gray;
388 }
389 return rgb;
390}
391
392/** apply_gamma
393 @brief Apply gamma correction to RGB color
394 @ingroup color_management
395 @param rgb Pointer to RGB color
396 @details This function modifies the RGB color in place. It applies gamma
397 correction to the RGB color based on the gamma values set in the SIO struct.
398 If the color is a shade of gray, it applies the gray gamma correction.
399 Otherwise, it applies the individual red, green, and blue gamma corrections.
400 */
401void apply_gamma(RGB *rgb) {
402 if (rgb->r == rgb->g && rgb->r == rgb->b) {
403 if (GRAY_GAMMA > 0.0f && GRAY_GAMMA != 1.0f) {
404 rgb->r = (int)(pow((rgb->r / 255.0f), 1.0f / GRAY_GAMMA) * 255.0f);
405 rgb->g = rgb->r;
406 rgb->b = rgb->r;
407 }
408 return;
409 }
410 if (rgb->r != 0 && RED_GAMMA > 0.0f && RED_GAMMA != 1.0f)
411 rgb->r = (int)(pow((rgb->r / 255.0f), 1.0f / RED_GAMMA) * 255.0f);
412 if (rgb->g != 0 && GREEN_GAMMA > 0.0f && GREEN_GAMMA != 1.0f)
413 rgb->g = (int)(pow((rgb->g / 255.0f), 1.0f / GREEN_GAMMA) * 255.0f);
414 if (rgb->b != 0 && BLUE_GAMMA > 0.0f && BLUE_GAMMA != 1.0f)
415 rgb->b = (int)(pow((rgb->b / 255.0f), 1.0f / BLUE_GAMMA) * 255.0f);
416}
417/** init_clr_palette
418 @brief Initialize color palette based on SIO settings
419 @ingroup color_management
420 @param sio Pointer to SIO struct with color settings
421 @return true if successful, false if error
422 @details This function initializes the xterm256 color cube and applies any
423 color overrides specified in the SIO struct. The color strings in the SIO
424 struct are expected to be six-digit HTML style hex color codes (e.g.,
425 "#RRGGBB"). If a color override is specified for any of the standard colors,
426 it is applied using the init_hex_clr function. After processing all colors,
427 the clr_cnt variable is set to CLR_NCOLORS to indicate that the standard
428 colors have been initialized. */
429bool init_clr_palette(SIO *sio) {
430 if (sio->black[0])
432 if (sio->red[0])
434 if (sio->green[0])
436 if (sio->yellow[0])
438 if (sio->blue[0])
440 if (sio->magenta[0])
442 if (sio->cyan[0])
444 if (sio->white[0])
446 if (sio->bblack[0])
448 if (sio->bred[0])
450 if (sio->bgreen[0])
452 if (sio->byellow[0])
454 if (sio->bblue[0])
456 if (sio->bmagenta[0])
458 if (sio->bcyan[0])
460 if (sio->bwhite[0])
462 if (sio->borange[0])
464 if (sio->fg_clr_x[0])
466 if (sio->bg_clr_x[0])
468 if (sio->bo_clr_x[0])
470 if (sio->ln_clr_x[0])
472 if (sio->ln_bg_clr_x[0])
474
475 if (sio->nt_fg[0])
477 if (sio->nt_bg[0])
479
480 if (sio->nt_rev_fg[0])
482 if (sio->nt_rev_bg[0])
484
485 if (sio->nt_hl_fg[0])
487 if (sio->nt_hl_bg[0])
489
490 if (sio->nt_hl_rev_fg[0])
492 if (sio->nt_hl_rev_bg[0])
494
496 return true;
497}
498/** init_hex_clr
499 @brief Initialize extended ncurses color from HTML style hex string
500 @ingroup color_management
501 @param idx Color index
502 @param s Hex color string
503 @details NCurses uses 0-1000 for RGB values, so the RGB values from the hex
504 string are converted to this range before initializing the color. If the
505 color index is less than 16, the RGB values are also stored in the StdColors
506 array for reference.
507 */
508void init_hex_clr(int idx, char *s) {
509 RGB rgb;
511 apply_gamma(&rgb);
512 if (idx < 16) {
513 StdColors[idx].r = rgb.r;
514 StdColors[idx].g = rgb.g;
515 StdColors[idx].b = rgb.b;
516 }
517 rgb.r = (rgb.r * 1000) / 255;
518 rgb.g = (rgb.g * 1000) / 255;
519 rgb.b = (rgb.b * 1000) / 255;
520 init_extended_color(idx, rgb.r, rgb.g, rgb.b);
521}
522/** hex_clr_str_to_rgb
523 @brief Convert six-digit HTML style hex color code to RGB struct
524 @ingroup color_management
525 @param s six-digit HTML style hex color code */
526RGB hex_clr_str_to_rgb(char *s) {
527 RGB rgb;
528 sscanf(s, "#%02x%02x%02x", &rgb.r, &rgb.g, &rgb.b);
529 return rgb;
530}
531/** destroy_curses
532 @brief Gracefully shut down NCurses and restore terminal settings
533 @ingroup window_support
534 @details This function should be called before exiting the program to ensure
535 that the terminal is left in a usable state. It checks if NCurses was
536 initialized and, if so, it erases the screen, refreshes it, and ends the
537 NCurses session. It also restores the original terminal settings using
538 restore_shell_tioctl and resets signal handlers to their default state with
539 sig_dfl_mode. */
541 if (!f_curses_open)
542 return;
543 while (win_ptr > 0) {
544 if (win_win[win_ptr])
545 delwin(win_win[win_ptr]);
546 if (win_win2[win_ptr])
547 delwin(win_win2[win_ptr]);
548 if (win_box[win_ptr])
549 delwin(win_box[win_ptr]);
553 win_ptr--;
554 }
555 werase(stdscr);
556 wrefresh(stdscr);
557 endwin();
558 delscreen(screen);
559 fclose(ncurses_fp);
560 f_curses_open = false;
563 return;
564}
565/** mb_to_cc
566 @brief Convert multibyte string to complex character array
567 @ingroup Chyron
568 @param cmplx_buf Output buffer for complex characters
569 @param str Input multibyte string
570 @param attr Attributes to apply to the complex characters
571 @param cpx Color pair index for the complex characters
572 @param pos Pointer to current position in the output buffer, updated as
573 characters are added
574 @param maxlen Maximum length of the output buffer
575 @return Number of bytes processed from the input string
576 @details This function converts a multibyte string to an array of complex
577 characters (cchar_t) that can be used with NCurses functions. It handles
578 multibyte characters and applies the specified color pair to each character.
579 The pos parameter is updated to reflect the current position in the output
580 buffer, and the function ensures that it does not exceed the maximum length.
581*/
582int mb_to_cc(cchar_t *cmplx_buf, char *str, attr_t attr, int cpx, int *pos,
583 int maxlen) {
584 int i = 0, len = 0;
585 const char *s;
586 cchar_t cc = {0};
587 wchar_t wstr[2] = {L'\0', L'\0'};
588 mbstate_t mbstate;
589 memset(&mbstate, 0, sizeof(mbstate));
590 attr = WA_NORMAL;
591 if (*pos >= maxlen - 1)
592 return 0;
593 while (str[i] != '\0') {
594 s = &str[i];
595 len = mbrtowc(wstr, s, MB_CUR_MAX, &mbstate);
596 if (len <= 0) {
597 wstr[0] = L'?';
598 wstr[1] = L'\0';
599 len = 1;
600 }
601 wstr[1] = L'\0';
602 if (*pos >= maxlen - 1)
603 break;
604 if (setcchar(&cc, wstr, attr, cpx, nullptr) != ERR) {
605 if (len > 0 && (*pos + len) < MAXLEN - 1)
606 cmplx_buf[(*pos)++] = cc;
607 }
608 i += len;
609 }
610 wstr[0] = L'\0';
611 wstr[1] = L'\0';
612 setcchar(&cc, wstr, attr, cpx, nullptr);
613 cmplx_buf[*pos] = cc;
614 return *pos;
615}
616/** mkccc
617 @brief Create a cchar_t with the specified color pair index
618 @ingroup color_management
619 @param cp Color pair index
620 @param attr Attributes to apply to the cchar_t
621 @param s Multibyte string to convert to wide character (only the first
622 character is used)
623 @return cchar_t with the specified color pair index and a space character
624 as the wide character */
625cchar_t mkccc(int cp, attr_t attr, char *s) {
626 cchar_t cc = {0};
627 wchar_t wstr[2] = {L'\0', L'\0'};
628 mbstate_t mbstate;
629 memset(&mbstate, 0, sizeof(mbstate));
630 mbrtowc(wstr, s, MB_CUR_MAX, &mbstate);
631 setcchar(&cc, wstr, attr, cp, nullptr);
632 return cc;
633}
634/** mk_cmplx_str
635 @brief Convert a multibyte string to an array of cchar_t complex characters
636 @ingroup color_management
637 @param cmplx_buf Output buffer for complex characters (allocated within the
638 function)
639 @param s Input multibyte string
640 @param attr Attributes to apply to the complex characters
641 @param cp Color pair index for the complex characters
642 @return Number of bytes processed from the input string
643 @details This function converts a multibyte string to an array of complex
644 characters (cchar_t) that can be used with NCurses functions. It handles
645 multibyte characters and applies the specified color pair to each character.
646 @note cmplx_buf is allocated within the function and should be freed by the
647 caller when no longer needed. */
648size_t mk_cmplx_str(cchar_t *cmplx_buf, char *s, attr_t attr, int cp) {
649 cchar_t cc = {0};
650 wchar_t wstr[2] = {L'\0', L'\0'};
651 mbstate_t mbstate;
652 memset(&mbstate, 0, sizeof(mbstate));
653 size_t len = strlen(s);
654 cmplx_buf = calloc(len + 1, sizeof(cchar_t));
655
656 while (*s != '\0') {
657 mbrtowc(wstr, s, MB_CUR_MAX, &mbstate);
658 setcchar(&cc, wstr, attr, cp, nullptr);
659 *cmplx_buf++ = cc;
660 s += mbrlen(s, MB_CUR_MAX, &mbstate);
661 }
662 wstr[0] = L'\0';
663 wstr[1] = L'\0';
664 setcchar(&cc, wstr, attr, cp, nullptr);
665 *cmplx_buf++ = cc;
666 return len;
667}
668/** display_cmplx_str
669 @brief Display a complex character string on a window
670 @ingroup color_management
671 @param win NCurses window to display the string on
672 @param cmplx_buf Array of cchar_t complex characters to display
673 @param line Line number to display the string on
674 @param col Column number to start displaying the string from
675 @details This function clears the line where the string will be displayed,
676 then uses wadd_wchstr to add the complex character string (cmplx_buf) to the
677 window. Finally, it moves the cursor to the specified column position. */
678void display_cmplx_str(WINDOW *win, cchar_t *cmplx_buf, int line, int col) {
679 wmove(win, line, 0);
680 wclrtoeol(win);
681 wmove(win, line, 0);
682 wadd_wchstr(win, cmplx_buf);
683 wmove(win, line, col);
684 return;
685}
686
687/** box2_new
688 @brief Create a new window with optional box and title
689 @ingroup window_support
690 @param wlines Number of lines
691 @param wcols Number of columns
692 @param wbegy Beginning Y position
693 @param wbegx Beginning X position
694 @param wtitle Window title
695 @param win_pair If true, creates a pair of windows (box and inner window)
696 @return 0 if successful, 1 if error */
697int box2_new(int wlines, int wcols, int wbegy, int wbegx, char *wtitle,
698 bool win_pair) {
699 int maxx;
700 if (win_ptr >= MAXWIN) {
701 ssnprintf(em0, MAXLEN - 1, "Maximum number of windows (%d) exceeded");
702 abend(-1, em0);
703 }
704 win_ptr++;
705 wlines = min(wlines, LINES - 2);
706 wcols = min(wcols, COLS - 2);
707 win_box[win_ptr] = newwin(wlines + 4, wcols + 2, wbegy, wbegx);
708 if (win_box[win_ptr] == nullptr) {
709 win_ptr--;
710 return 1;
711 }
712#ifdef DEBUG_IMMEDOK
713 immedok(win_box[win_ptr], true);
714#endif
715 wbkgrndset(win_box[win_ptr], &CCC_BOX);
717 mvwaddnwstr(win_box[win_ptr], 0, 1, &bw_rt, 1);
718 mvwaddnwstr(win_box[win_ptr], 0, 2, &bw_sp, 1);
719 mvwaddstr(win_box[win_ptr], 0, 3, wtitle);
720 maxx = getmaxx(win_box[win_ptr]);
721 int s = strlen(wtitle);
722 if ((s + 3) < maxx)
723 mvwaddch(win_box[win_ptr], 0, (s + 3), ' ');
724 if ((s + 4) < maxx)
725 mvwaddnwstr(win_box[win_ptr], 0, (s + 4), &bw_lt, 1);
726 wnoutrefresh(win_box[win_ptr]);
729 if (win_pair) {
730 win_new(wlines - 1, wcols, wbegy, wbegx);
731 win2_new(2, wcols, wbegy + wlines, wbegx);
732 }
733 return 0;
734}
735/** box_new
736 @brief Create a new window with optional box and title
737 @ingroup window_support
738 @param wlines Number of lines
739 @param wcols Number of columns
740 @param wbegy Beginning Y position
741 @param wbegx Beginning X position
742 @param wtitle Window title
743 @param win_pair If true, creates a pair of windows (box and inner window)
744 @return 0 if successful, 1 if error */
745int box_new(int wlines, int wcols, int wbegy, int wbegx, char *wtitle,
746 bool win_pair) {
747 int maxx;
748 if (win_ptr >= MAXWIN) {
749 ssnprintf(em0, MAXLEN - 1, "Maximum number of windows (%d) exceeded");
750 abend(-1, em0);
751 }
752 win_ptr++;
753 wlines = min(wlines, LINES - 2);
754 wcols = min(wcols, COLS - 2);
755 win_box[win_ptr] = newwin(wlines + 2, wcols + 2, wbegy, wbegx);
756 if (win_box[win_ptr] == nullptr) {
757 win_ptr--;
758 return 1;
759 }
760#ifdef DEBUG_IMMEDOK
761 immedok(win_box[win_ptr], true);
762#endif
763 wbkgrndset(win_box[win_ptr], &CCC_BOX);
765 mvwaddnwstr(win_box[win_ptr], 0, 1, &bw_rt, 1);
766 mvwaddnwstr(win_box[win_ptr], 0, 2, &bw_sp, 1);
767 mvwaddstr(win_box[win_ptr], 0, 3, wtitle);
768 maxx = getmaxx(win_box[win_ptr]);
769 int s = strlen(wtitle);
770 if ((s + 3) < maxx)
771 mvwaddch(win_box[win_ptr], 0, (s + 3), ' ');
772 if ((s + 4) < maxx)
773 mvwaddnwstr(win_box[win_ptr], 0, (s + 4), &bw_lt, 1);
774 wnoutrefresh(win_box[win_ptr]);
776 if (win_pair)
777 win_new(wlines, wcols, wbegy, wbegx);
778 return 0;
779}
780/** win_new
781 @brief Create a new window with specified dimensions and position
782 @ingroup window_support
783 @param wlines Number of lines
784 @param wcols Number of columns
785 @param wbegy Beginning Y position
786 @param wbegx Beginning X position
787 @return 0 if successful, 1 if error */
788int win_new(int wlines, int wcols, int wbegy, int wbegx) {
789 wbegy += 1;
790 wbegx += 1;
791 win_win[win_ptr] = newwin(wlines, wcols, wbegy, wbegx);
792 if (win_win[win_ptr] == nullptr) {
793 delwin(win_box[win_ptr]);
794 return 1;
795 }
796#ifdef DEBUG_IMMEDOK
797 immedok(win_win[win_ptr], true);
798#endif
799 wbkgrndset(win_win[win_ptr], &CCC_NT);
800 keypad(win_win[win_ptr], true);
801 idlok(win_win[win_ptr], false);
802 idcok(win_win[win_ptr], false);
803 scrollok(win_win[win_ptr], true);
804 return 0;
805}
806/** win2_new
807 @brief Create a new window with specified dimensions and position
808 @ingroup window_support
809 @param wlines Number of lines
810 @param wcols Number of columns
811 @param wbegy Beginning Y position
812 @param wbegx Beginning X position
813 @return 0 if successful, 1 if error */
814int win2_new(int wlines, int wcols, int wbegy, int wbegx) {
815 wbegy += 1;
816 wbegx += 1;
817 win_win2[win_ptr] = newwin(wlines, wcols, wbegy, wbegx);
818 if (win_win2[win_ptr] == nullptr) {
819 delwin(win_box[win_ptr]);
820 return 1;
821 }
822#ifdef DEBUG_IMMEDOK
823 immedok(win_win2[win_ptr], true);
824#endif
825 wbkgrndset(win_win2[win_ptr], &CCC_NT);
826 keypad(win_win2[win_ptr], true);
827 idlok(win_win2[win_ptr], false);
828 idcok(win_win2[win_ptr], false);
829 return 0;
830}
831/** win_resize
832 @brief Resize the current window and its box, and update the title
833 @ingroup window_support
834 @param wlines Number of lines
835 @param wcols Number of columns
836 @param title Window title
837 @details This function resizes the current window and its associated box
838 window to the specified number of lines and columns. It also updates the
839 title of the box window if a title is provided. After resizing, it refreshes
840 the windows to apply the changes. */
841void win_resize(int wlines, int wcols, char *title) {
842 int maxx;
843 wrefresh(stdscr);
844 wresize(win_box[win_ptr], wlines + 2, wcols + 2);
845 wbkgrndset(win_box[win_ptr], &CCC_BOX);
847 if (title != nullptr && *title != '\0') {
848 wmove(win_box[win_ptr], 0, 1);
849 waddnstr(win_box[win_ptr], (const char *)&bw_rt, 1);
850 wmove(win_box[win_ptr], 0, 2);
851 waddnstr(win_box[win_ptr], (const char *)&bw_sp, 1);
852 mvwaddnwstr(win_box[win_ptr], 0, 1, &bw_rt, 1);
853 mvwaddnwstr(win_box[win_ptr], 0, 2, &bw_sp, 1);
854 mvwaddstr(win_box[win_ptr], 0, 3, title);
855 maxx = getmaxx(win_box[win_ptr]);
856 int s = strlen(title);
857 if ((s + 3) < maxx)
858 mvwaddch(win_box[win_ptr], 0, (s + 3), ' ');
859 if ((s + 4) < maxx)
860 mvwaddnwstr(win_box[win_ptr], 0, (s + 4), &bw_lt, 1);
861 }
862 wnoutrefresh(win_box[win_ptr]);
863 wresize(win_win[win_ptr], wlines, wcols);
864 wbkgrndset(win_win[win_ptr], &CCC_NT);
865 wsetscrreg(win_win[win_ptr], 0, wlines - 1);
866 keypad(win_win[win_ptr], TRUE);
867 idlok(win_win[win_ptr], false);
868 idcok(win_win[win_ptr], false);
869 scrollok(win_win[win_ptr], true);
870#ifdef DEBUG_IMMEDOK
871 immedok(win_win[win_ptr], true);
872#endif
873}
874/** win_redraw
875 @brief Redraw the specified window
876 @ingroup window_support
877 @param win Pointer to the window to redraw
878 @details This function erases the contents of the specified window and then
879 refreshes it to update the display. Use this function when you need to clear
880 and redraw a window, such as after resizing or when updating its contents. */
881void win_redraw(WINDOW *win) {
882 werase(win);
883 wnoutrefresh(win);
884}
885/** win_del
886 @brief Delete the current window and its associated box window
887 @ingroup window_support
888 @return nullptr
889 @details This function deletes the current window and its associated box
890 window, if they exist. It also refreshes the remaining windows to ensure the
891 display is updated correctly. After calling this function, the global win_ptr
892 variable is decremented to point to the previous window in the stack. */
893WINDOW *win_del() {
894 int i;
895 curs_set(0);
896 if (win_ptr >= 0) {
897 if (win_win[win_ptr] != nullptr) {
898 touchwin(win_win[win_ptr]);
899 wbkgrndset(win_win[win_ptr], &CCC_NT);
900 werase(win_win[win_ptr]);
901 wnoutrefresh(win_win[win_ptr]);
902 delwin(win_win[win_ptr]);
903 }
904 if (win_box[win_ptr] != nullptr) {
905 touchwin(win_box[win_ptr]);
906 wbkgrndset(win_box[win_ptr], &CCC_NT);
907 werase(win_box[win_ptr]);
908 wnoutrefresh(win_box[win_ptr]);
909 delwin(win_box[win_ptr]);
910 }
911 for (i = 0; i < win_ptr; i++) {
912 if (win_box[i] != nullptr) {
913 touchwin(win_box[i]);
914 wnoutrefresh(win_box[i]);
915 }
916 if (win_win[i] == nullptr)
917 continue;
918 touchwin(win_win[i]);
919 wnoutrefresh(win_win[i]);
920 }
921 win_ptr--;
922 }
923 return 0;
924}
925/** restore_wins
926 @brief Restore all windows after a screen resize
927 @ingroup window_support
928 @details This function is used to restore the display of all windows after a
929 screen resize event. It clears the standard screen and then iterates through
930 all existing windows, touching and refreshing them to ensure they are redrawn
931 correctly on the resized screen. Use this function in response to a SIGWINCH
932 signal to handle terminal resizing gracefully. */
934 int i;
935 for (i = 0; i <= win_ptr; i++) {
936 if (win_box[i] != nullptr) {
937 touchwin(win_box[i]);
938 wnoutrefresh(win_box[i]);
939 wrefresh(win_box[i]);
940 }
941 if (win_win[i] == nullptr)
942 continue;
943 touchwin(win_win[i]);
944 wnoutrefresh(win_win[i]);
945 wrefresh(win_win[i]);
946 }
947}
948/** cbox
949 @brief Draw a box around the specified window
950 @ingroup window_support
951 @param box Pointer to the window to draw the box around
952 @details This function uses NCurses functions to draw a box around the
953 specified window. It adds the appropriate characters for the corners and
954 edges of the box based on the current character set. Use this function when
955 you want to visually separate a window from the rest of the screen with a
956 border. */
957void cbox(WINDOW *box) {
958 int x, y;
959 int maxx;
960 int maxy;
961
962 maxx = getmaxx(box);
963 maxx--;
964 mvwaddnwstr(box, 0, 0, &bw_tl, 1);
965 for (x = 1; x < maxx; x++)
966 waddnwstr(box, &bw_ho, 1);
967 waddnwstr(box, &bw_tr, 1);
968 maxy = getmaxy(box);
969 maxy--;
970 for (y = 1; y < maxy; y++) {
971 mvwaddnwstr(box, y, 0, &bw_ve, 1);
972 mvwaddnwstr(box, y, maxx, &bw_ve, 1);
973 }
974 mvwaddnwstr(box, maxy, 0, &bw_bl, 1);
975 for (x = 1; x < maxx; x++)
976 waddnwstr(box, &bw_ho, 1);
977 waddnwstr(box, &bw_br, 1);
978}
979/** cbox2
980 @brief Draw a box with a separator line around the specified window
981 @ingroup window_support
982 @param box Pointer to the window to draw the box around
983 @details This function draws a box around the specified window, similar to
984 cbox(), but it also includes a horizontal separator line that divides the box
985 into two sections. The separator line is drawn at a fixed position (line 00,
986 page 00) and extends across the width of the box. Use this function when you
987 want to visually separate two sections within a window, such as for a header
988 and content area. */
989void cbox2(WINDOW *box) {
990 int x, y;
991 int maxx;
992 int maxy;
993
994 maxx = getmaxx(box);
995 maxx--;
996 mvwaddnwstr(box, 0, 0, &bw_tl, 1);
997 for (x = 1; x < maxx; x++)
998 waddnwstr(box, &bw_ho, 1);
999 waddnwstr(box, &bw_tr, 1);
1000 maxy = getmaxy(box);
1001 // Verticals
1002 for (y = 1; y < maxy - 4; y++) {
1003 mvwaddnwstr(box, y, 0, &bw_ve, 1);
1004 mvwaddnwstr(box, y, maxx, &bw_ve, 1);
1005 }
1006 // Separator line
1007 mvwaddnwstr(box, y, 0, &bw_lt, 1);
1008 // line 00, page 00
1009 mvwaddnwstr(box, y, 1, &bw_rt, 1);
1010 mvwaddnwstr(box, y, 24, &bw_lt, 1);
1011 for (x = 25; x < maxx; x++)
1012 waddnwstr(box, &bw_ho, 1);
1013 waddnwstr(box, &bw_rt, 1);
1014 // Window 2
1015 y++;
1016 mvwaddnwstr(box, y, 0, &bw_ve, 1);
1017 mvwaddnwstr(box, y, maxx, &bw_ve, 1);
1018 y++;
1019 mvwaddnwstr(box, y, 0, &bw_ve, 1);
1020 mvwaddnwstr(box, y, maxx, &bw_ve, 1);
1021 // Bottom
1022 y++;
1023 mvwaddnwstr(box, y, 0, &bw_bl, 1);
1024 for (x = 1; x < maxx; x++)
1025 waddnwstr(box, &bw_ho, 1);
1026 waddnwstr(box, &bw_br, 1);
1027}
1028
1029/** @defgroup error_handling Error Handling
1030 @brief Display Error messages
1031 */
1032
1033/** answer_yn
1034 @brief Accept a single letter answer
1035 @ingroup error_handling
1036 @param em0 First error message line
1037 @param em1 Second error message line
1038 @param em2 Third error message line
1039 @param em3 Fourth error message line
1040 @return Key code of user command */
1041int answer_yn(char *em0, char *em1, char *em2, char *em3) {
1042 char title[MAXLEN];
1043 int line, pos, em_l, em0_l, em1_l, em2_l, em3_l;
1044 WINDOW *error_win;
1045
1046 if (!f_curses_open) {
1047 fprintf(stderr, "\n\n%s\n%s\n%s\n%s\n\n", em0, em1, em2, em3);
1048 return 1;
1049 }
1050
1051 Chyron *chyron = new_chyron();
1052 set_chyron_key(chyron, 1, "F1 Help", KEY_F(1));
1053 set_chyron_key(chyron, 2, "N - No", 'n');
1054 set_chyron_key(chyron, 3, "Y - Yes", 'y');
1055 compile_chyron(chyron);
1056
1057 em0_l = strnz(em0, COLS - 4);
1058 em1_l = strnz(em1, COLS - 4);
1059 em2_l = strnz(em2, COLS - 4);
1060 em3_l = strnz(em1, COLS - 4);
1061 em_l = max(em0_l, em1_l);
1062 em_l = max(em_l, em2_l);
1063 em_l = max(em_l, em3_l);
1064 em_l = max(em_l, chyron->l);
1065 em_l = min(em_l, COLS - 4);
1066
1067 pos = ((COLS - em_l) - 4) / 2;
1068 line = (LINES - 6) / 2;
1069 strnz__cpy(title, "Notification", MAXLEN - 1);
1070 if (box_new(5, em_l + 2, line, pos, title, true)) {
1071 ssnprintf(title, MAXLEN - 1, "box_new(%d, %d, %d, %d, %s) failed", 5,
1072 em_l + 2, line, pos, title);
1073 destroy_chyron(chyron);
1074 abend(-1, title);
1075 }
1076 error_win = win_win[win_ptr];
1077 mvwaddstr(error_win, 0, 1, em0);
1078 mvwaddstr(error_win, 1, 1, em1);
1079 mvwaddstr(error_win, 2, 1, em2);
1080 mvwaddstr(error_win, 3, 1, em3);
1081 display_chyron(error_win, chyron, 4, chyron->l + 1);
1082 do {
1083 curs_set(1);
1084 cmd_key = xwgetch(error_win, chyron, -1);
1085 curs_set(0);
1086 if (cmd_key == KEY_F(1) || cmd_key == 'N' || cmd_key == 'n' ||
1087 cmd_key == 'Y' || cmd_key == 'y')
1088 break;
1089 } while (1);
1090 win_del();
1091 destroy_chyron(chyron);
1092 return (cmd_key);
1093}
1094/** display_error
1095 @brief Display an error message window or print to stderr
1096 @ingroup error_handling
1097 @param em0 First error message line
1098 @param em1 Second error message line
1099 @param em2 Third error message line
1100 @param em3 Fourth error message line
1101 @return Key code of user command */
1102int display_error(char *em0, char *em1, char *em2, char *em3) {
1103 char title[MAXLEN];
1104 int line, pos, em_l, em0_l, em1_l, em2_l, em3_l;
1105 WINDOW *error_win;
1106
1107 if (!f_curses_open) {
1108 fprintf(stderr, "\n\n%s\n", em0);
1109 fprintf(stderr, "%s\n", em1);
1110 fprintf(stderr, "%s\n", em2);
1111 fprintf(stderr, "%s\n\n", em3);
1112 return 1;
1113 }
1114
1115 Chyron *chyron = new_chyron();
1116 set_chyron_key(chyron, 1, "F1 Help", KEY_F(1));
1117 set_chyron_key(chyron, 9, "F9 Cancel", KEY_F(9));
1118 set_chyron_key(chyron, 10, "F10 Continue", KEY_F(10));
1119 compile_chyron(chyron);
1120
1121 em0_l = strnz(em0, COLS - 4);
1122 em1_l = strnz(em1, COLS - 4);
1123 em2_l = strnz(em2, COLS - 4);
1124 em3_l = strnz(em1, COLS - 4);
1125 em_l = max(em0_l, em1_l);
1126 em_l = max(em_l, em2_l);
1127 em_l = max(em_l, em3_l);
1128 em_l = max(em_l, chyron->l);
1129 em_l = min(em_l, COLS - 4);
1130
1131 pos = ((COLS - em_l) - 4) / 2;
1132 line = (LINES - 6) / 2;
1133 strnz__cpy(title, "Notification", MAXLEN - 1);
1134 if (box_new(5, em_l + 2, line, pos, title, true)) {
1135 ssnprintf(title, MAXLEN - 1, "box_new(%d, %d, %d, %d, %s) failed", 5,
1136 em_l + 2, line, pos, title);
1137 destroy_chyron(chyron);
1138 abend(-1, title);
1139 }
1140 error_win = win_win[win_ptr];
1141 mvwaddstr(error_win, 0, 1, em0);
1142 mvwaddstr(error_win, 1, 1, em1);
1143 mvwaddstr(error_win, 2, 1, em2);
1144 mvwaddstr(error_win, 3, 1, em3);
1145 display_chyron(error_win, chyron, 4, chyron->l + 1);
1146 do {
1147 cmd_key = xwgetch(error_win, chyron, -1);
1148 if (cmd_key == KEY_F(9) || cmd_key == KEY_F(10) || cmd_key == 'q' ||
1149 cmd_key == 'Q')
1150 break;
1151 } while (1);
1152 win_del();
1153 destroy_chyron(chyron);
1154 return (cmd_key);
1155}
1156
1157/** Perror
1158 @brief Display a simple error message window or print to stderr
1159 @ingroup error_handling
1160 @param emsg_str Error message string
1161 @return Key code of user command */
1162int Perror(char *emsg_str) {
1163 char emsg[80];
1164 int emsg_max_len = 80;
1165 unsigned cmd_key;
1166 WINDOW *error_win;
1167 int len, line, pos;
1168 char title[MAXLEN];
1169 bool f_xwgetch = true;
1170 if (emsg_str[0] == '␛' && emsg_str[1] == 'w') {
1171 emsg_str += 2;
1172 f_xwgetch = false;
1173 }
1174 strnz__cpy(emsg, emsg_str, emsg_max_len - 1);
1175 if (!f_curses_open) {
1176 fprintf(stderr, "\n%s\n", emsg);
1177 return 1;
1178 }
1179 Chyron *chyron = new_chyron();
1180 set_chyron_key(chyron, 1, "F1 Help", KEY_F(1));
1181 set_chyron_key(chyron, 9, "F9 Cancel", KEY_F(9));
1182 set_chyron_key(chyron, 10, "F10 Continue", KEY_F(10));
1183 compile_chyron(chyron);
1184 len = max(strlen(title), strlen(emsg));
1185 len = max(len, chyron->l);
1186 len = max(len, 40);
1187 pos = (COLS - len - 4) / 2;
1188 line = (LINES - 4) / 2;
1189 strnz__cpy(title, "Notification", MAXLEN - 1);
1190 if (box_new(2, len + 2, line, pos, title, true)) {
1191 ssnprintf(title, MAXLEN - 1, "box_new(%d, %d, %d, %d, %s, %b) failed",
1192 4, line, line, pos, title);
1193 destroy_chyron(chyron);
1194 abend(-1, title);
1195 }
1196 error_win = win_win[win_ptr];
1197 mvwaddstr(error_win, 0, 1, emsg);
1198 display_chyron(error_win, chyron, 1, chyron->l + 1);
1199 if (f_xwgetch) {
1200 curs_set(1);
1201 cmd_key = xwgetch(error_win, chyron, -1);
1202 curs_set(0);
1203 win_del();
1204 } else {
1205 cmd_key = KEY_F(10);
1206 }
1207 destroy_chyron(chyron);
1208 return (cmd_key);
1209}
1210/** wait_mk_chyron
1211 @brief Create a Chyron struct for the waiting message
1212 @ingroup error_handling
1213 @return Pointer to the chyron struct */
1215 Chyron *chyron = new_chyron();
1216 set_chyron_key(chyron, 9, "F9 Cancel", KEY_F(9));
1217 compile_chyron(chyron);
1218 return chyron;
1219}
1220/** wait_mk_win
1221 @brief Display a popup waiting message
1222 @ingroup error_handling
1223 @param chyron Pointer to Chyron struct for displaying key options
1224 @param title window title
1225 @return WINDOW * struct */
1226WINDOW *wait_mk_win(Chyron *chyron, char *title) {
1227 char wm1[] = "Seconds remaining:";
1228 int len;
1229 int line, col;
1230 WINDOW *wait_win;
1231
1232 if (!f_curses_open) {
1233 fprintf(stderr, "\n%s\n", title);
1234 fprintf(stderr, "%s\n", wm1);
1235 return NULL;
1236 }
1237 len = max(strlen(title), strlen(wm1));
1238 len = max(len, chyron->l);
1239 len = max(len, 40);
1240 col = (COLS - len - 4) / 2;
1241 line = (LINES - 4) / 2;
1242 if (box_new(2, len + 2, line, col, title, true)) {
1243 ssnprintf(title, MAXLEN - 1, "box_new(%d, %d, %d, %d, %s) failed", 4,
1244 line, line, col, title);
1245 abend(-1, title);
1246 }
1247 wait_win = win_win[win_ptr];
1248 mvwaddstr(wait_win, 0, 1, wm1);
1249 display_chyron(wait_win, chyron, 1, 0);
1250 wmove(wait_win, 1, chyron->l);
1251 return wait_win;
1252}
1253/** wait_destroy
1254 @brief Destroy the waiting message window and chyron
1255 @ingroup error_handling
1256 @param chyron Pointer to Chyron struct for displaying key options
1257 @return true if successful */
1258bool wait_destroy(Chyron *chyron) {
1259 win_del();
1260 destroy_chyron(chyron);
1261 return true;
1262}
1263/** wait_continue
1264 @brief Update the waiting message with remaining time and check for user
1265 input
1266 @ingroup error_handling
1267 @param chyron Pointer to Chyron struct for displaying key options
1268 @param wait_win Pointer to the waiting message window
1269 @param remaining Time remaining for the wait in seconds
1270 @return true if the wait should continue, false if it should be cancelled */
1271int wait_continue(WINDOW *wait_win, Chyron *chyron, int remaining) {
1272 char time_str[10];
1273 ssnprintf(time_str, 9, "%-4d", remaining);
1274 mvwaddstr(wait_win, 0, 21, time_str);
1275 display_chyron(wait_win, chyron, 1, 0);
1276 wmove(wait_win, 1, chyron->l);
1277 cmd_key = xwgetch(wait_win, chyron, 1);
1278 return cmd_key;
1279}
1280/** action_disposition
1281 @brief Display a simple action disposition message window or print to stderr
1282 @ingroup error_handling
1283 @param title Window title
1284 @param action_str Action description string
1285 @return true if successful */
1286bool action_disposition(char *title, char *action_str) {
1287 int len;
1288 int line, col;
1289 WINDOW *action_disposition_win;
1290
1291 if (!f_curses_open) {
1292 fprintf(stderr, "\n%s\n", title);
1293 fprintf(stderr, "%s\n", action_str);
1294 return true;
1295 }
1296 Chyron *chyron = new_chyron();
1297 set_chyron_key(chyron, 10, "F10 Continue", KEY_F(10));
1298 compile_chyron(chyron);
1299 len = max(strlen(title), strlen(action_str));
1300 col = (COLS - len - 4) / 2;
1301 line = (LINES - 4) / 2;
1302 if (box_new(2, len + 2, line, col, title, true)) {
1303 ssnprintf(em0, MAXLEN - 1, "box_new(%d, %d, %d, %d, %s) failed", 4,
1304 line, line, col, title);
1306 }
1307 action_disposition_win = win_win[win_ptr];
1308 mvwaddstr(action_disposition_win, 0, 1, action_str);
1309 display_chyron(action_disposition_win, chyron, 1, 0);
1310 wmove(action_disposition_win, 1, chyron->l);
1311 cmd_key = xwgetch(action_disposition_win, chyron, 1);
1312 win_del();
1313 destroy_chyron(chyron);
1314 return true;
1315}
1316/** @defgroup Chyron Chyron Management
1317 @brief Create and manage the Chyron
1318 */
1319
1320/** new_chyron
1321 @brief Create and initialize Chyron structure
1322 @ingroup Chyron
1323 @return pointer to new Chyron structure
1324 @details This function allocates memory for a new Chyron structure and
1325 initializes the key pointers. Each key pointer is allocated memory for a
1326 ChyronKey structure. The Chyron structure is used to manage function key
1327 labels and their associated keycodes for mouse click handling in the chyron
1328 area of the interface.
1329 The use of calloc ensures that the allocated memory is initialized to
1330 zero, which means that the text for each key will be initialized to an empty
1331 string and the keycodes will be initialized to zero. This allows the
1332 is_set_chyron_key function to check if a key is set by checking if the first
1333 character of the text is not '\0'. If any memory allocation fails, the
1334 function will call abend to handle the error and return nullptr.
1335 */
1336Chyron *new_chyron() {
1337 Chyron *chyron = (Chyron *)calloc(1, sizeof(Chyron));
1338 if (!chyron) {
1339 abend(-1, "calloc chyron failed");
1340 return nullptr;
1341 }
1342 for (int i = 0; i < CHYRON_KEYS; i++)
1343 chyron->key[i] = (ChyronKey *)calloc(1, sizeof(ChyronKey));
1344 return chyron;
1345}
1346/** destroy_chyron
1347 @brief Destroy Chyron structure
1348 @ingroup Chyron
1349 @param chyron pointer to Chyron structure
1350 @return nullptr
1351 */
1352Chyron *destroy_chyron(Chyron *chyron) {
1353 int i;
1354
1355 if (!chyron)
1356 return nullptr;
1357 for (i = 0; i < CHYRON_KEYS; i++) {
1358 if (chyron->key[i])
1359 free(chyron->key[i]);
1360 chyron->key[i] = nullptr;
1361 }
1362 free(chyron);
1363 chyron = nullptr;
1364 return chyron;
1365}
1366/** is_set_chyron_key
1367 @brief Check if function key label is set
1368 @ingroup Chyron
1369 @param chyron structure
1370 @param k Function key index (0-19)
1371 @return true if set, false if not set */
1372bool is_set_chyron_key(Chyron *chyron, int k) {
1373 if (chyron->key[k]->text[0] != '\0')
1374 return true;
1375 else
1376 return false;
1377}
1378/** set_chyron_key_cp
1379 @brief Set chyron key with color pair (cp)
1380 @ingroup Chyron
1381 @param chyron structure
1382 @param k chyron key index (0-19)
1383 @param s chyron key label
1384 @param kc chyron key code
1385 @param cp color pair index for the key label
1386 @details This function is like set_chyron_key, except it includes a color
1387 pair numbers */
1388void set_chyron_key_cp(Chyron *chyron, int k, char *s, int kc, int cp) {
1389 if (*s != '\0')
1390 ssnprintf(chyron->key[k]->text, CHYRON_KEY_MAXLEN - 1, "%s", s);
1391 else
1392 chyron->key[k]->text[0] = '\0';
1393 chyron->key[k]->keycode = kc;
1394 chyron->key[k]->cp = cp;
1395}
1396/** set_chyron_key
1397 @brief Set chyron key with default color pair (cp_nt_rev)
1398 @ingroup Chyron
1399 @param chyron structure
1400 @param k chyron key index (0-19)
1401 @param s chyron key label
1402 @param kc chyron key code
1403 @details This function sets the label and keycode for a function key in the
1404 chyron structure. It uses the default color pair cp_nt_rev for the key
1405 label. If the input string s is not empty, it copies the string into the
1406 chyron key's text field. If the input string is empty, it sets the first
1407 character of the text field to '\0' to indicate that the key is not set.
1408 The keycode is stored in the chyron key's keycode field, and the color pair
1409 index is set to cp_nt_rev.
1410 */
1411void set_chyron_key(Chyron *chyron, int k, char *s, int kc) {
1412 if (*s != '\0')
1413 ssnprintf(chyron->key[k]->text, CHYRON_KEY_MAXLEN - 1, "%s", s);
1414 else
1415 chyron->key[k]->text[0] = '\0';
1416 chyron->key[k]->keycode = kc;
1417 chyron->key[k]->cp = cp_nt_rev;
1418}
1419/** unset_chyron_key
1420 @brief Unset chyron key
1421 @ingroup Chyron
1422 @param chyron structure
1423 @param k chyron_key index
1424*/
1425void unset_chyron_key(Chyron *chyron, int k) { chyron->key[k]->text[0] = '\0'; }
1426/** compile_chyron
1427 @brief construct the chyron string from the chyron structure
1428 @ingroup Chyron
1429 @param chyron
1430 @details The chyron string is constructed by concatenating the labels of the
1431 set keys, separated by " | ". The end_pos values for each key are set to
1432 determine the zones for mouse clicks. When a mouse click occurs, the
1433 get_chyron_key function uses the end_pos values to determine which key was
1434 clicked based on the X position of the click.
1435*/
1436void compile_chyron(Chyron *chyron) {
1437 int end_pos = 0;
1438 int k = 0;
1439 int pos = 0;
1440 int cp = cp_nt_rev;
1441 cchar_t *cx;
1442 while (k < CHYRON_KEYS) {
1443 if (chyron->key[k]->text[0] == '\0') {
1444 k++;
1445 continue;
1446 }
1447 if (end_pos == 0) {
1448 cx = chyron->cmplx_buf;
1449 mb_to_cc(cx, " ", WA_NORMAL, cp_nt_rev, &pos, MAXLEN - 1);
1450 } else {
1451 mb_to_cc(chyron->cmplx_buf, "|", WA_NORMAL, cp_nt_rev, &pos,
1452 MAXLEN - 1);
1453 }
1454 cx = chyron->cmplx_buf;
1455 cp = chyron->key[k]->cp;
1456 mb_to_cc(cx, chyron->key[k]->text, WA_NORMAL, cp, &pos, MAXLEN - 1);
1457 end_pos = pos;
1458 chyron->l = end_pos;
1459 chyron->key[k]->end_pos = end_pos;
1460 k++;
1461 }
1462 mb_to_cc(chyron->cmplx_buf, " ", WA_NORMAL, cp, &pos, MAXLEN - 1);
1463 chyron->l = end_pos;
1464}
1465/** display_chyron
1466 @brief Display chyron on window
1467 @ingroup Chyron
1468 @param win NCurses window to display chyron on
1469 @param chyron Chyron structure containing the compiled chyron string
1470 @param line Line number to display the chyron on
1471 @param col Column number to start displaying the chyron from
1472 @details This function clears the line where the chyron will be displayed,
1473 then uses wadd_wchstr to add the compiled chyron string (cmplx_buf) to the
1474 window. Finally, it moves the cursor to the specified column position.
1475*/
1476void display_chyron(WINDOW *win, Chyron *chyron, int line, int col) {
1477 wmove(win, line, 0);
1478 wclrtoeol(win);
1479 wmove(win, line, 0);
1480 wadd_wchstr(win, chyron->cmplx_buf);
1481 wmove(win, line, col);
1482 return;
1483}
1484/** get_chyron_key
1485 @brief Get keycode from chyron
1486 @ingroup Chyron
1487 @param chyron structure
1488 @param x Mouse X position
1489 @return Keycode
1490 @details This function uses the end_pos values set in compile_chyron
1491 to determine which key was clicked.
1492 The chyron functions provide xwgetch() with a mechanism to translate
1493 mouse click positions into key codes based on the labels set in the chyron
1494 structure. When a mouse click occurs, xwgetch() can call get_chyron_key()
1495 with the X position of the click to determine which function key was clicked,
1496 allowing for dynamic and customizable function key behavior in the chyron
1497 area of the interface.
1498*/
1499int get_chyron_key(Chyron *chyron, int x) {
1500 int i;
1501 for (i = 0; chyron->key[i]->end_pos != -1; i++)
1502 if (x < chyron->key[i]->end_pos)
1503 break;
1504 return chyron->key[i]->keycode;
1505}
1506
1507/** mvwaddstr_fill
1508 @brief For lines shorter than their display area, fill the rest with spaces
1509 @ingroup window_support
1510 @param w Pointer to window
1511 @param y Y coordinate
1512 @param x X coordinate
1513 @param s String to display
1514 @param l Length of display area */
1515void mvwaddstr_fill(WINDOW *w, int y, int x, char *s, int l) {
1516 char *d, *e;
1517 char tmp_str[MAXLEN];
1518
1519 l = min(l, MAXLEN - 1);
1520 e = d = tmp_str;
1521 e += l;
1522 while (d < e) {
1523 if (*s == '\0' || *s == '\n')
1524 *d++ = ' ';
1525 else
1526 *d++ = *s++;
1527 }
1528 *d = '\0';
1529 mvwaddstr(w, y, x, tmp_str);
1530}
1531/** clr_name_to_idx
1532 @brief Get color index from color name
1533 @ingroup color_management
1534 @param s Color name
1535 @return Color index or -1 if not found */
1536int clr_name_to_idx(char *s) {
1537 int i = 0;
1538 int n = 16;
1539
1541 while (i < n) {
1542 if (!strcmp(colors_text[i], s))
1543 break;
1544 i++;
1545 }
1546 if (i >= n)
1547 return (-1);
1548 return (i);
1549}
1550/** list_colors
1551 @brief list colors to stderr
1552 @ingroup color_management
1553 @details only lists the first 16, since that's how many we let the
1554 user redefine */
1556 int i, col;
1557
1558 for (i = 0, col = 0; i < 16; i++, col++) {
1559 if (i < 8) {
1560 fprintf(stderr, " ");
1561 }
1562 if (i == 8) {
1563 col = 0;
1564 fprintf(stderr, "\n");
1565 } else if (col > 0)
1566 fprintf(stderr, " ");
1567 fprintf(stderr, "%s", colors_text[i]);
1568 }
1569 fprintf(stderr, "\n");
1570}
1571/** nf_error
1572 @brief Display error message and wait for key press
1573 @ingroup error_handling
1574 @param ec Error code
1575 @param s Error message */
1576int nf_error(int ec, char *s) {
1577 fprintf(stderr, "ERROR: %s code: %d\n", s, ec);
1578 fprintf(stderr, "Press a key to continue");
1579 di_getch();
1580 fprintf(stderr, "\n");
1581 return ec;
1582}
1583/** abend
1584 @brief Abnormal program termination
1585 @ingroup error_handling
1586 @param ec Exit code
1587 @param s Error message */
1588void abend(int ec, char *s) {
1592 fprintf(stderr, "\n\nABEND: %s (code: %d)\n", s, ec);
1593 exit(EXIT_FAILURE);
1594}
1595/** waitpid_with_timeout
1596 @brief Wait for a process to finish with a timeout and optional user
1597 cancellation
1598 @ingroup error_handling
1599 @param pid Process ID to wait for
1600 @param timeout Time in seconds to wait before timing out
1601 @return true if the process finished, false if it timed out or was cancelled
1602 */
1603bool waitpid_with_timeout(pid_t pid, int timeout) {
1604 int status;
1605 Chyron *wait_chyron;
1606 WINDOW *wait_win;
1607 int remaining = timeout;
1608
1609 waitpid(pid, &status, WNOHANG);
1610 if (WIFEXITED(status) || WIFSIGNALED(status))
1611 return true;
1612 usleep(100000); // Sleep for 200ms */
1613 wait_chyron = wait_mk_chyron();
1614 ssnprintf(em0, MAXLEN - 1, "Waiting for process %d to finish...", pid);
1615 wait_win = wait_mk_win(wait_chyron, em0);
1616 cmd_key = 0;
1617 while (remaining > 0 && cmd_key != KEY_F(9)) {
1618 cmd_key = wait_continue(wait_win, wait_chyron, remaining);
1619 if (cmd_key == KEY_F(9))
1620 break;
1621 remaining--;
1622 waitpid(pid, &status, WNOHANG);
1623 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1624 wait_destroy(wait_chyron);
1625 return true;
1626 }
1627 }
1628 wait_destroy(wait_chyron);
1629 return false;
1630}
1631/** xwgetch
1632 @brief Wrapper for wgetch that handles signals, mouse events, checks for
1633 clicks on the chyron line, and accepts a sinigle character answer
1634 @ingroup window_support
1635 @param win Pointer to window
1636 @param chyron Pointer to chyron struct
1637 @param n Number of seconds to wait before timing out
1638 @verbatim
1639
1640 0: Wait indefinitely for user input (raw mode)
1641 accept a single character answer, and don't wait for Enter key
1642 1: Wait for 1 decisecond
1643 n > 1: Wait for n/10 seconds
1644
1645 @endverbatim
1646 @return Key code or ERR if interrupted by signal
1647 @details Get mouse event and check if it's a left click or double click. If
1648 the click is outside the window, ignore it. If it's on the chyron line, get
1649 the corresponding key command. Otherwise, store the click coordinates as
1650 click_y and click_x for later use. */
1651int xwgetch(WINDOW *win, Chyron *chyron, int n) {
1652 int c;
1653 MEVENT event;
1654 mousemask(BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON4_PRESSED |
1655 BUTTON5_PRESSED,
1656 nullptr);
1657 click_y = event.y = -1;
1658 click_x = event.x = -1;
1659
1660 if (n == -1) {
1661 struct termios raw_tioctl;
1662 raw_tioctl = curses_tioctl;
1663 mk_raw_tioctl(&raw_tioctl);
1664 } else if (n == 0)
1665 halfdelay(1);
1666 else
1667 halfdelay(min(255, max(0, n * 10)));
1668 tcflush(2, TCIFLUSH);
1669 curs_set(1);
1670 do {
1671 c = wgetch(win);
1672 if (sig_received != 0) {
1675 if (c == 'q' || c == 'Q' || c == KEY_F(9))
1676 exit(EXIT_FAILURE);
1677 }
1678 if (n > 0 && c == ERR) {
1679 c = 0;
1680 break;
1681 }
1682 if (c == ERR)
1683 continue;
1684 if (c == KEY_MOUSE) {
1685 if (getmouse(&event) != OK) {
1686 c = 0;
1687 continue;
1688 }
1689 if (event.bstate & BUTTON4_PRESSED) {
1690 curs_set(0);
1691 return KEY_UP;
1692 } else if (event.bstate & BUTTON5_PRESSED) {
1693 curs_set(0);
1694 return KEY_DOWN;
1695 }
1696 if (event.bstate & BUTTON1_CLICKED ||
1697 event.bstate & BUTTON1_DOUBLE_CLICKED) {
1698 if (wenclose(win, event.y, event.x)) {
1699 wmouse_trafo(win, &event.y, &event.x, false);
1700 click_y = event.y;
1701 click_x = event.x;
1702 if (chyron && event.y == getmaxy(win) - 1) {
1703 c = get_chyron_key(chyron, event.x);
1704 break;
1705 }
1706 }
1707 c = ERR;
1708 continue;
1709 }
1710 }
1711 } while (c == ERR);
1712 curs_set(0);
1714 return c;
1715}
1716/** dxwgetch
1717 This is a version of xwgetch that checks for mouse clicks in two windows.
1718 Sets mouse_win to the window that was clicked and click_y and click_x to the
1719 coordinates of the click. If the click is in the chyron line of the second
1720 window, it gets the corresponding key command. Otherwise, it stores the click
1721 coordinates and returns 0.
1722 */
1723int dxwgetch(WINDOW *win, WINDOW *win2, Chyron *chyron, int n) {
1724 int c;
1725 MEVENT event;
1726 mousemask(BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON4_PRESSED |
1727 BUTTON5_PRESSED,
1728 nullptr);
1729 click_y = event.y = -1;
1730 click_x = event.x = -1;
1731
1732 if (n == -1) {
1733 struct termios raw_tioctl;
1734 raw_tioctl = curses_tioctl;
1735 mk_raw_tioctl(&raw_tioctl);
1736 } else if (n == 0)
1737 halfdelay(1);
1738 else
1739 halfdelay(min(255, max(0, n * 10)));
1740 tcflush(2, TCIFLUSH);
1741 curs_set(1);
1742 do {
1743 c = wgetch(win);
1744 if (sig_received != 0) {
1747 if (c == 'q' || c == 'Q' || c == KEY_F(9))
1748 exit(EXIT_FAILURE);
1749 }
1750 if (n > 0 && c == ERR) {
1751 c = 0;
1752 break;
1753 }
1754 if (c == ERR)
1755 continue;
1756 if (c == KEY_MOUSE) {
1757 if (getmouse(&event) != OK) {
1758 c = 0;
1759 continue;
1760 }
1761 if (event.bstate & BUTTON4_PRESSED) {
1762 curs_set(0);
1763 return KEY_UP;
1764 } else if (event.bstate & BUTTON5_PRESSED) {
1765 curs_set(0);
1766 return KEY_DOWN;
1767 }
1768 if (event.bstate & BUTTON1_CLICKED ||
1769 event.bstate & BUTTON1_DOUBLE_CLICKED) {
1770 // Check if the click is in win or win2, and set mouse_win
1771 // accordingly
1772 // don't free mouse_win, since it is borrowed
1774 if (wenclose(win, event.y, event.x)) {
1775 if (wmouse_trafo(win, &event.y, &event.x, false))
1776 mouse_win = win;
1777 } else if (win2 != nullptr &&
1778 wenclose(win2, event.y, event.x) &&
1779 wmouse_trafo(win2, &event.y, &event.x, false))
1780 mouse_win = win2;
1781 click_y = event.y;
1782 click_x = event.x;
1783 if (mouse_win == nullptr) {
1784 c = 0;
1785 break;
1786 }
1787 if (chyron && event.y == getmaxy(mouse_win) - 1)
1788 c = get_chyron_key(chyron, event.x);
1789 break;
1790 }
1791 }
1792 } while (c == ERR);
1793 curs_set(0);
1795 return c;
1796}
volatile sig_atomic_t sig_received
Definition sig.c:31
bool handle_signal(sig_atomic_t)
#define BW_RBL
Definition cm.h:488
#define MAXWIN
Definition cm.h:542
#define BW_DA
Definition cm.h:499
#define BW_LAN
Definition cm.h:501
#define BW_HO
Definition cm.h:480
#define BW_VE
Definition cm.h:481
bool f_curses_open
Definition sig.c:33
#define BW_LT
Definition cm.h:490
#define BW_RTR
Definition cm.h:487
#define CHYRON_KEYS
Definition cm.h:266
struct termios shell_tioctl curses_tioctl
Definition scriou.c:34
#define BW_RT
Definition cm.h:492
#define BW_UA
Definition cm.h:498
#define BW_RAN
Definition cm.h:500
#define CHYRON_KEY_MAXLEN
Definition cm.h:263
#define BW_SP
Definition cm.h:495
#define BW_RBR
Definition cm.h:489
@ CLR_FG
Definition cm.h:141
@ CLR_RED
Definition cm.h:125
@ CLR_NT_FG
Definition cm.h:146
@ CLR_YELLOW
Definition cm.h:127
@ CLR_BCYAN
Definition cm.h:138
@ CLR_WHITE
Definition cm.h:131
@ CLR_MAGENTA
Definition cm.h:129
@ CLR_NT_REV_BG
Definition cm.h:149
@ CLR_BLACK
Definition cm.h:124
@ CLR_BWHITE
Definition cm.h:139
@ CLR_LN_BG
Definition cm.h:145
@ CLR_NT_HL_REV_BG
Definition cm.h:153
@ CLR_BO
Definition cm.h:143
@ CLR_BBLACK
Definition cm.h:132
@ CLR_NT_HL_FG
Definition cm.h:150
@ CLR_BBLUE
Definition cm.h:136
@ CLR_LN
Definition cm.h:144
@ CLR_BGREEN
Definition cm.h:134
@ CLR_BYELLOW
Definition cm.h:135
@ CLR_BMAGENTA
Definition cm.h:137
@ CLR_BORANGE
Definition cm.h:140
@ CLR_NT_HL_BG
Definition cm.h:151
@ CLR_NT_HL_REV_FG
Definition cm.h:152
@ CLR_BG
Definition cm.h:142
@ CLR_NT_BG
Definition cm.h:147
@ CLR_BRED
Definition cm.h:133
@ CLR_NCOLORS
Definition cm.h:154
@ CLR_BLUE
Definition cm.h:128
@ CLR_GREEN
Definition cm.h:126
@ CLR_NT_REV_FG
Definition cm.h:148
@ CLR_CYAN
Definition cm.h:130
#define BW_LA
Definition cm.h:497
#define BW_RA
Definition cm.h:496
#define nullptr
Definition cm.h:25
#define min(x, y)
min macro evaluates two expressions, returning least result
Definition cm.h:56
#define BW_RTL
Definition cm.h:486
#define max(a, b)
max macro evaluates two expressions, returning greatest result.
Definition cm.h:49
#define TRUE
Definition iloan.c:19
#define MAXLEN
Definition curskeys.c:15
int box_attr
Definition dwin.c:129
int cp_box
Definition dwin.c:147
unsigned int cmd_key
Definition dwin.c:126
WINDOW * win
Definition dwin.c:121
const wchar_t bw_rt
Definition dwin.c:103
const wchar_t bw_ho
Definition dwin.c:96
int cp_nt
Definition dwin.c:148
int cp_nt_hl
Definition dwin.c:150
cchar_t CCC_LN
Definition dwin.c:164
int cp_win
Definition dwin.c:146
int clr_pair_cnt
Definition dwin.c:155
WINDOW * win_win[MAXWIN]
Definition dwin.c:122
int pipe_in
Definition dwin.c:168
const wchar_t bw_tl
Definition dwin.c:98
const wchar_t bw_ua
Definition dwin.c:107
bool f_sigwench
Definition dwin.c:127
char em1[MAXLEN]
Definition dwin.c:142
int m_cols
Definition dwin.c:132
int tty_fd
Definition dwin.c:168
RGB StdColors[16]
Definition dwin.c:85
WINDOW * win_win2[MAXWIN]
Definition dwin.c:123
cchar_t CCC_WIN
Definition dwin.c:157
int clr_cnt
Definition dwin.c:153
int m_begy
Definition dwin.c:133
int m_begx
Definition dwin.c:134
int stdout_fd
Definition dwin.c:137
const wchar_t bw_lan
Definition dwin.c:110
WINDOW * mouse_win
Definition dwin.c:77
const wchar_t bw_tr
Definition dwin.c:99
double BLUE_GAMMA
Definition dwin.c:118
int clr_pair_idx
Definition dwin.c:154
const wchar_t bw_ran
Definition dwin.c:109
const wchar_t bw_sp
Definition dwin.c:104
cchar_t CCC_BG
Definition dwin.c:158
const wchar_t bw_ra
Definition dwin.c:105
int dxwgetch(WINDOW *win, WINDOW *win2, Chyron *chyron, int n)
Definition dwin.c:1723
int mouse_support
Definition dwin.c:135
int cp_ln
Definition dwin.c:152
const wchar_t bw_da
Definition dwin.c:108
int m_lines
Definition dwin.c:131
const wchar_t bw_lt
Definition dwin.c:102
SCREEN * screen
Definition dwin.c:79
const wchar_t bw_la
Definition dwin.c:106
int click_x
Definition dwin.c:49
int cp_nt_hl_rev
Definition dwin.c:151
int src_line
Definition dwin.c:138
char * src_name
Definition dwin.c:139
cchar_t CCC_BOX
Definition dwin.c:159
SIO * sio
Definition dwin.c:80
cchar_t CCC_NT_HL_REV
Definition dwin.c:162
const wchar_t bw_bl
Definition dwin.c:100
int win_ptr
Definition dwin.c:130
FILE * ncurses_fp
Definition dwin.c:169
int exit_code
Definition dwin.c:125
int click_y
Definition dwin.c:48
int stdin_fd
Definition dwin.c:136
char em0[MAXLEN]
Definition dwin.c:141
cchar_t CCC_NT_HL
Definition dwin.c:163
double GRAY_GAMMA
Definition dwin.c:112
char em3[MAXLEN]
Definition dwin.c:144
double RED_GAMMA
Definition dwin.c:114
char const colors_text[][10]
Color names for .minitrc overrides.
Definition dwin.c:91
const wchar_t bw_ve
Definition dwin.c:97
int cp_nt_rev
Definition dwin.c:149
cchar_t CCC_BRKTR
Definition dwin.c:166
int pipe_out
Definition dwin.c:168
double GREEN_GAMMA
Definition dwin.c:116
cchar_t CCC_NORM
Definition dwin.c:156
int win_attr
Definition dwin.c:128
WINDOW * win_box[MAXWIN]
Definition dwin.c:124
char fn[MAXLEN]
Definition dwin.c:140
cchar_t CCC_NT_REV
Definition dwin.c:161
char em2[MAXLEN]
Definition dwin.c:143
int cp_norm
Definition dwin.c:145
cchar_t CCC_NT
Definition dwin.c:160
const wchar_t bw_br
Definition dwin.c:101
cchar_t CCC_BRKTL
Definition dwin.c:165
bool open_curses(SIO *)
Initialize NCurses and color settings.
Definition dwin.c:192
int xwgetch(WINDOW *, Chyron *, int)
Wrapper for wgetch that handles signals, mouse events, checks for clicks on the chyron line,...
Definition dwin.c:1651
int box_new(int, int, int, int, char *, bool)
Create a new window with optional box and title.
Definition dwin.c:745
int box2_new(int, int, int, int, char *, bool)
Create a new window with optional box and title.
Definition dwin.c:697
void restore_wins()
Restore all windows after a screen resize.
Definition dwin.c:933
void win_init_attrs()
Initialize window attributes.
Definition dwin.c:176
WINDOW * win_del()
Delete the current window and its associated box window.
Definition dwin.c:893
void mvwaddstr_fill(WINDOW *, int, int, char *, int)
For lines shorter than their display area, fill the rest with spaces.
Definition dwin.c:1515
int win2_new(int wlines, int wcols, int wbegy, int wbegx)
Create a new window with specified dimensions and position.
Definition dwin.c:814
void cbox(WINDOW *)
Draw a box around the specified window.
Definition dwin.c:957
int win_new(int, int, int, int)
Create a new window with specified dimensions and position.
Definition dwin.c:788
void cbox2(WINDOW *)
Draw a box with a separator line around the specified window.
Definition dwin.c:989
void win_resize(int, int, char *)
Resize the current window and its box, and update the title.
Definition dwin.c:841
void destroy_curses()
Gracefully shut down NCurses and restore terminal settings.
Definition dwin.c:540
void win_redraw(WINDOW *)
Redraw the specified window.
Definition dwin.c:881
void display_cmplx_str(WINDOW *win, cchar_t *cmplx_buf, int line, int col)
Display a complex character string on a window.
Definition dwin.c:678
RGB xterm256_idx_to_rgb(int)
Convert XTerm 256 color index to RGB color.
Definition dwin.c:366
int clr_name_to_idx(char *)
Get color index from color name.
Definition dwin.c:1536
void list_colors()
list colors to stderr
Definition dwin.c:1555
int rgb_to_curses_clr(RGB *)
Get color index for RGB color.
Definition dwin.c:315
size_t mk_cmplx_str(cchar_t *cmplx_buf, char *s, attr_t attr, int cp)
Convert a multibyte string to an array of cchar_t complex characters.
Definition dwin.c:648
void init_hex_clr(int, char *)
Initialize extended ncurses color from HTML style hex string.
Definition dwin.c:508
bool init_clr_palette(SIO *)
Initialize color palette based on SIO settings.
Definition dwin.c:429
RGB hex_clr_str_to_rgb(char *)
Convert six-digit HTML style hex color code to RGB struct.
Definition dwin.c:526
void apply_gamma(RGB *)
Apply gamma correction to RGB color.
Definition dwin.c:401
int rgb_to_xterm256_idx(RGB *)
Convert RGB color to XTerm 256 color index.
Definition dwin.c:344
cchar_t mkccc(int, attr_t, char *)
Create a cchar_t with the specified color pair index.
Definition dwin.c:625
int get_clr_pair(int fg, int bg)
Get color pair index for foreground and background colors.
Definition dwin.c:284
bool wait_destroy(Chyron *)
Destroy the waiting message window and chyron.
Definition dwin.c:1258
bool waitpid_with_timeout(pid_t pid, int timeout)
Wait for a process to finish with a timeout and optional user cancellation.
Definition dwin.c:1603
bool action_disposition(char *title, char *action_str)
Display a simple action disposition message window or print to stderr.
Definition dwin.c:1286
int nf_error(int, char *)
Display error message and wait for key press.
Definition dwin.c:1576
int wait_continue(WINDOW *, Chyron *, int)
Update the waiting message with remaining time and check for user input.
Definition dwin.c:1271
int answer_yn(char *em0, char *em1, char *em2, char *em3)
Accept a single letter answer.
Definition dwin.c:1041
WINDOW * wait_mk_win(Chyron *, char *)
Display a popup waiting message.
Definition dwin.c:1226
int Perror(char *)
Display a simple error message window or print to stderr.
Definition dwin.c:1162
int display_error(char *em0, char *em1, char *em2, char *em3)
Display an error message window or print to stderr.
Definition dwin.c:1102
void abend(int, char *)
Abnormal program termination.
Definition dwin.c:1588
Chyron * wait_mk_chyron()
Create a Chyron struct for the waiting message.
Definition dwin.c:1214
bool is_set_chyron_key(Chyron *, int)
Check if function key label is set.
Definition dwin.c:1372
void set_chyron_key(Chyron *, int, char *, int)
Set chyron key with default color pair (cp_nt_rev).
Definition dwin.c:1411
void display_chyron(WINDOW *win, Chyron *chyron, int line, int col)
Display chyron on window.
Definition dwin.c:1476
Chyron * destroy_chyron(Chyron *chyron)
Destroy Chyron structure.
Definition dwin.c:1352
int get_chyron_key(Chyron *, int)
Get keycode from chyron.
Definition dwin.c:1499
void set_chyron_key_cp(Chyron *, int, char *, int, int)
Set chyron key with color pair (cp).
Definition dwin.c:1388
void compile_chyron(Chyron *)
construct the chyron string from the chyron structure
Definition dwin.c:1436
void unset_chyron_key(Chyron *, int)
Unset chyron key.
Definition dwin.c:1425
int mb_to_cc(cchar_t *, char *, attr_t, int, int *, int)
Convert multibyte string to complex character array.
Definition dwin.c:582
Chyron * new_chyron()
Create and initialize Chyron structure.
Definition dwin.c:1336
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:435
bool str_to_lower(char *)
Converts a string to lowercase.
Definition futil.c:399
size_t strnz(char *, size_t)
terminates string at New Line, Carriage Return, or max_len
Definition futil.c:506
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:311
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
Definition futil.c:464
char di_getch()
get single character from terminal in raw mode
Definition scriou.c:148
bool restore_curses_tioctl()
restore_curses_tioctl() - restore curses terminal settings
Definition scriou.c:81
bool mk_raw_tioctl(struct termios *)
mk_raw_tioctl() - set terminal to raw mode
Definition scriou.c:126
bool restore_shell_tioctl()
restore_shell_tioctl() - restore shell terminal settings
Definition scriou.c:56
void sig_dfl_mode()
Set signal handlers to default behavior.
Definition sig.c:42
char text[CHYRON_KEY_MAXLEN]
Definition cm.h:269
int end_pos
Definition cm.h:272
int cp
Definition cm.h:273
int keycode
Definition cm.h:271
int l
Definition cm.h:280
cchar_t cmplx_buf[MAXLEN]
Definition cm.h:279
ChyronKey * key[CHYRON_KEYS]
Definition cm.h:277
int r
Definition cm.h:305
int b
Definition cm.h:307
int g
Definition cm.h:306
char nt_hl_rev_bg[COLOR_LEN]
Definition cm.h:735
double green_gamma
Definition cm.h:698
char nt_rev_bg[COLOR_LEN]
Definition cm.h:729
char black[COLOR_LEN]
Definition cm.h:701
char bg_clr_x[COLOR_LEN]
Definition cm.h:722
char fg_clr_x[COLOR_LEN]
Definition cm.h:721
double blue_gamma
Definition cm.h:699
char bred[COLOR_LEN]
Definition cm.h:711
char yellow[COLOR_LEN]
Definition cm.h:704
char nt_hl_bg[COLOR_LEN]
Definition cm.h:731
char nt_hl_fg[COLOR_LEN]
Definition cm.h:730
char bo_clr_x[COLOR_LEN]
Definition cm.h:723
char bcyan[COLOR_LEN]
Definition cm.h:716
char borange[COLOR_LEN]
Definition cm.h:718
double red_gamma
Definition cm.h:697
char red[COLOR_LEN]
Definition cm.h:702
char nt_fg[COLOR_LEN]
Definition cm.h:726
char magenta[COLOR_LEN]
Definition cm.h:706
char bgreen[COLOR_LEN]
Definition cm.h:712
char nt_rev_fg[COLOR_LEN]
Definition cm.h:728
char ln_clr_x[COLOR_LEN]
Definition cm.h:724
char byellow[COLOR_LEN]
Definition cm.h:713
char bwhite[COLOR_LEN]
Definition cm.h:717
char ln_bg_clr_x[COLOR_LEN]
Definition cm.h:725
char cyan[COLOR_LEN]
Definition cm.h:707
char tty_name[MAXLEN]
Definition cm.h:736
char green[COLOR_LEN]
Definition cm.h:703
char white[COLOR_LEN]
Definition cm.h:708
char bblue[COLOR_LEN]
Definition cm.h:714
char bmagenta[COLOR_LEN]
Definition cm.h:715
char blue[COLOR_LEN]
Definition cm.h:705
char nt_hl_rev_fg[COLOR_LEN]
Definition cm.h:733
double gray_gamma
Definition cm.h:700
char bblack[COLOR_LEN]
Definition cm.h:710
char nt_bg[COLOR_LEN]
Definition cm.h:727