C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
ui_ncurses.c
Go to the documentation of this file.
1/** @file ui_ncurses.c
2 @ingroup ui_ncurses
3 @brief NCurses UI backend — lifecycle, surface management, and capabilities.
4
5 Implements all UiRuntime and UiSurface operations declared in ui_backend.h
6 using the NCurses / panelw library.
7
8 When compiled as part of the main C-Menu build (UAL_LEGACY_COMPAT defined),
9 the legacy globals @c screen and @c tty_fp from dwin.c are kept in sync so
10 that code not yet migrated to the UAL API continues to work.
11*/
12
13#define _XOPEN_SOURCE_EXTENDED 1
14
15#include "cm.h"
16
18#ifdef UAL_LEGACY_COMPAT
19#include "ui_ncurses_compat.h"
20#endif
21#include <locale.h>
22#include <stdint.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26
27/** @defgroup ui_ncurses
28 @ingroup ui_backend
29 @brief NCurses UI backend — lifecycle, surface management, and capabilities.
30
31 Implements all UiRuntime and UiSurface operations declared in ui_backend.h
32 using the NCurses / panelw library.
33
34 When compiled as part of the main C-Menu build (UAL_LEGACY_COMPAT defined),
35 the legacy globals @c screen and @c tty_fp from dwin.c are kept in sync so
36 that code not yet migrated to the UAL API continues to work.
37*/
38
39UiRuntime *ui = NULL;
41
42int sfc_ptr = -1;
43uint ui_color_cnt = 0;
44uint ui_pair_cnt = 0;
45
46UiSurface *stdsfc;
47
48/* -------------------------------------------------------------------------
49 Backend identification and capability query
50 ------------------------------------------------------------------------- */
51/** @brief Get the UI backend type.
52 * @ingroup ui_ncurses
53 * @return The UI backend type, which is always UI_BACKEND_NCURSES for this implementation.
54 */
55UiBackend ui_get_backend() {
56 return UI_BACKEND_NCURSES;
57}
58/** @brief Get the UI backend capabilities.
59 *
60 * @param caps Pointer to a UiCaps struct to be filled with the backend capabilities.
61 */
62void ui_get_caps(UiCaps *caps) {
63 if (!caps)
64 return;
65 memset(caps, 0, sizeof(*caps));
66 if (!ui)
67 return;
68 // Will add code to actually check later. For now, just lie.
69 caps->truecolor = true;
70 caps->palette256 = true;
71 caps->mouse = ui->mouse_enabled;
72 caps->unicode = true;
73 caps->resize = true;
74 caps->color_pairs = 0;
75}
76
77/* -------------------------------------------------------------------------
78 Styles
79 ------------------------------------------------------------------------- */
80/** @brief Convert hex color strings to a curses color pair index.
81 *
82 * @param fg Foreground color in hex format (e.g., "#RRGGBB").
83 * @param bg Background color in hex format (e.g., "#RRGGBB").
84 * @return The curses color pair index corresponding to the given foreground and background colors.
85 */
86int ui_pair_from_hex(const char *fg, const char *bg) {
87 RGB rgb;
88 sscanf(fg, "#%02x%02x%02x", &rgb.r, &rgb.g, &rgb.b);
89 int f_idx = ui_color_from_rgb(&rgb);
90 sscanf(bg, "#%02x%02x%02x", &rgb.r, &rgb.g, &rgb.b);
91 int b_idx = ui_color_from_rgb(&rgb);
92 return ui_add_pair(f_idx, b_idx);
93}
94/** @brief Convert a Unicode code point to a curses UiCell with specified foreground and background colors.
95 *
96 * @param ucp Pointer to a wide character string containing the Unicode code point.
97 * @param fg Pointer to a 32-bit integer representing the foreground color in hex format (e.g., 0xRRGGBB).
98 * @param bg Pointer to a 32-bit integer representing the background color in hex format (e.g., 0xRRGGBB).
99 * @return A UiCell structure representing the Unicode character with the specified colors.
100 */
101UiCell ui_cell_from_ucp(const wchar_t *ucp, const uint32_t *fg, const uint32_t *bg) {
102 UiCell cc = {0};
103 RGB rgb;
104 rgb.r = (*fg >> 16) & 0xff;
105 rgb.g = (*fg >> 8) & 0xff;
106 rgb.b = *fg & 0xff;
107 int f_idx = ui_color_from_rgb(&rgb);
108 rgb.r = (*bg >> 16) & 0xff;
109 rgb.g = (*bg >> 8) & 0xff;
110 rgb.b = *bg & 0xff;
111 int b_idx = ui_color_from_rgb(&rgb);
112 short cp = ui_add_pair(f_idx, b_idx);
113 wchar_t wstr[2] = {L'\0', L'\0'};
114 wstr[0] = *ucp;
115 wstr[1] = L'\0';
116 setcchar(&cc, wstr, WA_NORMAL, cp, nullptr);
117 return cc;
118}
119
120/* -------------------------------------------------------------------------
121 Lifecycle
122 ------------------------------------------------------------------------- */
123/** @brief Initialize the UI runtime with the given configuration and SIO.
124 *
125 * @param cfg Pointer to a UiConfig structure containing the configuration settings.
126 * @param sio Pointer to an SIO structure for input/output operations.
127 * @return A pointer to the initialized UiRuntime structure, or NULL on failure.
128 */
129struct UiRuntime *ui_init(const UiConfig *cfg, SIO *sio) {
130 setlocale(LC_ALL, "en_US.UTF-8");
131 ui = calloc(1, sizeof(*ui));
132 if (!ui)
133 return NULL;
134 char tty_name[MAXLEN];
135 if (ttyname_r(STDERR_FILENO, tty_name, sizeof(tty_name)) != 0) {
136 free(ui);
137 return NULL;
138 }
139 ui->tty_fp = fopen(tty_name, "r+");
140 if (!ui->tty_fp) {
141 free(ui);
142 return NULL;
143 }
144 ui->tty_fd = fileno(ui->tty_fp);
146
147 ui_log(INFO, _("ui_init: using tty: %s"), tty_name);
148 ui->screen = newterm(NULL, ui->tty_fp, ui->tty_fp);
149 f_ncurses_open = true;
150 if (!ui->screen) {
151 fclose(ui->tty_fp);
152 free(ui);
153 return NULL;
154 }
155 set_term(ui->screen);
156 if (!has_colors() || !can_change_color()) {
158 return NULL;
159 }
160 start_color();
161 use_default_colors();
162 cbreak();
163 noecho();
164 keypad(stdscr, TRUE);
165 if (ui->mouse_enabled)
166 mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
167 getmaxyx(stdscr, ui->lines, ui->cols);
168
169 stdsfc = calloc(1, sizeof(*stdsfc));
170 if (!stdsfc)
171 return NULL;
172 stdsfc->runtime = ui;
173 stdsfc->parent = NULL;
174 stdsfc->meta[BOX].lines = (int)ui->lines;
175 stdsfc->meta[BOX].cols = (int)ui->cols;
176 stdsfc->meta[BOX].y = 0;
177 stdsfc->meta[BOX].x = 0;
178 stdsfc->mwin[BOX] = stdscr;
179 stdsfc->mpan[BOX] = new_panel(stdsfc->mwin[BOX]);
180 if (!stdsfc->mpan[BOX]) {
181 free(stdsfc);
182 ui_log(ERROR, _("new_panel failed for stdsfc->mpan[BOX]"));
183 exit(EXIT_FAILURE);
184 }
185 if (cfg->border_style)
186 ui->border_style = cfg->border_style;
187 if (!ui->border_style)
188 ui->border_style = UI_BORDER_ROUNDED;
189 if (cfg) {
190 switch (ui->border_style) {
191 case UI_BORDER_SINGLE:
192 memcpy(bw.str, border_single, sizeof(bw.str));
193 break;
194 case UI_BORDER_DOUBLE:
195 memcpy(bw.str, border_double, sizeof(bw.str));
196 break;
197 case UI_BORDER_ROUNDED:
198 memcpy(bw.str, border_rounded, sizeof(bw.str));
199 break;
200 case UI_BORDER_HEAVY:
201 memcpy(bw.str, border_heavy, sizeof(bw.str));
202 break;
203 case UI_BORDER_NONE:
204 memcpy(bw.str, border_none, sizeof(bw.str));
205 break;
206 default:
207 memcpy(bw.str, border_rounded, sizeof(bw.str));
208 break;
209 }
210 }
212 ui_log(INFO, _("ui_init: stdsfc->mwin[BOX]: %p, stdsfc->mpan[BOX]: %p"), (void *)stdsfc->mwin[BOX], (void *)stdsfc->mpan[BOX]);
213 return ui;
214}
215// -------------------------------------------------------------------------
216// Surface Creation and Destruction
217// -------------------------------------------------------------------------
218/** @brief Create a new UI surface with the specified parameters.
219 *
220 * @param w The index of the window within the surface.
221 * @param parent Pointer to the parent UiSurface, or NULL for a top-level surface.
222 * @param p The index of the parent window to derive from, if applicable.
223 * @param lines The number of lines (rows) for the new surface.
224 * @param cols The number of columns for the new surface.
225 * @param y The y-coordinate (row) for the new surface's position.
226 * @param x The x-coordinate (column) for the new surface's position.
227 * @return A pointer to the newly created UiSurface, or NULL on failure.
228 */
229UiSurface *ui_surface_new(ss_t w, UiSurface *parent, uint p, uint lines, uint cols, uint y, uint x) {
230 if (!ui)
231 return NULL;
232 uint maxy, maxx;
233 ui_get_screen_size(&maxy, &maxx);
234 if (lines > maxy || cols > maxx) {
235 ssnprintf(em0, MAXLEN - 1, _("%s, line: %d"), __FILE__, __LINE__ - 1);
236 ssnprintf(em1, MAXLEN - 1, _("ui_surface_new failed for lines: %d, cols: %d"), lines, cols);
237 ssnprintf(em2, MAXLEN - 1, _("maxy: %d, maxx: %d"), maxy, maxx);
239 return NULL;
240 }
241
242 UiSurface *s = calloc(1, sizeof(*s));
243 if (!s)
244 return NULL;
245 for (int i = 0; i < SUB_SFC_MAX; i++) {
246 s->mwin[i] = NULL;
247 s->mpan[i] = NULL;
248 }
249 s->runtime = ui;
250 s->parent = parent;
251 s->meta[w].lines = lines;
252 s->meta[w].cols = cols;
253 s->meta[w].y = y;
254 s->meta[w].x = x;
255
256 if (parent && parent->mwin[p]) {
257 s->mwin[w] = derwin(parent->mwin[p], lines, cols, y, x);
258 if (!s->mwin[w]) {
259 free(s);
260 return NULL;
261 }
262 } else {
263 s->mwin[w] = newwin(lines, cols, y, x);
264 if (!s->mwin[w]) {
265 free(s);
266 return NULL;
267 }
268 s->mpan[w] = new_panel(s->mwin[w]);
269 if (!s->mpan[w]) {
270 delwin(s->mwin[w]);
271 free(s);
272 return NULL;
273 }
274 }
275 return s;
276}
277/** @brief Create a new UI surface with a border box and optional title.
278 *
279 * @param parent Pointer to the parent UiSurface, or NULL for a top-level surface.
280 * @param p The index of the parent window to derive from, if applicable.
281 * @param lines The number of lines (rows) for the new surface.
282 * @param cols The number of columns for the new surface.
283 * @param y The y-coordinate (row) for the new surface's position.
284 * @param x The x-coordinate (column) for the new surface's position.
285 * @param wtitle The title string to display in the border box, or NULL for no title.
286 * @return A pointer to the newly created UiSurface with a border box, or NULL on failure.
287 */
288UiSurface *ui_surface_box(UiSurface *parent, uint p, uint lines, uint cols, uint y, uint x, const char *wtitle) {
289 if (!ui)
290 return NULL;
291 uint maxy, maxx;
292 ui_get_screen_size(&maxy, &maxx);
293 if (lines > maxy || cols > maxx) {
294 ssnprintf(em0, MAXLEN - 1, _("%s, line: %d"), __FILE__, __LINE__ - 1);
295 ssnprintf(em1, MAXLEN - 1, _("ui_surface_box failed for lines: %d, cols: %d"), lines, cols);
296 ssnprintf(em2, MAXLEN - 1, _("maxy: %d, maxx: %d"), maxy, maxx);
298 return NULL;
299 }
300 UiSurface *s = calloc(1, sizeof(*s));
301 if (!s)
302 return NULL;
303 s->runtime = ui;
304 s->parent = parent;
305 s->meta[BOX].y = y;
306 s->meta[BOX].x = x;
307 s->meta[BOX].lines = lines;
308 s->meta[BOX].cols = cols;
309 if (parent && parent->mwin[p]) {
310 s->mwin[BOX] = derwin(parent->mwin[p], lines, cols, y, x);
311 if (!s->mwin[BOX]) {
312 free(s);
313 return NULL;
314 }
315 } else {
316 s->mwin[BOX] = newwin(lines, cols, y, x);
317 if (!s->mwin[BOX]) {
318 free(s);
319 return NULL;
320 }
321 s->mpan[BOX] = new_panel(s->mwin[BOX]);
322 if (!s->mpan[BOX]) {
323 delwin(s->mwin[BOX]);
324 return NULL;
325 }
326 }
327 ui_scrollok(s, BOX, false);
329 ui_border_title(s, wtitle);
330#ifdef DEBUG_UI
331 immedok(s->mwin[BOX], true);
332#endif
333 return s;
334}
335/** @brief Exit the UI application quickly, cleaning up resources.
336 *
337 * @param s Pointer to the UiSurface to be cleaned up before exiting.
338 */
339void fast_exit(UiSurface *s) {
340 update_panels();
341 doupdate();
342 for (int i = SUB_SFC_MAX; i >= 0; i--) {
343 if (s->mpan[i]) {
344 hide_panel(s->mpan[i]);
345 del_panel(s->mpan[i]);
346 s->mpan[i] = NULL;
347 }
348 }
349 for (int i = SUB_SFC_MAX; i >= 0; i--) {
350 if (s->mwin[i]) {
351 delwin(s->mwin[i]);
352 s->mwin[i] = NULL;
353 }
354 }
355 endwin();
356 exit(EXIT_SUCCESS);
357}
358/** @brief Add a new pad to the specified UiSurface.
359 *
360 * @param s Pointer to the UiSurface to which the pad will be added.
361 * @param w The index of the window within the surface where the pad will be created.
362 * @param view_win The index of the window that will be used to view the pad.
363 * @param lines The number of lines (rows) for the new pad.
364 * @param cols The number of columns for the new pad.
365 * @param begy The y-coordinate (row) for the new pad's position (ignored in this implementation).
366 * @param begx The x-coordinate (column) for the new pad's position (ignored in this implementation).
367 * @return 0 on success, or -1 on failure.
368 */
369int ui_surface_addpad(UiSurface *s, ss_t w, uint view_win, uint lines, uint cols, uint begy, uint begx) {
370 (void)begy;
371 (void)begx;
372 s->mwin[w] = newpad(lines, cols);
373 if (s->mwin[w] == nullptr)
374 return -1;
375 s->mwin[view_win] = subpad(s->mwin[PAD], lines, cols, 0, 0);
376 if (s->mwin[view_win] == nullptr)
377 return -1;
378 s->mpan[w] = new_panel(s->mwin[view_win]);
379 immedok(s->mwin[w], true);
380#ifdef DEBUG_UI
381#endif
382 return 0;
383}
384/** @brief Add a new window to the specified UiSurface.
385 *
386 * @param s Pointer to the UiSurface to which the window will be added.
387 * @param w The index of the window within the surface where the new window will be created.
388 * @param p The index of the parent window from which the new window will be derived.
389 * @param lines The number of lines (rows) for the new window.
390 * @param cols The number of columns for the new window.
391 * @param y The y-coordinate (row) for the new window's position relative to the parent window.
392 * @param x The x-coordinate (column) for the new window's position relative to the parent window.
393 * @return 0 on success, or -1 on failure.
394 */
395int ui_surface_addwin(UiSurface *s, ss_t w, uint p, uint lines, uint cols, uint y, uint x) {
396 s->mwin[w] = derwin(s->mwin[p], lines, cols, y, x);
397 if (!s->mwin[w]) {
398 free(s);
399 return -1;
400 }
401 s->mpan[w] = new_panel(s->mwin[w]);
402 keypad(s->mwin[w], true);
405 immedok(s->mwin[w], true);
406#ifdef DEBUG_UI
407#endif
408 return 0;
409}
410/** @brief End the UI application, cleaning up resources and shutting down the UI runtime.
411 */
412void ui_endwin() {
413 endwin();
414 // ui_shutdown();
415}
416/** @brief Shutdown the UI runtime, cleaning up resources and freeing memory.
417 */
419 if (ui == NULL)
420 return;
421 ui_log(INFO, _("ui_shutdown in progress..."));
422 while (sfc_ptr >= 0) {
423 if (ui_surface[sfc_ptr] != NULL) {
425 ui_surface[sfc_ptr] = NULL;
426 }
427 ui_log(INFO, _("surface destroy: %d"), sfc_ptr);
428 sfc_ptr--;
429 }
430 if (stdsfc->mpan[0] != NULL) {
431 ui_log(INFO, _("calling del_panel(stdsfc->mpan[BOX])"));
432 hide_panel(stdsfc->mpan[0]);
433 del_panel(stdsfc->mpan[0]);
434 stdsfc->mpan[0] = NULL;
435 }
436 ui_log(INFO, _("calling endwin()"));
437 endwin();
438 f_ncurses_open = false;
439 if (ui->screen != NULL) {
440 ui_log(INFO, _("calling delscreen(ui->screen)"));
441 delscreen(ui->screen);
442 ui->screen = NULL;
443 }
444 if (ui->tty_fp != NULL) {
445 ui_log(INFO, _("closing tty_fp"));
446 fclose(ui->tty_fp);
447 ui->tty_fp = NULL;
448 }
449 if (stdsfc != NULL) {
450 ui_log(INFO, _("freeing stdsfc"));
451 free(stdsfc);
452 stdsfc = NULL;
453 }
454 if (ui != NULL) {
455 if (ui->sio) {
456 free(ui->sio);
457 ui->sio = nullptr;
458 }
459 ui_log(INFO, _("freeing ui"));
460 free(ui);
461 ui = NULL;
462 }
463}
464/** @brief Destroy a UiSurface, cleaning up its windows and panels.
465 *
466 * @param s Pointer to the UiSurface to be destroyed.
467 */
468void ui_surface_destroy(UiSurface *s) {
469 if (!s)
470 return;
471 for (int i = SUB_SFC_MAX; i >= 0; i--) {
472 if (s->mpan[i] != NULL) {
473 hide_panel(s->mpan[i]);
475 del_panel(s->mpan[i]);
476 s->mpan[i] = NULL;
477 }
478 }
479 for (int i = SUB_SFC_MAX; i >= 0; i--) {
480 if (s->mwin[i] != NULL) {
481 delwin(s->mwin[i]);
482 s->mwin[i] = NULL;
483 }
484 }
485 if (s != NULL) {
486 free(s);
487 s = NULL;
488 }
489}
490/** @brief Suspend the UI, saving the current program state and ending the window session.
491 *
492 * @return 0 on success, or -1 on failure.
493 */
495 def_prog_mode();
496 endwin();
497 return 0;
498}
499/** @brief Resume the UI, restoring the previous program state and updating the display.
500 *
501 * @return 0 on success, or -1 on failure.
502 */
504 reset_prog_mode();
505 update_panels();
506 doupdate();
507 return 0;
508}
509
510// -------------------------------------------------------------------------
511// Surface Management
512// -------------------------------------------------------------------------
513/** @brief Move a UiSurface to a new position on the screen.
514 *
515 * @param s Pointer to the UiSurface to be moved.
516 * @param w The index of the window within the surface to be moved.
517 * @param y The new y-coordinate (row) for the surface's position.
518 * @param x The new x-coordinate (column) for the surface's position.
519 * @return 0 on success, or -1 on failure.
520 */
521int ui_surface_move(UiSurface *s, ss_t w, uint y, uint x) {
522 if (!s)
523 return -1;
524 s->meta[w].y = y;
525 s->meta[w].x = x;
526 return move_panel(s->mpan[w], y, x);
527}
528/** @brief Resize a UiSurface to new dimensions.
529 *
530 * @param s Pointer to the UiSurface to be resized.
531 * @param w The index of the window within the surface to be resized.
532 * @param lines The new number of lines (rows) for the surface.
533 * @param cols The new number of columns for the surface.
534 * @return 0 on success, or -1 on failure.
535 */
536int ui_surface_resize(UiSurface *s, ss_t w, uint lines, uint cols) {
537 if (!s)
538 return -1;
539 s->meta[w].lines = lines;
540 s->meta[w].cols = cols;
541 wresize(s->mwin[w], lines + 2, cols + 2);
542 wresize(s->mwin[w + 1], lines, cols);
543 return 0;
544}
545/** @brief Erase the contents of a UiSurface or all surfaces.
546 *
547 * @param s Pointer to the UiSurface to be erased, or NULL to erase all surfaces.
548 * @param w The index of the window within the surface to be erased, or ALLWINS to erase all windows.
549 * @return 0 on success, or -1 on failure.
550 */
551int ui_werase(UiSurface *s, ss_t w) {
552 if (w == ALLWINS) {
553 for (int i = 1; i < SUB_SFC_MAX; i++) {
554 if (s->mwin[i]) {
555 werase(s->mwin[i]);
556 }
557 }
558 } else {
559 if (s->mwin[w]) {
560 werase(s->mwin[w]);
561 }
562 }
563 return 0;
564}
565/** @brief Clear the contents of a UiSurface or all surfaces.
566 *
567 * @param s Pointer to the UiSurface to be cleared, or NULL to clear all surfaces.
568 * @param w The index of the window within the surface to be cleared, or ALLWINS to clear all windows.
569 * @return 0 on success, or -1 on failure.
570 */
571int ui_wclear(UiSurface *s, ss_t w) {
572 if (!s)
573 return -1;
574 if (w == ALLWINS) {
575 for (int i = 1; i < SUB_SFC_MAX; i++) {
576 if (s->mwin[i]) {
577 wclear(s->mwin[i]);
578 }
579 }
580 } else {
581 if (s->mwin[w]) {
582 wclear(s->mwin[w]);
583 }
584 }
585 return 0;
586}
587/** @brief Erase the entire screen.
588 *
589 * @return 0 on success, or -1 on failure.
590 */
591int ui_erase() {
592 erase();
593 return 0;
594}
595/** @brief Clear the entire screen.
596 *
597 * @return 0 on success, or -1 on failure.
598 */
599int ui_clear() {
600 clear();
601 return 0;
602}
603/** @brief Show a UiSurface, making it visible on the screen.
604 *
605 * @param s Pointer to the UiSurface to be shown.
606 * @param w The index of the window within the surface to be shown.
607 * @return 0 on success, or -1 on failure.
608 */
609int ui_surface_show(UiSurface *s, ss_t w) {
610 if (!s)
611 return -1;
612 show_panel(s->mpan[w]);
613 s->meta[w].hidden = false;
614 return 0;
615 return 0;
616}
617/** @brief Hide a UiSurface, making it invisible on the screen.
618 *
619 * @param s Pointer to the UiSurface to be hidden.
620 * @param w The index of the window within the surface to be hidden.
621 * @return 0 on success, or -1 on failure.
622 */
623int ui_top_surface(UiSurface *s, ss_t w) {
624 if (!s)
625 return -1;
626 top_panel(s->mpan[w]);
627 return 0;
628}
629/** @brief Hide a UiSurface, making it invisible on the screen.
630 *
631 * @param s Pointer to the UiSurface to be hidden.
632 * @param w The index of the window within the surface to be hidden.
633 * @return 0 on success, or -1 on failure.
634 */
635int ui_surface_hide(UiSurface *s, ss_t w) {
636 if (!s)
637 return -1;
638 hide_panel(s->mpan[w]);
639 s->meta[w].hidden = true;
640 return 0;
641}
642// -------------------------------------------------------------------------
643// Screen Navigation
644// -------------------------------------------------------------------------
645/** @brief Move the cursor to a specified position within a UiSurface.
646 *
647 * @param s Pointer to the UiSurface where the cursor will be moved.
648 * @param w The index of the window within the surface where the cursor will be moved.
649 * @param y The new y-coordinate (row) for the cursor's position.
650 * @param x The new x-coordinate (column) for the cursor's position.
651 * @return 0 on success, or -1 on failure.
652 */
653int ui_wmove(UiSurface *s, ss_t w, uint y, uint x) {
654 if (!s || !s->mwin[w])
655 return -1;
656 return wmove(s->mwin[w], y, x);
657}
658/** @brief Move the cursor to a specified position within a UiSurface.
659 *
660 * @param s Pointer to the UiSurface where the cursor will be moved.
661 * @param w The index of the window within the surface where the cursor will be moved.
662 * @param y The new y-coordinate (row) for the cursor's position.
663 * @param x The new x-coordinate (column) for the cursor's position.
664 * @return 0 on success, or -1 on failure.
665 */
666int ui_cursor_move(UiSurface *s, ss_t w, uint y, uint x) {
667 if (!s || !s->mwin[w])
668 return -1;
669 return wmove(s->mwin[w], y, x);
670}
671// ui_cursor_yx(*int y, int *x);
672//
673// ui_abs_yx(UiSurface *s, ss_t w, int *y, int *x);
674//
675void ui_getyx(UiSurface *s, ss_t w, uint *lines, uint *cols) {
676 if (!s->mwin[w])
677 return;
678 int _lines, _cols;
679 getyx(s->mwin[w], _lines, _cols);
680 *lines = (uint)(_lines);
681 *cols = (uint)(_cols);
682}
683/** @brief Get the maximum dimensions of a UiSurface.
684 *
685 * @param s Pointer to the UiSurface for which to retrieve the maximum dimensions.
686 * @param w The index of the window within the surface for which to retrieve the maximum dimensions.
687 * @param lines Pointer to a uint variable where the maximum number of lines (rows) will be stored.
688 * @param cols Pointer to a uint variable where the maximum number of columns will be stored.
689 */
690void ui_getmaxyx(UiSurface *s, ss_t w, uint *lines, uint *cols) {
691 if (!s->mwin[w])
692 return;
693 getmaxyx(s->mwin[w], *lines, *cols);
694}
695/** @brief Get the maximum number of lines (rows) of a UiSurface.
696 *
697 * @param s Pointer to the UiSurface for which to retrieve the maximum number of lines.
698 * @param w The index of the window within the surface for which to retrieve the maximum number of lines.
699 * @return The maximum number of lines (rows) of the specified UiSurface, or -1 on failure.
700 */
701int ui_getmaxy(UiSurface *s, ss_t w) {
702 if (!s->mwin[w])
703 return -1;
704 return (int)(getmaxy(s->mwin[w]));
705}
706/** @brief Get the maximum number of columns of a UiSurface.
707 *
708 * @param s Pointer to the UiSurface for which to retrieve the maximum number of columns.
709 * @param w The index of the window within the surface for which to retrieve the maximum number of columns.
710 * @return The maximum number of columns of the specified UiSurface, or -1 on failure.
711 */
712int ui_getmaxx(UiSurface *s, ss_t w) {
713 if (!s->mwin[w])
714 return -1;
715 return (int)(getmaxx(s->mwin[w]));
716}
717/** @brief Get the current screen size (number of lines and columns).
718 *
719 * @param lines Pointer to a uint variable where the number of lines (rows) will be stored.
720 * @param cols Pointer to a uint variable where the number of columns will be stored.
721 */
722void ui_get_screen_size(uint *lines, uint *cols) {
723 if (!ui)
724 return;
725 getmaxyx(stdscr, ui->lines, ui->cols);
726 if (lines)
727 *lines = ui->lines;
728 if (cols)
729 *cols = ui->cols;
730}
731/** @brief Scroll the contents of a UiSurface by a specified number of lines.
732 *
733 * @param s Pointer to the UiSurface to be scrolled.
734 * @param w The index of the window within the surface to be scrolled.
735 * @param n The number of lines to scroll. Positive values scroll down, negative values scroll up.
736 * @return 0 on success, or -1 on failure.
737 */
738int ui_wscrl(UiSurface *s, ss_t w, int n) {
739 if (!s->mwin[w])
740 return -1;
741 wscrl(s->mwin[w], n);
742 return 0;
743}
744
745// -------------------------------------------------------------------------
746// Configuration Control
747// -------------------------------------------------------------------------
748/** @brief Enable or disable scrolling for a UiSurface.
749 *
750 * @param s Pointer to the UiSurface for which to enable or disable scrolling.
751 * @param w The index of the window within the surface for which to enable or disable scrolling.
752 * @param enable A boolean value indicating whether to enable (true) or disable (false) scrolling.
753 * @return 0 on success, or -1 on failure.
754 */
755int ui_scrollok(UiSurface *s, ss_t w, bool enable) {
756 if (!s->mwin[w])
757 return -1;
758 if (enable)
759 scrollok(s->mwin[w], true);
760 else
761 scrollok(s->mwin[w], false);
762 return 0;
763}
764/** @brief Enable or disable the keypad for a UiSurface.
765 *
766 * @param s Pointer to the UiSurface for which to enable or disable the keypad.
767 * @param w The index of the window within the surface for which to enable or disable the keypad.
768 * @param enable A boolean value indicating whether to enable (true) or disable (false) the keypad.
769 * @return 0 on success, or -1 on failure.
770 */
771int ui_keypad(UiSurface *s, ss_t w, bool enable) {
772 if (!s->mwin[w])
773 return -1;
774 if (enable)
775 keypad(s->mwin[w], true);
776 else
777 keypad(s->mwin[w], false);
778 return 0;
779}
780/** @brief Enable or disable the use of the insert/delete line capabilities for a UiSurface.
781 *
782 * @param s Pointer to the UiSurface for which to enable or disable the insert/delete line capabilities.
783 * @param w The index of the window within the surface for which to enable or disable the insert/delete line capabilities.
784 * @param enable A boolean value indicating whether to enable (true) or disable (false) the insert/delete line capabilities.
785 * @return 0 on success, or -1 on failure.
786 */
787int ui_idlok(UiSurface *s, ss_t w, bool enable) {
788 if (!s->mwin[w])
789 return -1;
790 if (enable)
791 idlok(s->mwin[w], true);
792 else
793 idlok(s->mwin[w], false);
794 return 0;
795}
796/** @brief Enable or disable the use of the insert/delete character capabilities for a UiSurface.
797 *
798 * @param s Pointer to the UiSurface for which to enable or disable the insert/delete character capabilities.
799 * @param w The index of the window within the surface for which to enable or disable the insert/delete character capabilities.
800 * @param enable A boolean value indicating whether to enable (true) or disable (false) the insert/delete character capabilities.
801 * @return 0 on success, or -1 on failure.
802 */
803int ui_idcok(UiSurface *s, ss_t w, bool enable) {
804 if (!s->mwin[w])
805 return -1;
806 if (enable)
807 idcok(s->mwin[w], true);
808 else
809 idcok(s->mwin[w], false);
810 return 0;
811}
812/** @brief Set the scrolling region for a UiSurface.
813 *
814 * @param s Pointer to the UiSurface for which to set the scrolling region.
815 * @param w The index of the window within the surface for which to set the scrolling region.
816 * @param top The top line of the scrolling region (0-based).
817 * @param bottom The bottom line of the scrolling region (0-based).
818 * @return 0 on success, or -1 on failure.
819 */
820int ui_setscrreg(UiSurface *s, ss_t w, uint top, uint bottom) {
821 if (!s->mwin[w])
822 return -1;
823 wsetscrreg(s->mwin[w], top, bottom);
824 return 0;
825}
827 def_prog_mode();
828}
829// -------------------------------------------------------------------------
830// Cursor Control
831// -------------------------------------------------------------------------
832/** @brief Set the visibility of the cursor.
833 *
834 * @param visibility An integer value indicating the desired cursor visibility:
835 * 0 - Invisible
836 * 1 - Visible
837 * 2 - Very visible (e.g., block cursor)
838 * @return 0 on success, or -1 on failure.
839 */
840int ui_curs_set(int visibility) {
841 curs_set(visibility);
842 return 0;
843}
844// included for symetry with notcurses, which needs it to compensate
845// for cursor positioning bug
846/** @brief Enable or disable the cursor at a specific position within a UiSurface.
847 *
848 * @param s Pointer to the UiSurface where the cursor will be enabled or disabled.
849 * @param w The index of the window within the surface where the cursor will be enabled or disabled.
850 * @param y The y-coordinate (row) for the cursor's position.
851 * @param x The x-coordinate (column) for the cursor's position.
852 * @param visible A boolean value indicating whether to make the cursor visible (true) or invisible (false).
853 * @return 0 on success, or -1 on failure.
854 */
855int ui_cursor_enable_yx(UiSurface *s, ss_t w, uint y, uint x, bool visible) {
856 if (!ui)
857 return -1;
858 wmove(s->mwin[w], y, x);
859 ui->cursor_visible = visible;
860 curs_set(visible ? 2 : 0);
861 return 0;
862}
863/** @brief Enable or disable the cursor for a UiSurface.
864 *
865 * @param s Pointer to the UiSurface where the cursor will be enabled or disabled.
866 * @param w The index of the window within the surface where the cursor will be enabled or disabled.
867 * @param visible A boolean value indicating whether to make the cursor visible (true) or invisible (false).
868 * @return 0 on success, or -1 on failure.
869 */
870int ui_cursor_enable(UiSurface *s, ss_t w, bool visible) {
871 (void)s;
872 (void)w;
873 if (!ui)
874 return -1;
875 ui->cursor_visible = visible;
876 curs_set(visible ? 1 : 0);
877 return 0;
878}
879/* -------------------------------------------------------------------------
880 Rendering
881 ------------------------------------------------------------------------- */
882/** @brief Render the UI by updating panels and refreshing the display.
883 */
884void ui_render() {
885 update_panels();
886 doupdate();
887}
888/** @brief Update the panels in the UI.
889 */
891 update_panels();
892}
893/** @brief Refresh the display by updating the screen.
894 */
896 doupdate();
897 return 0;
898}
899/** -------------------------------------------------------------------------
900 Refreshing
901 ------------------------------------------------------------------------- */
902/** @brief Refresh a specific window within a UiSurface.
903 *
904 * @param s Pointer to the UiSurface containing the window to be refreshed.
905 * @param w The index of the window within the surface to be refreshed.
906 * @return 0 on success, or -1 on failure.
907 */
908int ui_wnoutrefresh(UiSurface *s, ss_t w) {
909 if (!s)
910 return -1;
911 wnoutrefresh(s->mwin[w]);
912 return 0;
913}
914
915// -------------------------------------------------------------------------
916// Background
917// -------------------------------------------------------------------------
918
919// for the entire window
920/** @brief Set the background of a specific window within a UiSurface.
921 *
922 * @param s Pointer to the UiSurface containing the window.
923 * @param w The index of the window within the surface for which to set the background.
924 * @param cell Pointer to a UiCell structure representing the desired background attributes.
925 * @return 0 on success, or -1 on failure.
926 */
927int ui_bkgd(UiSurface *s, ss_t w, const UiCell *cell) {
928 if (!s)
929 return -1;
930 wbkgrnd(s->mwin[w], cell);
931 return 0;
932}
933// for new content to be written to the window
934/** @brief Set the background for new content to be written to a specific window within a UiSurface.
935 *
936 * @param s Pointer to the UiSurface containing the window.
937 * @param w The index of the window within the surface for which to set the background for new content.
938 * @param cell Pointer to a UiCell structure representing the desired background attributes for new content.
939 * @return 0 on success, or -1 on failure.
940 */
941int ui_bkgdset(UiSurface *s, ss_t w, const UiCell *cell) {
942 if (!s)
943 return -1;
944 wbkgrndset(s->mwin[w], cell);
945 return 0;
946}
947// for the entire window
948/** @brief Set the background of a specific window within a UiSurface.
949 *
950 * @param s Pointer to the UiSurface containing the window.
951 * @param w The index of the window within the surface for which to set the background.
952 * @param cell Pointer to a UiCell structure representing the desired background attributes.
953 * @return 0 on success, or -1 on failure.
954 */
955int ui_bkgrnd(UiSurface *s, ss_t w, const UiCell *cell) {
956 if (!s->mwin[w])
957 return -1;
958 wbkgrnd(s->mwin[w], cell);
959 return 0;
960}
961// for new content to be written to the window
962/** @brief Set the background for new content to be written to a specific window within a UiSurface.
963 *
964 * @param s Pointer to the UiSurface containing the window.
965 * @param w The index of the window within the surface for which to set the background for new content.
966 * @param cell Pointer to a UiCell structure representing the desired background attributes for new content.
967 * @return 0 on success, or -1 on failure.
968 */
969int ui_bkgrndset(UiSurface *s, ss_t w, const UiCell *cell) {
970 if (!s->mwin[w])
971 return -1;
972 wbkgrndset(s->mwin[w], cell);
973 return 0;
974}
975/* -------------------------------------------------------------------------
976 Cell Manipulation
977 ------------------------------------------------------------------------- */
978/** @brief Get the character and attributes from a UiCell.
979 *
980 * @param cell Pointer to the UiCell from which to retrieve the character and attributes.
981 * @param wstr Pointer to a wchar_t array where the retrieved character will be stored.
982 * @param attrs Pointer to an attr_t variable where the retrieved attributes will be stored.
983 * @param pair Pointer to a short variable where the retrieved color pair will be stored.
984 * @param opts Pointer to additional options (not used in this implementation).
985 * @return 0 on success, or -1 on failure.
986 */
987int ui_getcchar(const UiCell *cell, wchar_t *wstr, attr_t *attrs, short *pair, const void *opts) {
988 (void)opts;
989 getcchar(cell, wstr, attrs, pair, nullptr);
990 return 0;
991}
992/** @brief Set the character and attributes of a UiCell.
993 *
994 * @param cell Pointer to the UiCell to be modified.
995 * @param wstr Pointer to a wchar_t array containing the character to be set.
996 * @param attrs The attributes to be applied to the cell.
997 * @param pair The color pair to be applied to the cell.
998 * @param opts Pointer to additional options (not used in this implementation).
999 * @return 0 on success, or -1 on failure.
1000 */
1001int ui_setcchar(UiCell *cell, const wchar_t *wstr, const attr_t attrs, short pair, const void *opts) {
1002 (void)opts;
1003 return setcchar(cell, wstr, attrs, pair, NULL);
1004}
1005/* -------------------------------------------------------------------------
1006 Colors, Color Pairs
1007 ------------------------------------------------------------------------- */
1008/** @brief Add a new color pair to the UI, or retrieve the index of an existing pair.
1009 *
1010 * @param fg The foreground color index for the new color pair.
1011 * @param bg The background color index for the new color pair.
1012 * @return The index of the new or existing color pair, or EXIT_FAILURE on failure.
1013 */
1014uint ui_add_pair(uint fg, uint bg) {
1015 int rc;
1016 uint i;
1017 uint pfg, pbg;
1018 for (i = 1; i < ui_pair_cnt; i++) {
1019 ui_pair_content(i, &pfg, &pbg);
1020 if (pfg == fg && pbg == bg)
1021 return i;
1022 }
1023 if (i + 1 >= UI_PAIRS) {
1024 ssnprintf(em0, MAXLEN - 1, _("%s, line: %d"), __FILE__, __LINE__ - 1);
1025 ssnprintf(em1, MAXLEN - 1, _("ui_add_pair failed for pair: %d"), i);
1026 strerror_r(errno, em2, MAXLEN);
1028 return (EXIT_FAILURE);
1029 }
1030 rc = init_extended_pair(i, fg, bg);
1031 if (rc == ERR) {
1032 ssnprintf(em0, MAXLEN - 1, _("%s, line: %d"), __FILE__, __LINE__ - 1);
1033 ssnprintf(em1, MAXLEN - 1, _("init_extended_pair failed for pair: %d"), i);
1034 ssnprintf(em2, MAXLEN - 1, _("fg: %d, bg: %d, ui_pair_cnt: %d"), fg, bg, ui_pair_cnt);
1036 return (EXIT_FAILURE);
1037 }
1038 ui_pair_cnt++;
1039 return (int)(ui_pair_cnt - 1);
1040}
1041/** @brief Change the foreground and background colors of an existing color pair.
1042 *
1043 * @param pair The index of the color pair to be modified.
1044 * @param fg The new foreground color index for the color pair.
1045 * @param bg The new background color index for the color pair.
1046 * @return 0 on success, or -1 on failure.
1047 */
1048int ui_chg_pair(uint pair, uint fg, uint bg) {
1049 if (pair + 1 >= UI_PAIRS)
1050 return -1;
1051 init_extended_pair(pair, fg, bg);
1052 return 0;
1053}
1054
1055/** was rgb_to_curses_clr
1056 * @brief Convert RGB to curses color index, adding new color if necessary.
1057 * @param rgb Pointer to RGB struct with r, g, b values (0-255).
1058 * @return Color index in curses color table, or 0 on failure.
1059 */
1060int ui_color_from_rgb(RGB *rgb) {
1061 if (rgb->r == rgb->g && rgb->g == rgb->b && rgb->b == 0)
1062 return 0;
1063 // #ifdef DEBUG_COLOR
1064 if (rgb->r > 255 || rgb->g > 255 || rgb->b > 255) {
1065 ssnprintf(em0, MAXLEN - 1, _("%s, line: %d"), __FILE__, __LINE__ - 1);
1066 ui_log(ERROR, "%s", em0);
1067 ssnprintf(em1, MAXLEN - 1, _("ui_color_from_rgb failed for RGB: %d,%d,%d"), rgb->r, rgb->g, rgb->b);
1068 ui_log(ERROR, "%s", em0);
1069 // return (EXIT_FAILURE);
1070 }
1071 // #endif
1072 uint i;
1073 RGB tmp;
1075 rgb->r = (rgb->r * 1000) / 255;
1076 rgb->g = (rgb->g * 1000) / 255;
1077 rgb->b = (rgb->b * 1000) / 255;
1078 for (i = 0; i < ui_color_cnt && i < UI_COLORS; i++) {
1079 extended_color_content(i, &tmp.r, &tmp.g, &tmp.b);
1080 if (rgb->r == tmp.r && rgb->g == tmp.g && rgb->b == tmp.b)
1081 return i;
1082 }
1083 if (i < UI_COLORS) {
1084 if (i < 16) {
1085 std_color[i].r = rgb->r;
1086 std_color[i].g = rgb->g;
1087 std_color[i].b = rgb->b;
1088 }
1089 init_extended_color(i, rgb->r, rgb->g, rgb->b);
1090 if (ui_color_cnt + 1 < UI_COLORS)
1091 ui_color_cnt++;
1092 return ui_color_cnt - 1;
1093 }
1094 return 0;
1095}
1096/** @brief Get the RGB color value for a given color index.
1097 *
1098 * @param color_idx The index of the color in the curses color table.
1099 * @return The RGB color value as a 32-bit unsigned integer (0xRRGGBB), or -1 on failure.
1100 */
1101uint32_t ui_get_color(uint16_t color_idx) {
1102 if (color_idx + 1 >= UI_COLORS)
1103 return -1;
1104 RGB rgb;
1105 extended_color_content(color_idx, &rgb.r, &rgb.g, &rgb.b);
1106 rgb.r = (rgb.r * 255) / 1000;
1107 rgb.g = (rgb.g * 255) / 1000;
1108 rgb.b = (rgb.b * 255) / 1000;
1109 return 0;
1110}
1111RGB ui_hex_to_rgb(char *s) {
1112 RGB rgb;
1113 sscanf(s, "#%02x%02x%02x", &rgb.r, &rgb.g, &rgb.b);
1114 return rgb;
1115}
1116int ui_color_content(uint color, uint *r, uint *g, uint *b) {
1117 int _color = (int)color;
1118 int _r, _g, _b;
1119 extended_color_content(_color, &_r, &_g, &_b);
1120 *r = (uint)_r;
1121 *g = (uint)_g;
1122 *b = (uint)_b;
1123 return 0;
1124}
1125/** @brief Initialize a color in the curses color table with specified RGB values.
1126 *
1127 * @param color The index of the color to be initialized.
1128 * @param r The red component of the color (0-255).
1129 * @param g The green component of the color (0-255).
1130 * @param b The blue component of the color (0-255).
1131 * @return 0 on success, or -1 on failure.
1132 */
1133int ui_init_color(uint color, uint r, uint g, uint b) {
1134 init_extended_color(color, r, g, b);
1135 return 0;
1136}
1137/** @brief Get the foreground and background colors of a specified color pair.
1138 *
1139 * @param pair The index of the color pair to be queried.
1140 * @param fg Pointer to a uint variable where the foreground color index will be stored.
1141 * @param bg Pointer to a uint variable where the background color index will be stored.
1142 * @return 0 on success, or -1 on failure.
1143 */
1144int ui_pair_content(uint pair, uint *fg, uint *bg) {
1145 int _pair = (int)pair;
1146 int _fg, _bg;
1147 extended_pair_content(_pair, &_fg, &_bg);
1148 *fg = (uint)_fg;
1149 *bg = (uint)_bg;
1150 return 0;
1151}
1152/** @brief Initialize a color pair in the curses color table with specified foreground and background colors.
1153 *
1154 * @param pair The index of the color pair to be initialized.
1155 * @param fg The foreground color index for the color pair.
1156 * @param bg The background color index for the color pair.
1157 * @return 0 on success, or -1 on failure.
1158 */
1159int ui_init_pair(uint pair, uint fg, uint bg) {
1160 init_extended_pair(pair, fg, bg);
1161 return 0;
1162}
1163/** @brief Change the RGB color value for a given color index.
1164 *
1165 * @param color_idx The index of the color in the curses color table to be changed.
1166 * @param color Pointer to a 32-bit unsigned integer representing the new RGB color value (0xRRGGBB).
1167 * @return 0 on success, or -1 on failure.
1168 */
1169int ui_chg_color(uint16_t color_idx, uint32_t *color) {
1170 if (color_idx + 1 >= UI_COLORS)
1171 return -1;
1172 RGB rgb;
1173 rgb.r = (*color >> 16) & 0xff;
1174 rgb.g = (*color >> 8) & 0xff;
1175 rgb.b = *color & 0xff;
1176 ui_apply_gamma(&rgb);
1177 if (color_idx < 16) {
1178 std_color[color_idx].r = rgb.r;
1179 std_color[color_idx].g = rgb.g;
1180 std_color[color_idx].b = rgb.b;
1181 }
1182 rgb.r = (rgb.r * 1000) / 255;
1183 rgb.g = (rgb.g * 1000) / 255;
1184 rgb.b = (rgb.b * 1000) / 255;
1185 init_extended_color(color_idx, rgb.r, rgb.g, rgb.b);
1186 return 0;
1187}
1188/* -------------------------------------------------------------------------
1189 Non-portable escape-hatch getters (see ui_ncurses_compat.h)
1190 ------------------------------------------------------------------------- */
1191/** @brief Get the current SCREEN pointer used by the UI.
1192 *
1193 * @return The SCREEN pointer if the UI is initialized, or NULL if the UI is not initialized.
1194 */
1196 if (!ui)
1197 return NULL;
1198 return ui->screen;
1199}
1200/** @brief Get the current FILE pointer for the TTY used by the UI.
1201 *
1202 * @return The FILE pointer for the TTY if the UI is initialized, or NULL if the UI is not initialized.
1203 */
1204WINDOW *ui_ncurses_surface_get_win(const UiSurface *s, ss_t w) {
1205 if (!s)
1206 return NULL;
1207 return s->mwin[w];
1208}
1209/** @brief Get the current PANEL pointer for a specific window within a UiSurface.
1210 *
1211 * @param s Pointer to the UiSurface containing the window.
1212 * @param w The index of the window within the surface for which to retrieve the PANEL pointer.
1213 * @return The PANEL pointer for the specified window, or NULL if the UiSurface is NULL.
1214 */
1215PANEL *ui_ncurses_surface_get_panel(const UiSurface *s, ss_t w) {
1216 if (!s)
1217 return NULL;
1218 return s->mpan[w];
1219}
1220// -------------------------------------------------------------------------
1221// Multibyte conversion
1222// -------------------------------------------------------------------------
1223uint ui__mbstr_to_cellstr(UiCell *cmplx_buf, const char *str, const UiCell *cell_base, uint *p, const uint atmost) {
1224 attr_t attrs;
1225 short cp;
1226 uint p1 = 0;
1227 uint *pos = &p1;
1228 if (p)
1229 pos = p;
1230 else
1231 pos = &p1;
1232 uint i = 0, len = 0;
1233 const char *s;
1234 UiCell cc = {};
1235 wchar_t wstr[5];
1236 getcchar(cell_base, &wstr[0], &attrs, &cp, nullptr);
1237 mbstate_t mbstate;
1238 memset(&mbstate, 0, sizeof(mbstate));
1239 if (pos && *pos >= atmost - 1)
1240 return 0;
1241 while (str[i] != '\0') {
1242 s = &str[i];
1243 len = mbrtowc(wstr, s, MB_CUR_MAX, &mbstate);
1244 if (len <= 0) {
1245 wstr[0] = L'?';
1246 wstr[1] = L'\0';
1247 len = 1;
1248 }
1249 wstr[1] = L'\0';
1250 if (*pos > atmost)
1251 break;
1252 if (setcchar(&cc, wstr, attrs, cp, nullptr) != ERR) {
1253 if (len > 0 && (*pos + len) < atmost)
1254 cmplx_buf[(*pos)++] = cc;
1255 }
1256 i += len;
1257 }
1258 wstr[0] = L'\0';
1259 wstr[1] = L'\0';
1260 setcchar(&cc, wstr, attrs, cp, nullptr);
1261 cmplx_buf[*pos] = cc;
1262 return *pos;
1263}
1266 return;
1268 f_ncurses_open = false;
1271 return;
1272}
int ui_border_draw(UiSurface *sfc)
Definition ui_common.c:474
int ui_surface_resize(UiSurface *s, ss_t w, uint lines, uint cols)
Resize a UiSurface to new dimensions.
Definition ui_ncurses.c:536
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
UiRuntime * ui_init(const UiConfig *config, SIO *sio)
Initialize the UI runtime with the given configuration and SIO.
Definition ui_ncurses.c:129
void ui_render()
Render the UI by updating panels and refreshing the display.
Definition ui_ncurses.c:884
void ui_getyx(UiSurface *s, ss_t w, uint *lines, uint *cols)
Get the current cursor position within a window of a UI surface.
Definition ui_ncurses.c:675
UiCell cell_nt
Definition ui_common.c:106
bool f_ncurses_open
Definition ui_common.c:50
char em1[MAXLEN]
Definition ui_common.c:47
int ui_setscrreg(UiSurface *s, ss_t w, uint top, uint bottom)
Set the scrolling region for a UiSurface.
Definition ui_ncurses.c:820
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
void ui_getmaxyx(UiSurface *s, ss_t w, uint *lines, uint *cols)
Get the maximum dimensions of a UiSurface.
Definition ui_ncurses.c:690
int ui_cursor_enable_yx(UiSurface *s, ss_t w, uint y, uint x, bool visible)
Enable or disable the cursor at a specific position within a UiSurface.
Definition ui_ncurses.c:855
char em2[MAXLEN]
Definition ui_common.c:48
int ui_wscrl(UiSurface *s, ss_t w, int rows)
Scroll the contents of a UiSurface by a specified number of lines.
Definition ui_ncurses.c:738
int ui_idcok(UiSurface *s, ss_t w, bool enable)
Enable or disable the use of the insert/delete character capabilities for a UiSurface.
Definition ui_ncurses.c:803
int ui_surface_addpad(UiSurface *s, ss_t w, uint view_win, uint lines, uint cols, uint begy, uint begx)
Add a new pad to the specified UiSurface.
Definition ui_ncurses.c:369
BorderWide bw
Definition ui_common.c:27
int ui_cursor_move(UiSurface *s, ss_t w, uint y, uint x)
Move the cursor to a specified position within a UiSurface.
Definition ui_ncurses.c:666
#define UI_SFC_MAX
Definition ui_backend.h:196
#define UI_PAIRS
Definition ui_backend.h:194
int ui_suspend()
Suspend the UI, saving the current program state and ending the window session.
Definition ui_ncurses.c:494
void ui_surface_destroy(UiSurface *s)
Destroy a UiSurface, cleaning up its windows and panels.
Definition ui_ncurses.c:468
@ SUB_SFC_MAX
Definition ui_backend.h:47
int ui_border_title(UiSurface *sfc, const char *title)
Draw a box with a title around the specified window.
Definition ui_common.c:563
void ui_update_panels()
Update the panels in the UI.
Definition ui_ncurses.c:890
int ui_bkgd(UiSurface *s, ss_t w, const UiCell *cell)
Set the background of a specific window within a UiSurface.
Definition ui_ncurses.c:927
#define ERR
Definition ui_backend.h:427
int ui_idlok(UiSurface *s, ss_t w, bool enable)
Enable or disable the use of the insert/delete line capabilities for a UiSurface.
Definition ui_ncurses.c:787
const wchar_t * border_double
Definition ui_common.c:69
int ui_surface_move(UiSurface *s, ss_t w, uint y, uint x)
Move a UiSurface to a new position on the screen.
Definition ui_ncurses.c:521
int ui_getmaxy(UiSurface *s, ss_t w)
Get the maximum number of lines (rows) of a UiSurface.
Definition ui_ncurses.c:701
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
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
int ui_surface_show(UiSurface *s, ss_t w)
Show a UiSurface, making it visible on the screen.
Definition ui_ncurses.c:609
int ui_erase()
Erase the entire screen.
Definition ui_ncurses.c:591
void ui_shutdown()
Shutdown the UI runtime, cleaning up resources and freeing memory.
Definition ui_ncurses.c:418
UiSurface * ui_surface_new(ss_t w, UiSurface *parent, uint p, uint lines, uint cols, uint y, uint x)
Create a new UI surface with the specified parameters.
Definition ui_ncurses.c:229
void ui_initialize_sio(SIO *sio)
Definition ui_common.c:182
UiSurface * stdsfc
Definition ui_ncurses.c:46
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
int ui_resume()
Resume the UI, restoring the previous program state and updating the display.
Definition ui_ncurses.c:503
int ui_bkgrndset(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:969
int ui_top_surface(UiSurface *s, ss_t w)
Hide a UiSurface, making it invisible on the screen.
Definition ui_ncurses.c:623
int ui_wclear(UiSurface *s, ss_t w)
Clear the contents of a UiSurface or all surfaces.
Definition ui_ncurses.c:571
char em0[MAXLEN]
Definition ui_common.c:46
void ui_endwin()
End the UI application, cleaning up resources and shutting down the UI runtime.
Definition ui_ncurses.c:412
int ui_cursor_enable(UiSurface *s, ss_t w, bool visible)
Enable or disable the cursor for a UiSurface.
Definition ui_ncurses.c:870
int ui_clear()
Clear the entire screen.
Definition ui_ncurses.c:599
int ui_getmaxx(UiSurface *s, ss_t w)
Get the maximum number of columns of a UiSurface.
Definition ui_ncurses.c:712
const wchar_t * border_heavy
Definition ui_common.c:71
int ui_surface_hide(UiSurface *s, ss_t w)
Hide a UiSurface, making it invisible on the screen.
Definition ui_ncurses.c:635
bool f_notcurses_open
Definition ui_common.c:51
const wchar_t * border_rounded
Definition ui_common.c:70
int ui_bkgrnd(UiSurface *s, ss_t w, const UiCell *cell)
Set the background of a specific window within a UiSurface.
Definition ui_ncurses.c:955
int ui_scrollok(UiSurface *s, ss_t w, bool enable)
Enable or disable scrolling for a UiSurface.
Definition ui_ncurses.c:755
int ui_wnoutrefresh(UiSurface *s, ss_t w)
Refresh a specific window within a UiSurface.
Definition ui_ncurses.c:908
#define UI_COLORS
Definition ui_backend.h:193
void ui_get_caps(UiCaps *caps)
Get the UI backend capabilities.
Definition ui_ncurses.c:62
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
int ui_doupdate()
Refresh the display by updating the screen.
Definition ui_ncurses.c:895
int ui_werase(UiSurface *s, ss_t w)
Erase the contents of a UiSurface or all surfaces.
Definition ui_ncurses.c:551
@ UI_BACKEND_NCURSES
Definition ui_backend.h:452
#define ALLWINS
Definition ui_backend.h:195
int ui_keypad(UiSurface *s, ss_t w, bool enable)
Enable or disable the keypad for a UiSurface.
Definition ui_ncurses.c:771
#define WA_NORMAL
STDRGB std_color[]
Definition ui_common.c:159
UiLogLevel ui_min_log_level
Definition ui_common.c:1390
void ui_apply_gamma(RGB *rgb)
Apply gamma correction to RGB color.
Definition ui_common.c:941
int ui_setcchar(UiCell *cell, const wchar_t *wstr, const attr_t attrs, short pair, const void *opts)
Set the character and attributes of a UiCell.
uint ui__mbstr_to_cellstr(UiCell *cmplx_buf, const char *str, const UiCell *cell_base, uint *p, const uint atmost)
int ui_chg_pair(uint pair, uint fg, uint bg)
Change the foreground and background colors of an existing color pair.
int ui_pair_content(uint pair, uint *fg, uint *bg)
Get the foreground and background colors of a specified color pair.
SCREEN * ui_ncurses_get_screen()
Get the current SCREEN pointer used by the UI.
int ui_getcchar(const UiCell *cell, wchar_t *wstr, attr_t *attrs, short *pair, const void *opts)
Get the character and attributes from a UiCell.
Definition ui_ncurses.c:987
int ui_init_color(uint color, uint r, uint g, uint b)
Initialize a color in the curses color table with specified RGB values.
int ui_init_pair(uint pair, uint fg, uint bg)
Initialize a color pair in the curses color table with specified foreground and background colors.
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
uint32_t ui_get_color(uint16_t color_idx)
Get the RGB color value for a given color index.
int ui_color_content(uint color, uint *r, uint *g, uint *b)
void fast_exit(UiSurface *s)
Exit the UI application quickly, cleaning up resources.
Definition ui_ncurses.c:339
UiRuntime * ui
Definition ui_ncurses.c:39
RGB ui_hex_to_rgb(char *s)
Convert a hexadecimal color string to an RGB structure.
int ui_pair_from_hex(const char *fg, const char *bg)
Convert hex color strings to a curses color pair index.
Definition ui_ncurses.c:86
WINDOW * ui_ncurses_surface_get_win(const UiSurface *s, ss_t w)
Get the current FILE pointer for the TTY used by the UI.
void ui_destroy_curses()
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_pair_cnt
Definition ui_ncurses.c:44
PANEL * ui_ncurses_surface_get_panel(const UiSurface *s, ss_t w)
Get the current PANEL pointer for a specific window within a UiSurface.
uint ui_color_cnt
Definition ui_ncurses.c:43
void ui_def_prog_mode()
Definition ui_ncurses.c:826
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.
#define TRUE
Definition iloan.c:31
#define MAXLEN
Definition curskeys.c:15
#define _(String)
Definition amort.c:23
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:390
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_display_error(char *msg0, char *msg1, char *msg2, char *msg3)
Display an error message window or print to stderr.
Definition ui_common.c:1200
UiBackend ui_get_backend()
Get the UI backend type.
Definition ui_ncurses.c:55
UiBorderStyle border_style
Definition ui_backend.h:445
UiLogLevel log_level
Definition ui_backend.h:447
bool palette256
Definition ui_backend.h:458
bool mouse
Definition ui_backend.h:459
int color_pairs
Definition ui_backend.h:462
bool truecolor
Definition ui_backend.h:457
bool unicode
Definition ui_backend.h:460
bool resize
Definition ui_backend.h:461
wchar_t str[11]
Definition ui_backend.h:563