C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
ui_notcurses.c
Go to the documentation of this file.
1/** @file ui_notcurses.c
2 @ingroup ui_notcurses
3 @brief NotCurses UI backend — lifecycle, surface management, and capabilities.
4
5 Implements all UiRuntime and UiSurface operations declared in ui_backend.h
6 using the NotCurses library.
7*/
8
9#include "common.h"
10#define _XOPEN_SOURCE_EXTENDED 1
11
12#include "cm.h"
13#include "ui_backend.h"
16#include <errno.h>
17#include <inttypes.h>
18#include <locale.h>
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23
24UiRuntime *ui = NULL;
25uint ui_color_cnt = 0;
26uint ui_pair_cnt = 0;
27UiPair *ui_pair;
28UiColor *ui_color;
29UiSurface *stdsfc;
30uint LINES, COLS;
31UiRuntime *ui;
32UiConfig *ui_config;
35
36int sfc_ptr = -1;
37int win_ptr = -1;
38
40
41/** BOX WIDE UNICODE CODEPOINTS */
42
43wchar_t *border_single = L"─│├┤┬┴┼┌┐└┘";
44wchar_t *border_rounded = L"─│├┤┬┴┼╭╮╰╯";
45wchar_t *border_double = L"═║╠╣╦╩╬╔╗╚╝";
46wchar_t *border_heavy = L"━┃┣┫┳┻╋┏┓┗┛";
47wchar_t *border_none = L" ";
48
49BorderWide bw;
50
51const wchar_t *bw_rtl = L"\x256d"; /**< rounded top left */
52const wchar_t *bw_rtr = L"\x256e"; /**< rounded top right */
53const wchar_t *bw_rbl = L"\x2570"; /**< rounded bottom left */
54const wchar_t *bw_rbr = L"\x256f"; /**< rounded bottom right */
55const wchar_t *bw_sp = L"\x20"; /**< space */
56const wchar_t *bw_ra = L"\x2192"; /**< large right arrow */
57const wchar_t *bw_la = L"\x2190"; /**< large left arrow */
58const wchar_t *bw_ua = L"\x2191"; /**< large up arrow */
59const wchar_t *bw_da = L"\x2193"; /**< large down arrow */
60const wchar_t *bw_ran = L"\x276F"; /**< right_angle */
61const wchar_t *bw_lan = L"\x276E"; /**< left_angle */
62const wchar_t *bw_chk = L"\x2611"; /**< left_angle */
63const wchar_t *bw_h09 = L"\x23BD"; /**< horizontal line 9 */
64
65STDRGB std_color[] = {{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}};
66
67/* -------------------------------------------------------------------------
68 Backend identification and capability query
69 ------------------------------------------------------------------------- */
70
71UiBackend ui_get_backend() {
73}
74
75void ui_get_caps(UiCaps *caps) {
76 if (!caps)
77 return;
78 memset(caps, 0, sizeof(*caps));
79 if (!ui)
80 return;
81 // I don't know that it isn't truecolor
82 caps->truecolor = true;
83 caps->palette256 = true;
85 caps->unicode = true;
86 caps->resize = true;
87 caps->color_pairs = 0;
88}
89/* -------------------------------------------------------------------------
90 Lifecycle
91 ------------------------------------------------------------------------- */
92UiRuntime *ui_init(const UiConfig *cfg) {
93 setlocale(LC_ALL, "");
94 ui = calloc(1, sizeof(*ui));
95 if (!ui)
96 return NULL;
97 char tty_name[MAXLEN];
98 if (cfg && cfg->tty_path) {
99 strncpy(tty_name, cfg->tty_path, sizeof(tty_name) - 1);
100 tty_name[sizeof(tty_name) - 1] = '\0';
101 } else {
102 if (ttyname_r(STDIN_FILENO, tty_name,
103 sizeof(tty_name)) != 0) {
104 free(ui);
105 ui = NULL;
106 return NULL;
107 }
108 }
109 ui->tty_fp = fopen(tty_name, "r+");
110 if (ui->tty_fp == NULL) {
111 ui = NULL;
112 free(ui);
113 return NULL;
114 }
115 NotCursesOptions nc_opts = {
116 .flags = NCOPTION_SUPPRESS_BANNERS |
117 NCOPTION_NO_QUIT_SIGHANDLERS
118 // NCOPTION_PRESERVE_CURSOR,
119 // .loglevel = NCLOGLEVEL_SILENT,
120 };
121 ui->nc = notcurses_init(&nc_opts, ui->tty_fp);
122 if (ui->nc == NULL) {
123 free(ui);
124 ui = NULL;
125 return NULL;
126 }
127 f_curses_open = true;
128 stdplane = notcurses_stdplane(ui->nc);
129 notcurses_render(ui->nc);
130
131 if (ui->nc == NULL) {
132 fclose(ui->tty_fp);
133 ui->tty_fp = NULL;
134 free(ui);
135 ui = NULL;
136 return NULL;
137 }
138 if (cfg) {
143 } else {
144 ui->cursor_visible = false;
145 ui->alt_screen = false;
146 }
148 notcurses_mice_enable(ui->nc, NCMICE_ALL_EVENTS);
150 notcurses_cursor_disable(ui->nc);
151 notcurses_stddim_yx(ui->nc, &ui->lines, &ui->cols);
152 stdsfc = calloc(1, sizeof(*stdsfc));
153 if (!stdsfc)
154 return NULL;
155 for (int i = 0; i < SUB_SFC_MAX; i++) {
156 stdsfc->mplane[i] = NULL;
157 stdsfc->meta[i].lines = 0;
158 stdsfc->meta[i].cols = 0;
159 stdsfc->meta[i].y = 0;
160 stdsfc->meta[i].x = 0;
161 stdsfc->meta[i].hidden = false;
162 }
164 stdsfc->parent = NULL;
167 stdsfc->meta[BOX].y = 0;
168 stdsfc->meta[BOX].x = 0;
169 stdsfc->mplane[BOX] = stdplane;
170 if (!stdsfc->mplane[BOX]) {
171 notcurses_stop(ui->nc);
172 return NULL;
173 }
174 sfc_ptr = -1;
176 COLS = ui->cols;
177 ui_pair = calloc(UI_PAIRS, sizeof(UiPair));
178 if (!ui_pair) {
179 free(ui_pair);
180 notcurses_stop(ui->nc);
181 free(ui);
182 return NULL;
183 }
184 ui_color = calloc(UI_COLORS, sizeof(UiColor));
185 if (!ui_color) {
186 free(ui_pair);
187 notcurses_stop(ui->nc);
188 free(ui);
189 return NULL;
190 }
191 if (cfg) {
192 if (ui->border_style == 'r' || ui->border_style == 'R') {
193 memcpy(bw.str, border_rounded, sizeof(bw.str));
194 } else if (ui->border_style == 's' || ui->border_style == 'S') {
195 memcpy(bw.str, border_single, sizeof(bw.str));
196 } else if (ui->border_style == 'd' || ui->border_style == 'D') {
197 memcpy(bw.str, border_double, sizeof(bw.str));
198 } else if (ui->border_style == 'h' || ui->border_style == 'H') {
199 memcpy(bw.str, border_heavy, sizeof(bw.str));
200 } else if (ui->border_style == 'n' || ui->border_style == 'N') {
201 memcpy(bw.str, border_none, sizeof(bw.str));
202 }
203 }
204 stdsfc = calloc(1, sizeof(*stdsfc));
205 ui_color_cnt = 0;
206 ui_pair_cnt = 0;
207 return ui;
208}
209
210void ui_endwin() {
211 // if (ui == NULL)
212 // return;
213 // if (ui->nc) {
214 // if (ui->mouse_enabled)
215 // notcurses_mice_disable(ui->nc);
216 // notcurses_stop(ui->nc);
217 // }
218 // free(ui);
219 // ui = NULL;
220}
221
223 if (ui == NULL || f_curses_open == false)
224 return;
225 if (ui->nc) {
227 notcurses_mice_disable(ui->nc);
228 notcurses_stop(ui->nc);
229 f_curses_open = false;
230 }
231 free(ui);
232 ui = NULL;
233}
234
235/* -------------------------------------------------------------------------
236 Surface Creation and Destruction
237 ------------------------------------------------------------------------- */
238
239UiSurface *ui_surface_new(uint w, UiSurface *parent, uint p, uint lines, uint cols, uint y, uint x) {
240 if (!ui)
241 return NULL;
242 UiSurface *s = calloc(1, sizeof(*s));
243 if (!s)
244 return NULL;
245 s->runtime = ui;
246 s->parent = parent;
247 ncplane_options plane_opts = {
248 .y = y,
249 .x = x,
250 .rows = lines,
251 .cols = cols};
252 s->meta[w].y = y;
253 s->meta[w].x = x;
254 s->meta[w].lines = lines;
255 s->meta[w].cols = cols;
256 s->meta[w].hidden = false;
257 if (parent && parent->mplane[p]) {
258 s->mplane[w] = ncplane_create(parent->mplane[p], &plane_opts);
259 } else {
260 stdplane = notcurses_stdplane(ui->nc);
261 s->mplane[w] = ncplane_create(stdplane, &plane_opts);
262 }
263 if (!s->mplane[w]) {
264 notcurses_stop(ui->nc);
265 return NULL;
266 }
267 free(stdsfc);
268 return s;
269}
270
271UiSurface *ui_box_surface_new(UiSurface *parent, uint p, uint lines, uint cols, uint y, uint x, char *wtitle) {
272 if (!ui)
273 return NULL;
274 UiSurface *s = calloc(1, sizeof(*s));
275 if (!s)
276 return NULL;
277 s->runtime = ui;
278 s->parent = parent;
279 ncplane_options plane_opts = {
280 .y = y,
281 .x = x,
282 .rows = lines + 2,
283 .cols = cols + 2,
284 .name = NULL};
285 s->meta[BOX].y = y;
286 s->meta[BOX].x = x;
287 s->meta[BOX].lines = lines + 2;
288 s->meta[BOX].cols = cols + 2;
289 s->meta[BOX].hidden = false;
291 if (parent && parent->mplane[p]) {
292 s->mplane[BOX] = ncplane_create(parent->mplane[p], &plane_opts);
293 } else {
294 stdplane = notcurses_stdplane(ui->nc);
295 s->mplane[BOX] = ncplane_create(stdplane, &plane_opts);
296 }
297 if (!s->mplane[BOX]) {
298 free(s);
299 return NULL;
300 }
301 ncplane_set_base(s->mplane[BOX],
302 " ",
303 0,
305 ncplane_set_channels(s->mplane[BOX], cell_box.channels);
307 border_title(s, wtitle);
308 return s;
309}
310
311int ui_surface_addpad(UiSurface *s, uint w, uint p, uint lines, uint cols) {
312 uint plines, pcols;
313 ncplane_dim_yx(s->mplane[p], &plines, &pcols);
314 pcols = min(pcols, cols);
315 plines = min(plines, lines);
316 ncplane_options plane_opts = {
317 .y = 0,
318 .x = 0,
319 .rows = plines,
320 .cols = pcols,
321 .name = NULL};
322 s->meta[w].y = 0;
323 s->meta[w].x = 0;
324 s->meta[w].lines = plines;
325 s->meta[w].cols = pcols;
326 s->meta[w].hidden = false;
327 s->mplane[w] = ncplane_create(s->mplane[p], &plane_opts);
328 if (!s->mplane[w]) {
329 notcurses_stop(ui->nc);
330 return -1;
331 }
332 ncplane_set_base(s->mplane[w], " ", 0, cell_nt.channels);
333 ncplane_set_channels(s->mplane[w], cell_nt.channels);
336 return 0;
337}
338
339int ui_surface_addwin(UiSurface *s, uint w, uint p, uint lines, uint cols, uint y, uint x) {
340 ncplane_options plane_opts = {
341 .y = y,
342 .x = x,
343 .rows = lines,
344 .cols = cols,
345 .name = NULL};
346 s->meta[w].y = y;
347 s->meta[w].x = x;
348 s->meta[w].lines = lines;
349 s->meta[w].cols = cols;
350 s->meta[w].hidden = false;
351 s->mplane[w] = ncplane_create(s->mplane[p], &plane_opts);
352 if (!s->mplane[w]) {
353 notcurses_stop(ui->nc);
354 return -1;
355 }
356 ncplane_set_base(s->mplane[w], " ", 0, cell_nt.channels);
357 ncplane_set_channels(s->mplane[w], cell_nt.channels);
360 return 0;
361}
362
363void ui_surface_destroy(UiSurface *s) {
364 if (!s)
365 return;
366 for (int w = SUB_SFC_MAX; w >= 0; w--)
367 if (s->mplane[w] != NULL) {
368 ncplane_erase(s->mplane[w]);
369 ncplane_destroy(s->mplane[w]);
370 s->mplane[w] = NULL;
371 }
372 if (s != NULL) {
373 free(s);
374 s = NULL;
375 }
376}
377/* -------------------------------------------------------------------------
378 Configuration Control
379 ------------------------------------------------------------------------- */
380
381int ui_scrollok(UiSurface *s, uint w, bool enable) {
382 if (!s)
383 return -1;
384 ncplane_set_scrolling(s->mplane[w], enable);
385 return 0;
386}
387int ui_idcok(UiSurface *s, uint w, bool enable) {
388 (void)s;
389 (void)w;
390 (void)enable;
391 return 0;
392}
393int ui_idlok(UiSurface *s, uint w, bool enable) {
394 (void)s;
395 (void)w;
396 (void)enable;
397 return 0;
398}
399int ui_setscrreg(UiSurface *s, uint w, uint top, uint bottom) {
400 (void)s;
401 (void)w;
402 (void)top;
403 (void)bottom;
404 return 0;
405}
406int ui_keypad(UiSurface *s, uint w, bool enable) {
407 (void)s;
408 (void)w;
409 (void)enable;
410 return 0;
411}
412/* -------------------------------------------------------------------------
413 Screen management functions
414 ------------------------------------------------------------------------- */
415
416int ui_mousemask(int mask) {
417 if (!ui)
418 return 0;
419 if (mask)
420 notcurses_mice_enable(ui->nc, mask);
421 else
422 notcurses_mice_enable(ui->nc, NCMICE_ALL_EVENTS);
423 return 0;
424}
425
426int ui_mice_enable(int mask) {
427 if (mask)
428 notcurses_mice_enable(ui->nc, mask);
429 else
430 notcurses_mice_enable(ui->nc, NCMICE_ALL_EVENTS);
431 return 0;
432}
433
434void ui_get_screen_size(uint *lines, uint *cols) {
435 if (!ui)
436 return;
437 unsigned int r = 0, c = 0;
438 notcurses_stddim_yx(ui->nc, &r, &c);
439 ui->lines = (int)r;
440 ui->cols = (int)c;
441 if (lines)
442 *lines = ui->lines;
443 if (cols)
444 *cols = ui->cols;
445}
447 if (!ui)
448 return;
449 notcurses_render(ui->nc);
450}
451
452void ui_render() {
453 if (!ui)
454 return;
455 notcurses_render(ui->nc);
456}
457
459 if (!ui)
460 return -1;
461 notcurses_leave_alternate_screen(ui->nc);
462 return 0;
463}
464
466 if (!ui)
467 return -1;
468 notcurses_enter_alternate_screen(ui->nc);
469 notcurses_render(ui->nc);
470 return 0;
471}
472
473int ui_curs_set(int visible) {
474 if (!ui)
475 return -1;
476 if (visible == 0) {
477 ui->cursor_visible = false;
478 notcurses_cursor_disable(ui->nc);
479 } else {
480 ui->cursor_visible = true;
481 int y, x;
482 notcurses_cursor_yx(ui->nc, &y, &x);
483 int rc = notcurses_cursor_enable(ui->nc, y, x);
484 return rc;
485 }
486 return 0;
487}
488/** @brief Disable (visible = false) or enable (visibile = true) the cursor at a
489 * specified position on the surface and plane specified.
490 * Include workaround for NotCurses cursor position bug
491 */
492int ui_cursor_enable_yx(UiSurface *s, uint w, uint y, uint x, bool visible) {
493 if (!s)
494 return -1;
495 if (!visible) {
496 ui->cursor_visible = false;
497 notcurses_cursor_disable(ui->nc);
498 } else {
499 int yy, xx;
500 ncplane_abs_yx(s->mplane[w], &yy, &xx);
501 y += yy;
502 x += xx;
503 ui->cursor_visible = true;
504 int rc = notcurses_cursor_enable(ui->nc, y, x);
505 return rc;
506 }
507 return 0;
508}
509/** @brief Disable (visible = false) or enable (visibile = true) the cursor at
510 * its current position on the surface and plane specified.
511 */
512int ui_cursor_enable(UiSurface *s, uint w, bool visible) {
513 if (!s)
514 return -1;
515 if (!visible) {
516 ui->cursor_visible = false;
517 notcurses_cursor_disable(ui->nc);
518 } else {
519 uint y, x;
520 ncplane_cursor_yx(s->mplane[w], &y, &x);
521 int yy, xx;
522 ncplane_abs_yx(s->mplane[w], &yy, &xx);
523 y += yy;
524 x += xx;
525 ui->cursor_visible = true;
526 return notcurses_cursor_enable(ui->nc, y, x) == 0 ? 0 : -1;
527 }
528 return 0;
529}
530/* -------------------------------------------------------------------------
531 Surface management
532 ------------------------------------------------------------------------- */
533int ui_surface_move(UiSurface *s, uint w, uint y, uint x) {
534 if (!s)
535 return -1;
536 s->meta[w].y = y;
537 s->meta[w].x = x;
538 if (!s->meta[w].hidden)
539 return ncplane_move_yx(s->mplane[w], y, x) == 0 ? 0 : -1;
540 return 0;
541}
542
543int ui_surface_resize(UiSurface *s, uint w, uint lines, uint cols) {
544 if (!s)
545 return -1;
546 return ncplane_resize_simple(s->mplane[w], (unsigned int)lines,
547 (unsigned int)cols) == 0
548 ? 0
549 : -1;
550}
551
552int ui_clear() {
553 if (!stdplane)
554 return -1;
555 ncplane_erase_region(stdplane, 0, 0, 0, 0);
556 return 0;
557}
558int ui_erase() {
559 if (!stdplane)
560 return -1;
561 ncplane_erase_region(stdplane, 0, 0, 0, 0);
562 return 0;
563}
564int ui_werase(UiSurface *s, uint w) {
565 if (!s)
566 return -1;
567 ncplane_erase_region(s->mplane[w], 0, 0, 0, 0);
568 return 0;
569}
570int ui_wclear(UiSurface *s, uint w) {
571 if (!s)
572 return -1;
573 ncplane_erase_region(s->mplane[w], 0, 0, 0, 0);
574 return 0;
575}
576
577int ui_surface_show(UiSurface *s, uint w) {
578 if (!s)
579 return -1;
580 if (s->meta[w].hidden) {
581 s->meta[w].hidden = false;
582 ncplane_move_yx(s->mplane[w], s->meta[w].y, s->meta[w].x);
583 }
584 return 0;
585}
586
587int ui_surface_hide(UiSurface *s, uint w) {
588 if (!s)
589 return -1;
590 if (!s->meta[w].hidden) {
591 s->meta[w].hidden = true;
592 /* Move far off-screen so the plane does not obscure anything. */
593 ncplane_move_yx(s->mplane[w], -s->meta[w].lines - 1, 0);
594 }
595 return 0;
596}
597
598int ui_wmove(UiSurface *s, uint w, uint y, uint x) {
599 if (!s)
600 return -1;
601 if (ncplane_cursor_move_yx(s->mplane[w], y, x) != 0)
602 return -1;
603 return 0;
604}
605int ui_cursor_move(UiSurface *s, uint w, uint y, uint x) {
606 if (!s)
607 return -1;
608 if (ncplane_cursor_move_yx(s->mplane[w], y, x) != 0)
609 return -1;
610 return 0;
611}
612void ui_getyx(UiSurface *s, uint w, uint *y, uint *x) {
613 if (!s)
614 return;
615 ncplane_cursor_yx(s->mplane[w], y, x);
616}
617void ui_getmaxyx(UiSurface *s, uint w, uint *y, uint *x) {
618 if (!s)
619 return;
620 ncplane_dim_yx(s->mplane[w], y, x);
621}
622uint ui_getmaxy(UiSurface *s, uint w) {
623 if (!s)
624 return -1;
625 uint y, x;
626 ncplane_dim_yx(s->mplane[w], &y, &x);
627 return y;
628}
629uint ui_getmaxx(UiSurface *s, uint w) {
630 if (!s)
631 return -1;
632 uint y, x;
633 ncplane_dim_yx(s->mplane[w], &y, &x);
634 return x;
635}
636int ui_wscrl(UiSurface *s, uint w, int r) {
637 if (!r)
638 return -1;
639 ncplane_scrollup(s->mplane[w], r);
641 return 0;
642}
643int ui_top_panel(UiSurface *s, uint w) {
644 (void)w;
645 if (!s)
646 return -1;
647 return 0;
648}
649int ui_wnoutrefresh(UiSurface *s, uint w) {
650 (void)w;
651 if (!s)
652 return -1;
653 return 0;
654}
655/* -------------------------------------------------------------------------
656 Cell Manipulation
657 ------------------------------------------------------------------------- */
658
659int ui_getcchar(const UiCell *uic, wchar_t *wc, UiStyle *style, UiPairIdx *pair, const void *opts) {
660 (void)opts;
661 if (!uic || !wc || !style || !pair)
662 return -1;
663 GCluster gcluster;
664 gcluster.u32 = uic->gcluster;
665 wc = gcluster.u16;
666 *style = uic->stylemask;
667 // Convert the channels to a color pair index
668 UiChannels channels;
669 channels.fb = uic->channels;
670 RGB rgb;
671 rgb.r = channels.f_r;
672 rgb.g = channels.f_g;
673 rgb.b = channels.f_b;
674 // If the color index does not exist, create a new one
675 int fg = ui_add_color_rgb(&rgb);
676 rgb.r = channels.b_r;
677 rgb.g = channels.b_g;
678 rgb.b = channels.b_b;
679 // If the color index does not exist, create a new one
680 int bg = ui_add_color_rgb(&rgb);
681 // If the color pair does not exist, create a new one
682 *pair = ui_add_pair(fg, bg);
683 return 0;
684}
685
686int ui_setcchar(UiCell *cell, const wchar_t *wstr, const uint16_t style, ushort pair, const void *opts) {
687 (void)opts;
688 if (!cell)
689 return -1;
690 uint32_t fg, bg;
691 GCluster *gc = (GCluster *)&cell->gcluster;
692 gc->u16[0] = wstr[0];
693 gc->u16[1] = wstr[1];
694 cell->width = wcwidth((wchar_t)*wstr);
695 nccell_set_styles(cell, style);
696 UiChannels *chan = (UiChannels *)&cell->channels;
697 ui_get_pair(pair, &fg, &bg);
698 ui_color_content(fg, &chan->f_r, &chan->f_g, &chan->f_b);
699 chan->f_a = 0x40;
700 ui_color_content(bg, &chan->b_r, &chan->b_g, &chan->b_b);
701 chan->b_a = 0x40;
702 return 0;
703}
704
705UiCell ui_cell_from_ucp(const wchar_t *ucp, const uint32_t *fg, const uint32_t *bg) {
706 nccell cell;
707 nccell_init(&cell);
708 GCluster *gc = (GCluster *)&cell.gcluster;
709 wchar_t wstr[2] = {ucp[0], L'\0'};
710 // wcwidth expects Unicode codepoints, not UTF-8 encoded bytes
711 cell.width = wcwidth(wstr[0]);
712 // unicode_to_utf8_gcluster converts Unicode codepoints to UTF-8
713 unicode_to_utf8_gcluster(wstr[0], gc);
714 nccell_set_styles(&cell, WA_NORMAL);
715 UiChannels *chan = (UiChannels *)&cell.channels;
716 chan->bargb = *bg;
717 chan->fargb = *fg;
718 chan->b_a = chan->f_a = 0x40;
719 return cell;
720}
721
722/* -------------------------------------------------------------------------
723 Colors, Color Pairs
724 ------------------------------------------------------------------------- */
725
726int ui_add_color_rgb(RGB *rgb) {
727 uint i;
728 RGB tmp;
729 apply_gamma(rgb);
730 for (i = 0; i < ui_color_cnt && i < UI_COLORS; i++) {
731 ui_color_content(i, &tmp.r, &tmp.g, &tmp.b);
732 if (rgb->r == tmp.r && rgb->g == tmp.g && rgb->b == tmp.b)
733 return i;
734 }
735 if (i < UI_COLORS) {
736 if (i < 16) {
737 std_color[i].r = rgb->r;
738 std_color[i].g = rgb->g;
739 std_color[i].b = rgb->b;
740 }
741 ui_init_color(i, rgb->r, rgb->g, rgb->b);
742 if (ui_color_cnt + 1 < UI_COLORS)
743 ui_color_cnt++;
744 return ui_color_cnt - 1;
745 }
746 return -1;
747}
748/* ------------------------------------------------------------------------- */
749uint ui_add_pair(uint fg, uint bg) {
750 uint16_t i;
751 for (i = 1; i < ui_pair_cnt; i++) {
752 if (ui_pair[i].fg == fg && ui_pair[i].bg == bg)
753 return i;
754 }
755 if (i + 1 >= UI_PAIRS) {
756 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__ - 1);
757 ssnprintf(em1, MAXLEN - 1, "NotCurses COLOR_PAIRS (%d) exceeded (%d)",
758 UI_PAIRS, i);
759 strerror_r(errno, em2, MAXLEN);
761 return (EXIT_FAILURE);
762 }
763 if (i < UI_PAIRS) {
764 ui_pair[i].fg = fg;
765 ui_pair[i].bg = bg;
766 ui_pair_cnt++;
767 }
768 return ui_pair_cnt - 1;
769}
770int ui_get_pair(uint16_t pair, uint *fg, uint *bg) {
771 *fg = ui_pair[pair].fg;
772 *bg = ui_pair[pair].bg;
773 return 0;
774}
775
776uint64_t ui_get_channels_from_pair(uint16_t pair) {
777 uint fg, bg;
778 // ui_channels is a struct that holds the foreground and background color
779 // channels
780 // use channels.fb to get the combined foreground and background color channels
781 UiChannels ui_channels = {0};
782 ui_get_pair(pair, &fg, &bg);
783 ui_color_content(fg, &ui_channels.f_r, &ui_channels.f_g, &ui_channels.f_b);
784 ui_channels.f_a = 0x40;
785 ui_channels.f_r = ui_color[fg].r;
786 ui_channels.f_g = ui_color[fg].g;
787 ui_channels.f_b = ui_color[fg].b;
788 bg = ui_pair[pair].bg;
789 ui_color_content(bg, &ui_channels.b_r, &ui_channels.b_g, &ui_channels.b_b);
790 ui_channels.b_a = 0x40;
791 ui_channels.b_r = ui_color[bg].r;
792 ui_channels.b_g = ui_color[bg].g;
793 ui_channels.b_b = ui_color[bg].b;
794 return ui_channels.fb;
795}
796
797uint ui_init_color_hex(char *s) {
798 RGB rgb;
799 rgb = ui_hex_to_rgb(s);
800 apply_gamma(&rgb);
801 uint i;
802 for (i = 0; i < ui_color_cnt && i < UI_COLORS; i++) {
803 if (rgb.r == ui_color[i].r && rgb.g == ui_color[i].g && rgb.b == ui_color[i].b)
804 return i;
805 }
806 if (i < UI_COLORS) {
807 if (i < 16) {
808 std_color[i].r = rgb.r;
809 std_color[i].g = rgb.g;
810 std_color[i].b = rgb.b;
811 }
812 ui_color[i].r = rgb.r;
813 ui_color[i].g = rgb.g;
814 ui_color[i].b = rgb.b;
815 if (ui_color_cnt + 1 < UI_COLORS)
816 ui_color_cnt++;
817 return ui_color_cnt - 1;
818 }
819 return 0;
820}
821
822RGB ui_hex_to_rgb(char *s) {
823 RGB rgb;
824 sscanf(s, "#%02hhX%02hhX%02hhX", &rgb.r, &rgb.g, &rgb.b);
825 return rgb;
826}
827
828int ui_color_content(uint16_t color, uint8_t *r, uint8_t *g, uint8_t *b) {
829 if (color + 1 >= UI_COLORS)
830 return -1;
831 *r = ui_color[color].r;
832 *g = ui_color[color].g;
833 *b = ui_color[color].b;
834 return 0;
835}
836
837int ui_init_color(uint16_t color, uint8_t r, uint8_t g, uint8_t b) {
838 if (color + 1 >= UI_COLORS)
839 return -1;
840 ui_color[color].r = r;
841 ui_color[color].g = g;
842 ui_color[color].b = b;
843 return 0;
844}
845
846int ui_pair_content(uint16_t pair, uint *fg, uint *bg) {
847 if (pair + 1 >= UI_PAIRS)
848 return -1;
849 *fg = ui_pair[pair].fg;
850 *bg = ui_pair[pair].bg;
851 return 0;
852}
853
854int ui_init_pair(uint16_t pair, uint fg, uint bg) {
855 if (pair + 1 >= UI_PAIRS)
856 return -1;
857 ui_pair[pair].fg = fg;
858 ui_pair[pair].bg = bg;
859 return 0;
860}
861
862int ui_chg_color(uint16_t color_idx, uint32_t *color) {
863 RGB rgb;
864 rgb.color = *color;
865 if (color_idx + 1 >= UI_COLORS)
866 return -1;
867 apply_gamma(&rgb);
868 if (color_idx < 16) {
869 std_color[color_idx].r = rgb.r;
870 std_color[color_idx].g = rgb.g;
871 std_color[color_idx].b = rgb.b;
872 }
873 ui_color[color_idx].r = rgb.r;
874 ui_color[color_idx].g = rgb.g;
875 ui_color[color_idx].b = rgb.b;
876 return 0;
877}
878/* -------------------------------------------------------------------------
879 Style helpers (shared with draw and input modules)
880 ------------------------------------------------------------------------- */
881
882int ui_bkgd(UiSurface *s, uint w, const UiCell *cell) {
883 if (!s)
884 return -1;
885 ncplane_set_styles(s->mplane[w], cell->stylemask);
886 ncplane_set_channels(s->mplane[w], cell_box.channels);
887 ncplane_set_base(s->mplane[w], " ",
888 cell->stylemask, cell->channels);
889 return 0;
890}
891
892int ui_bkgdset(UiSurface *s, uint w, const UiCell *cell) {
893 if (!s)
894 return -1;
895 ncplane_set_styles(s->mplane[w], cell->stylemask);
896 ncplane_set_channels(s->mplane[w], cell->channels);
897 bkgd_cell = *cell;
898 return 0;
899}
900int ui_bkgrnd(UiSurface *s, uint w, const UiCell *cell) {
901 if (!s)
902 return -1;
903 ncplane_set_styles(s->mplane[w], cell->stylemask);
904 ncplane_set_channels(s->mplane[w], cell->channels);
905 ncplane_set_base(s->mplane[w], " ",
906 cell->stylemask, cell->channels);
907 return 0;
908}
909
910int ui_bkgrndset(UiSurface *s, uint w, const UiCell *cell) {
911 if (!s)
912 return -1;
913 ncplane_set_styles(s->mplane[w], cell->stylemask);
914 ncplane_set_channels(s->mplane[w], cell->channels);
915 return 0;
916}
917/* -------------------------------------------------------------------------
918 Non-portable escape-hatch getters (see ui_notcurses_compat.h)
919 ------------------------------------------------------------------------- */
920
921struct notcurses *ui_notcurses_get_nc() {
922 if (!ui)
923 return NULL;
924 return ui->nc;
925}
926
927NcPlane *ui_notcurses_surface_get_plane(const UiSurface *s, uint w) {
928 (void)w;
929 if (!s)
930 return NULL;
931 return s->mplane[w];
932}
bool f_curses_open
Definition sig.c:33
#define min(x, y)
min macro evaluates two expressions, returning least result
Definition cm.h:91
const wchar_t * bw_sp
Definition ui_ncurses.c:52
void ui_render()
Definition ui_ncurses.c:800
int ui_cursor_move(UiSurface *s, uint w, uint y, uint x)
Definition ui_ncurses.c:727
wchar_t * border_rounded
Definition ui_ncurses.c:41
UiRuntime * ui_init(const UiConfig *config)
Definition ui_ncurses.c:261
void ui_getyx(UiSurface *s, uint w, uint *lines, uint *cols)
Definition ui_ncurses.c:668
int ui_surface_hide(UiSurface *s, uint w)
Definition ui_ncurses.c:614
const wchar_t * bw_ran
Definition ui_ncurses.c:57
int ui_bkgdset(UiSurface *s, uint w, const UiCell *cell)
Definition ui_ncurses.c:760
int ui_mice_enable(int mask)
UiSurface * ui_surface_new(uint w, UiSurface *parent, uint p, uint lines, uint cols, uint y, uint x)
Definition ui_ncurses.c:414
int ui_setscrreg(UiSurface *s, uint w, uint top, uint bottom)
Definition ui_ncurses.c:662
int ui_scrollok(UiSurface *s, uint w, bool enable)
Definition ui_ncurses.c:626
NcPlane * stdplane
const wchar_t * bw_rbr
Definition ui_ncurses.c:51
int ui_add_color_rgb(RGB *rgb)
Definition ui_ncurses.c:138
const wchar_t * bw_ua
Definition ui_ncurses.c:55
int ui_wclear(UiSurface *s, uint w)
Definition ui_ncurses.c:574
uint COLS
Definition ui_backend.h:266
const wchar_t * bw_chk
Definition ui_ncurses.c:59
BorderWide bw
Definition ui_ncurses.c:46
int ui_bkgd(UiSurface *s, uint w, const UiCell *cell)
Definition ui_ncurses.c:753
#define UI_SFC_MAX
Definition ui_backend.h:24
const wchar_t * bw_rtl
Definition ui_ncurses.c:48
const wchar_t * bw_rtr
Definition ui_ncurses.c:49
const wchar_t * bw_lan
Definition ui_ncurses.c:58
#define UI_PAIRS
Definition ui_backend.h:40
int ui_suspend()
Definition ui_ncurses.c:398
struct notcurses_options NotCursesOptions
Definition ui_backend.h:253
void ui_surface_destroy(UiSurface *s)
Definition ui_ncurses.c:377
int ui_surface_move(UiSurface *s, uint w, uint y, uint x)
Definition ui_ncurses.c:542
int ui_idlok(UiSurface *s, uint w, bool enable)
Definition ui_ncurses.c:644
const wchar_t * bw_ra
Definition ui_ncurses.c:53
void ui_update_panels()
Definition ui_ncurses.c:804
STDRGB std_color[]
Definition ui_ncurses.c:62
int ui_wmove(UiSurface *s, uint w, uint y, uint x)
Definition ui_ncurses.c:732
UiSurface * ui_surface[UI_SFC_MAX]
Definition ui_ncurses.c:28
const wchar_t * bw_h09
Definition ui_ncurses.c:60
int ui_werase(UiSurface *s, uint w)
Definition ui_ncurses.c:560
void ui_get_screen_size(uint *lines, uint *cols)
Definition ui_ncurses.c:692
int ui_erase()
Definition ui_ncurses.c:590
UiRuntime * ui
RGB ui_hex_to_rgb(char *s)
Definition ui_ncurses.c:174
void ui_shutdown()
Definition ui_ncurses.c:344
int ui_wscrl(UiSurface *s, uint w, int rows)
int win_ptr
Definition ui_ncurses.c:30
int ui_mousemask(int mask)
uint LINES
UiSurface * stdsfc
Definition ui_ncurses.c:36
int sfc_ptr
Definition nckeys.c:47
UiCell ui_cell_from_ucp(const wchar_t *ucp, const uint32_t *fg, const uint32_t *bg)
Definition ui_ncurses.c:239
int ui_curs_set(int visibility)
Definition ui_ncurses.c:737
int ui_top_panel(UiSurface *s, uint w)
Definition ui_ncurses.c:607
int ui_resume()
Definition ui_ncurses.c:403
struct ncplane NcPlane
Definition ui_backend.h:251
uint ui_pair_cnt
Definition ui_ncurses.c:34
int ui_wnoutrefresh(UiSurface *s, uint w)
Definition ui_ncurses.c:811
struct nccell UiCell
Definition ui_backend.h:250
int ui_surface_resize(UiSurface *s, uint w, uint lines, uint cols)
Definition ui_ncurses.c:550
uint16_t UiPairIdx
Definition ui_backend.h:36
const wchar_t * bw_la
Definition ui_ncurses.c:54
uint ui_color_cnt
Definition ui_ncurses.c:33
void ui_endwin()
Definition ui_ncurses.c:341
wchar_t * border_heavy
Definition ui_ncurses.c:43
int ui_surface_show(UiSurface *s, uint w)
Definition ui_ncurses.c:598
int ui_clear()
Definition ui_ncurses.c:594
UiSurface * ui_box_surface_new(UiSurface *parent, uint p, uint lines, uint cols, uint y, uint x, char *title)
Definition ui_ncurses.c:453
int ui_keypad(UiSurface *s, uint w, bool enable)
Definition ui_ncurses.c:635
int ui_cursor_enable(UiSurface *s, uint w, bool visible)
Disable (visible = false) or enable (visibile = true) the cursor at its current position on the surfa...
Definition ui_ncurses.c:713
const wchar_t * bw_da
Definition ui_ncurses.c:56
wchar_t * border_double
Definition ui_ncurses.c:42
int ui_idcok(UiSurface *s, uint w, bool enable)
Definition ui_ncurses.c:653
uint16_t UiStyle
Definition ui_backend.h:35
#define UI_COLORS
Definition ui_backend.h:39
void ui_get_caps(UiCaps *caps)
Query the capabilities of the active backend.
Definition ui_ncurses.c:88
@ UI_BACKEND_NOTCURSES
Definition ui_backend.h:157
UiBackend ui_get_backend()
Return which backend is powering this runtime.
Definition ui_ncurses.c:84
int ui_surface_addpad(UiSurface *s, uint w, uint view_win, uint lines, uint cols)
Definition ui_ncurses.c:509
void ui_getmaxyx(UiSurface *s, uint w, uint *lines, uint *cols)
Definition ui_ncurses.c:676
const wchar_t * bw_rbl
Definition ui_ncurses.c:50
int ui_cursor_enable_yx(UiSurface *s, uint w, uint y, uint x, bool visible)
Disable (visible = false) or enable (visibile = true) the cursor at a specified position on the surfa...
Definition ui_ncurses.c:703
int ui_surface_addwin(UiSurface *s, uint w, uint p, uint lines, uint cols, uint y, uint x)
Definition ui_ncurses.c:523
int ui_chg_color(uint16_t color_idx, uint32_t *color)
Definition ui_ncurses.c:206
#define XLEN
#define WA_NORMAL
int ui_get_pair(uint16_t pair, uint *fg, uint *bg)
UiPair * ui_pair
UiConfig * ui_config
UiCell bkgd_cell
uint ui_init_color_hex(char *s)
UiColor * ui_color
struct notcurses * ui_notcurses_get_nc()
Return the raw struct notcurses* for the NotCurses session.
NcPlane * ui_notcurses_surface_get_plane(const UiSurface *s, uint w)
Return the raw struct ncplane* underlying a surface.
uint64_t ui_get_channels_from_pair(uint16_t pair)
int ui_pair_content(uint pair, uint *fg, uint *bg)
Definition ui_ncurses.c:194
int ui_getmaxx(UiSurface *s, uint w)
Definition ui_ncurses.c:686
int ui_bkgrndset(UiSurface *s, uint w, const UiCell *cell)
Definition ui_ncurses.c:774
int ui_init_color(uint color, uint r, uint g, uint b)
Definition ui_ncurses.c:189
int ui_init_pair(uint pair, uint fg, uint bg)
Definition ui_ncurses.c:202
uint ui_add_pair(uint fg, uint bg)
Definition ui_ncurses.c:105
int ui_getcchar(const UiCell *uc, wchar_t *wstr, attr_t *attrs, uint16_t *pair, void *opts)
Definition ui_ncurses.c:784
int ui_color_content(uint color, uint *r, uint *g, uint *b)
Definition ui_ncurses.c:179
int ui_getmaxy(UiSurface *s, uint w)
Definition ui_ncurses.c:681
int ui_bkgrnd(UiSurface *s, uint w, const UiCell *cell)
Definition ui_ncurses.c:767
wchar_t * border_single
Definition ui_ncurses.c:40
int ui_setcchar(cchar_t *wch, const wchar_t *wc, const attr_t attrs, short pair, const void *opts)
Definition ui_ncurses.c:792
wchar_t * border_none
Definition ui_ncurses.c:44
#define MAXLEN
Definition curskeys.c:15
UiCell cell_nt
Definition dwin.c:94
char em1[MAXLEN]
Definition dwin.c:143
char em2[MAXLEN]
Definition dwin.c:144
int border_draw(UiSurface *sfc)
Definition dwin.c:581
void apply_gamma(RGB *rgb)
Apply gamma correction to RGB color.
Definition dwin.c:307
char em0[MAXLEN]
Definition dwin.c:142
UiCell cell_box
Definition dwin.c:98
int border_title(UiSurface *sfc, char *title)
Draw a box with a title around the specified window.
Definition dwin.c:676
int display_error(char *msg0, char *msg1, char *msg2, char *msg3)
Display an error message window or print to stderr.
Definition dwin.c:778
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:537
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:413
bool cursor_visible
Definition ui_backend.h:145
const char * tty_path
Definition ui_backend.h:147
bool enable_mouse
Definition ui_backend.h:143
char border_style
Definition ui_backend.h:146
bool enable_alt_screen
Definition ui_backend.h:144
bool palette256
Definition ui_backend.h:170
bool mouse
Definition ui_backend.h:171
int color_pairs
Definition ui_backend.h:174
bool truecolor
Definition ui_backend.h:169
bool unicode
Definition ui_backend.h:172
bool resize
Definition ui_backend.h:173
wchar_t str[11]
Definition ui_backend.h:185
uint8_t g
Definition ui_backend.h:261
uint8_t r
Definition ui_backend.h:260
uint8_t b
Definition ui_backend.h:262
uint32_t u32
Definition ui_backend.h:288
wchar_t u16[2]
Definition ui_backend.h:289
struct notcurses * nc
unsigned int cols
unsigned int lines
struct UiSurface * parent
struct UiRuntime * runtime
struct UiSurfaceMeta meta[SUB_SFC_MAX]
uint32_t color
uint64_t channels
Definition nccell.h:8
uint16_t stylemask
Definition nccell.h:7
uint8_t width
Definition nccell.h:6
uint32_t gcluster
Definition nccell.h:4