C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
ui_notcurses_draw.c
Go to the documentation of this file.
1/** @file ui_notcurses_draw.c
2 @ingroup ui_notcurses
3 @brief NotCurses UI backend — drawing functions.
4
5 Implements the drawing operations declared in ui_backend.h using the
6 NotCurses API.
7*/
8#define _GNU_SOURCE
9#define _XOPEN_SOURCE_EXTENDED 1
10
11#include "ui_backend.h"
13#include <notcurses/notcurses.h>
14#include <stddef.h>
15#include <stdlib.h>
16#include <string.h>
17
18/* -------------------------------------------------------------------------
19 Housekeeping functions
20 ------------------------------------------------------------------------- */
21/** @brief clear the window from the current cursor position to the end of the window
22 * @param s surface
23 * @param w window
24 * @return 0 on success, -1 on error
25 */
26int ui_wclrtoeol(UiSurface *s, ss_t w) {
27 if (!s)
28 return -1;
29 uint y, x, ylen, xlen, maxy, maxx;
30 ncplane_cursor_yx(s->mplane[w], &y, &x);
31 ncplane_dim_yx(s->mplane[w], &maxy, &maxx);
32 xlen = maxx - x;
33 ylen = 1;
34 ncplane_erase_region(s->mplane[w], y, x, ylen, xlen);
35 return 0;
36}
37/** @brief clear from current cursor position to bottom of window
38 * @param s surface
39 * @param w window
40 * @return 0 on success, -1 on error
41 */
42int ui_wclrtobot(UiSurface *s, ss_t w) {
43 if (!s)
44 return -1;
45 uint y, x, ylen, xlen, maxy, maxx;
46 ncplane_cursor_yx(s->mplane[w], &y, &x);
47 ncplane_dim_yx(s->mplane[w], &maxy, &maxx);
48 xlen = maxx - x;
49 ylen = 1;
50 ncplane_erase_region(s->mplane[w], y, x, ylen, xlen);
51 ylen = maxy - y - 1;
52 xlen = maxx;
53 ncplane_erase_region(s->mplane[w], y + 1, x = 0, ylen, maxx);
54 return 0;
55}
56
57/* -------------------------------------------------------------------------
58 Text
59 ------------------------------------------------------------------------- */
60/** @brief create a cell with specified character, using background cell style
61 * and channels
62 * @param cell pointer to UiCell
63 * @param c character
64 * @return 0 on success, -1 on error
65 */
66int mk_chimera(UiCell *cell, char c) {
67 cell->gcluster = c;
68 cell->gcluster_backstop = 0;
69 cell->stylemask = bkgd_cell.stylemask;
70 cell->channels = bkgd_cell.channels;
71 return 0;
72}
73/** @brief on specified window, at current location, add character
74 * @param s surface
75 * @param w window
76 * @param c character
77 * @return 0 on success, -1 on error
78 */
79int ui_draw_ch(UiSurface *s, ss_t w, char c) {
80 if (!s || !c)
81 return -1;
82 nccell cell = CELL_INITIALIZER(c, s->meta[w].bkgd_cell.stylemask, s->meta[w].bkgd_cell.channels);
83 ncplane_putc_yx(s->mplane[w], -1, -1, &cell);
84 return 0;
85}
86/** @brief on specified window, move to y, x, add character
87 * @param s surface
88 * @param w window
89 * @param y row
90 * @param x column
91 * @param c character
92 * @return 0 on success, -1 on error
93 */
94int ui_draw_ch_yx(UiSurface *s, ss_t w, uint y, uint x, char c) {
95 if (!s || !c)
96 return -1;
97 nccell cell = CELL_INITIALIZER(c, s->meta[w].bkgd_cell.stylemask, s->meta[w].bkgd_cell.channels);
98 ncplane_putc_yx(s->mplane[w], y, x, &cell);
99 return 0;
100}
101/** @brief on specified window, move to y, x, add string
102 * @param s surface
103 * @param w window
104 * @param y row
105 * @param x column
106 * @param text string
107 * @return 0 on success, -1 on error
108 */
109int ui_draw_text(UiSurface *s, ss_t w, uint y, uint x, const char *text) {
110 if (!s || !text)
111 return -1;
112 ncplane_putstr_yx(s->mplane[w], y, x, text);
113 return 0;
114}
115/** @brief on specified window, move to y, x, add string, at most m columns
116 * @param s surface
117 * @param w window
118 * @param y row
119 * @param x column
120 * @param text string
121 * @param m maximum number of columns to write
122 * @return 0 on success, -1 on error
123 */
124int ui_draw_text_n(UiSurface *s, ss_t w, uint y, uint x, const char *text, int m) {
125 if (!s || !text)
126 return -1;
127 ncplane_putnstr_yx(s->mplane[w], y, x, m, text);
128 return 0;
129}
130/** @brief on specified window, move to y, x, add string, at most m columns, fill with spaces if text is shorter than m
131 * @param s surface
132 * @param w window
133 * @param y row
134 * @param x column
135 * @param text string
136 * @param m maximum number of columns to write
137 * @return 0 on success, -1 on error
138 */
139int ui_draw_text_fill(UiSurface *s, ss_t w, uint y, uint x, const char *text, int m) {
140 if (!s || !text)
141 return -1;
142 char tmp_str[MAXLEN];
143 strncpy(tmp_str, text, m);
144 int l = strlen(text);
145 for (int i = l; i < m; i++) {
146 tmp_str[i] = ' ';
147 }
148 tmp_str[m] = '\0';
149 ncplane_putnstr_yx(s->mplane[w], y, x, m, tmp_str);
151 return 0;
152}
153// -------------------------------------------------------------------------
154/** @brief on specified window, at current location, add character
155 * @param s surface
156 * @param w window
157 * @param c character
158 * @return 0 on success, -1 on error
159 */
160int ui_waddch(UiSurface *s, ss_t w, const char c) {
161 if (!s || !c)
162 return -1;
163 nccell cell = CELL_INITIALIZER(c, s->meta[w].bkgd_cell.stylemask, s->meta[w].bkgd_cell.channels);
164 ncplane_putc_yx(s->mplane[w], -1, -1, &cell);
165 return 0;
166}
167/** @brief on specified window, move to y, x, add character
168 * @param s surface
169 * @param w window
170 * @param y row
171 * @param x column
172 * @param c character
173 * @return 0 on success, -1 on error
174 */
175int ui_mvwaddch(UiSurface *s, ss_t w, uint y, uint x, const char c) {
176 if (!s || !c)
177 return -1;
178 nccell cell = CELL_INITIALIZER(c, s->meta[w].bkgd_cell.stylemask, s->meta[w].bkgd_cell.channels);
179 ncplane_putc_yx(s->mplane[w], y, x, &cell);
180 return 0;
181}
182/** @brief on specified window, at current location, add string
183 * @param s surface
184 * @param w window
185 * @param text string
186 * @return 0 on success, -1 on error
187 */
188int ui_waddstr(UiSurface *s, ss_t w, const char *text) {
189 if (!s || !text)
190 return -1;
191 ncplane_putstr(s->mplane[w], text);
192 return 0;
193}
194/** @brief on specified window, at current location, add string, at most m columns
195 * @param s surface
196 * @param w window
197 * @param text string
198 * @param m maximum number of columns to write
199 * @return 0 on success, -1 on error
200 */
201int ui_waddnstr(UiSurface *s, ss_t w, const char *text, int m) {
202 if (!s || !text)
203 return -1;
204 ncplane_putnstr(s->mplane[w], m, text);
205 return 0;
206}
207/** @brief on specified window, move to y, x, add string
208 * @param s surface
209 * @param w window
210 * @param y row
211 * @param x column
212 * @param text string
213 * @return 0 on success, -1 on error
214 */
215int ui_mvwaddstr(UiSurface *s, ss_t w, uint y, uint x, const char *text) {
216 if (!s || !text)
217 return -1;
218 ncplane_putstr_yx(s->mplane[w], y, x, text);
219 return 0;
220}
221/** @brief on specified window, move to y, x, add string, at most m columns
222 * @param s surface
223 * @param w window
224 * @param y row
225 * @param x column
226 * @param text string
227 * @param m maximum number of columns to write
228 * @return 0 on success, -1 on error
229 */
230int ui_mvwaddnstr(UiSurface *s, ss_t w, uint y, uint x, const char *text, int m) {
231 if (!s || !text)
232 return -1;
233 ncplane_putnstr_yx(s->mplane[w], y, x, m, text);
234 return 0;
235}
236/** @brief on specified window, move to y, x, add string, at most m columns, fill with spaces if text is shorter than m
237 * @param s surface
238 * @param w window
239 * @param y row
240 * @param x column
241 * @param text string
242 * @param m maximum number of columns to write
243 * @return 0 on success, -1 on error
244 */
245int ui_mvwaddstr_fill(UiSurface *s, ss_t w, uint y, uint x, const char *text, int m) {
246 if (!s || !text)
247 return -1;
248 int l = strlen(text);
249 if (l <= m) {
250 char *tmp_str = (char *)malloc(m + 1);
251 if (!tmp_str)
252 return -1;
253 strcpy(tmp_str, text);
254 for (int i = l; i < (int)m; i++) {
255 tmp_str[i] = ' ';
256 }
257 tmp_str[m] = '\0';
258 ncplane_putnstr_yx(s->mplane[w], y, x, m, tmp_str);
259 free(tmp_str);
260 }
261 return 0;
262}
263// ---------------------------------------------------------------------------
264// Wide Characters
265// ---------------------------------------------------------------------------
266/** @brief on specified window, at current location, add wchar_t string
267 * @param s surface
268 * @param w window
269 * @param wchar_t string
270 * @return 0 on success, -1 on error
271 */
272int ui_waddwstr(UiSurface *s, ss_t w, const wchar_t *wstr) {
273 if (!s || !wstr)
274 return -1;
275 while (*wstr != L'\0')
276 ncplane_putwc_yx(s->mplane[w], -1, -1, *wstr++);
277 return 0;
278}
279/** @brief on specified window, move to y, x, add wchar_t string
280 * @param s surface
281 * @param w window
282 * @param wchar_t string
283 * @return 0 on success, -1 on error
284 */
285int ui_mvwaddwstr(UiSurface *s, ss_t w, uint y, uint x, const wchar_t *wstr) {
286 if (!s || !wstr)
287 return -1;
288 while (*wstr != L'\0')
289 ncplane_putwc_yx(s->mplane[w], y, x++, *wstr++);
290 return 0;
291}
292/** @brief on specified window, at current location, add wchar_t string, at most
293 * m columns
294 * @param s surface
295 * @param w window
296 * @param wchar_t string
297 * @param m maximum number of columns to write
298 * @return 0 on success, -1 on error
299 */
300int ui_waddnwstr(UiSurface *s, ss_t w, const wchar_t *wstr, int m) {
301 if (!s || !wstr)
302 return -1;
303 int cols = 0;
304 int width;
305 while (*wstr != L'\0') {
306 width = wcwidth(*wstr);
307 if (width < 0)
308 width = 0;
309 if (cols + width > m)
310 break;
311 ncplane_putwc_yx(s->mplane[w], -1, -1, *wstr++);
312 }
313 return 0;
314}
315/** @brief on specified window, move to y, x, add string, at most m columns
316 * @param s surface
317 * @param w window
318 * @param y row
319 * @param x column
320 * @param wchar_t string
321 * @param m maximum number of columns to write
322 * @return 0 on success, -1 on error
323 */
324int ui_mvwaddnwstr(UiSurface *s, ss_t w, uint y, uint x, const wchar_t *wstr, int m) {
325 if (!s || !wstr)
326 return -1;
327 int cols = 0;
328 int width;
329 while (*wstr != L'\0') {
330 width = wcwidth(*wstr);
331 if (width < 0)
332 width = 0;
333 if (cols + width > m)
334 break;
335 ncplane_putwc_yx(s->mplane[w], y, x++, *wstr++);
336 cols += wcwidth(*wstr);
337 }
338 return 0;
339}
340// ---------------------------------------------------------------------------
341// UiCells
342// ---------------------------------------------------------------------------
343/** @brief on specified window, at current location, add cell
344 * @param s surface
345 * @param w window
346 * @param cell cell string
347 * @return 0 on success, -1 on error
348 */
349int ui_wadd_wch(UiSurface *s, ss_t w, const UiCell *cell) {
350 if (!s)
351 return -1;
352 ncplane_putc(s->mplane[w], cell);
353 return 0;
354}
355/** @brief on specified window, move to y, x, add cell
356 * @param s surface
357 * @param w window
358 * @param y row
359 * @param x column
360 * @param cell cell string
361 * @return 0 on success, -1 on error
362 */
363int ui_mvwadd_wch(UiSurface *s, ss_t w, uint y, uint x, const UiCell *cell) {
364 if (!s)
365 return -1;
366 ncplane_putc_yx(s->mplane[w], y, x, cell);
367 return 0;
368}
369
370/** @brief on specified window, at current location, add cell string
371 * @param s surface
372 * @param w window
373 * @param cell cell string
374 * @return 0 on success, -1 on error
375 */
376int ui_wadd_wchstr(UiSurface *s, ss_t w, const UiCell *cell) {
377 if (!s)
378 return -1;
379 while (cell->gcluster != 0) {
380 ncplane_putc(s->mplane[w], cell);
381 cell++;
382 }
383 return 0;
384}
385/** @brief on specified window, move to y, x, add cell string
386 * @param s surface
387 * @param w window
388 * @param y row
389 * @param x column
390 * @param cell cell string
391 * @return 0 on success, -1 on error
392 */
393int ui_mvwadd_wchstr(UiSurface *s, ss_t w, uint y, uint x, const UiCell *cell) {
394 if (!s)
395 return -1;
396 ui_wmove(s, w, y, x);
397 while (cell->gcluster != 0) {
398 ncplane_putc(s->mplane[w], cell);
399 cell++;
400 }
401 return 0;
402}
403/** @brief on specified window, add cell string, at most m columns
404 * @param s surface
405 * @param w window
406 * @param cell cell string
407 * @param m maximum number of columns to write
408 * @return 0 on success, -1 on error
409 */
410int ui_wadd_wchnstr(UiSurface *s, ss_t w, const UiCell *cell, uint m) {
411 if (!s)
412 return -1;
413 uint cols = 0;
414 while (cell->gcluster != 0 && cols < m) {
415 ncplane_putc(s->mplane[w], cell);
416 cols += cell->width;
417 cell++;
418 }
419 return 0;
420}
421/** @brief on specified window, move to y, x, add cell string, at most m columns
422 * @param s surface
423 * @param w window
424 * @param y row
425 * @param x column
426 * @param cell cell string
427 * @param m maximum number of columns to write
428 * @return 0 on success, -1 on error
429 */
430int ui_mvwadd_wchnstr(UiSurface *s, ss_t w, uint y, uint x, const UiCell *cell, uint m) {
431 if (!s)
432 return -1;
433 ui_wmove(s, w, y, x);
434 uint cols = 0;
435 while (cell->gcluster != 0 && cols < m) {
436 ncplane_putc(s->mplane[w], cell);
437 cols += cell->width;
438 cell++;
439 }
440 return 0;
441}
442/* -------------------------------------------------------------------------
443 Screen managemen t
444 ------------------------------------------------------------------------- */
446 // for (int s = 0; s <= sfc_ptr; s++) {
447 // for (int w = 0; w < 8; w++)
448 // if (ui_surface[s]->mplane[w] != nullptr)
449 // touchwin(ui_surface[s]->mplane[w]);
450 // }
451 // ui_render(ui);
452}
453/* -------------------------------------------------------------------------
454 Image Display
455 ------------------------------------------------------------------------- */
456/** @brief display an image on the terminal using NotCurses
457 * @param nc NotCurses context
458 * @param mm UiMultiMedia structure to hold the image and surface
459 * @param image_file path to the image file
460 * @param y height of the image display area (or -1 for full height)
461 * @param x width of the image display area (or -1 for full width)
462 * @param begy starting row for the image display area (or -1 for top)
463 * @param begx starting column for the image display area (or -1 for left)
464 * @return pointer to the ncvisual structure on success, nullptr on error
465 */
466struct ncvisual *ui_display_image(struct notcurses *nc, UiMultiMedia *mm, const char *image_file, int y, int x, int begy, int begx) {
467 struct ncplane *stdn = notcurses_stdplane(nc);
468 unsigned term_rows, term_cols;
469 ncplane_dim_yx(stdn, &term_rows, &term_cols);
470 mm->ncv = ncvisual_from_file(image_file);
471 if (!mm->ncv) {
472 fprintf(stderr, "Error: Could not load image file.\n");
473 return nullptr;
474 }
475 struct ncvgeom geom;
476 if (ncvisual_geom(nc, mm->ncv, NULL, &geom) < 0) {
477 ncvisual_destroy(mm->ncv);
478 return nullptr;
479 }
480 if (begy == -1)
481 begy = 0;
482 if (begx == -1)
483 begx = 0;
484 if (y == -1)
485 y = (int)term_rows - begy;
486 if (x == -1)
487 x = (int)term_cols - begx;
488 if (begy + y > (int)term_rows)
489 y = (int)term_rows - begy;
490 if (begx + x > (int)term_cols)
491 x = (int)term_cols - begx;
492 int max_rows = y - 2;
493 int max_cols = x - 2;
494 if (max_rows <= 0) {
495 ncvisual_destroy(mm->ncv);
496 return nullptr;
497 }
498 struct ncvisual_options vopts_calc = {
499 .scaling = NCSCALE_SCALE_HIRES,
500 .blitter = NCBLIT_PIXEL,
501 };
502 struct ncplane_options nopts = {
503 .y = begy,
504 .x = x,
505 .rows = max_rows,
506 .cols = max_cols,
507 };
508 struct ncplane *tmp_bound_plane = ncplane_create(stdn, &nopts);
509 if (!tmp_bound_plane) {
510 ncvisual_destroy(mm->ncv);
511 return nullptr;
512 }
513 vopts_calc.n = tmp_bound_plane;
514 if (ncvisual_geom(nc, mm->ncv, &vopts_calc, &geom) < 0) {
515 ncplane_destroy(tmp_bound_plane);
516 ncvisual_destroy(mm->ncv);
517 return nullptr;
518 }
519 unsigned rows = geom.rcelly;
520 unsigned cols = geom.rcellx;
521 // dimensions
522 ncplane_destroy(tmp_bound_plane);
523 mm->sfc = ui_surface_box(stdsfc, BOX, rows + 2, cols + 2, begy, 0, image_file);
524 ui_surface_addwin(mm->sfc, WIN, BOX, rows, cols, 1, 1);
525 struct ncvisual_options vopts = {
526 .n = mm->sfc->mplane[WIN],
527 .scaling = NCSCALE_SCALE_HIRES,
528 .blitter = NCBLIT_PIXEL,
529 };
530 ncvisual_blit(nc, mm->ncv, &vopts);
531 notcurses_render(nc);
532 return mm->ncv;
533}
int ui_draw_ch_yx(UiSurface *s, ss_t w, uint y, uint x, const char c)
Draw a character at a specific position in a surface window.
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
void ui_render()
Render the UI by updating panels and refreshing the display.
Definition ui_ncurses.c:884
int ui_draw_text_n(UiSurface *s, ss_t w, uint y, uint x, const char *text, int m)
Draw a text string at a specific position in a surface window.
int ui_draw_text_fill(UiSurface *s, ss_t w, uint y, uint x, const char *text, int m)
Draw a text string at a specific position in a surface window, filling the remaining space with space...
int ui_draw_text(UiSurface *s, ss_t w, uint y, uint x, const char *text)
on specified window, move to y, x, add string
int ui_wmove(UiSurface *s, ss_t w, uint y, uint x)
Move the cursor to a specified position within a UiSurface.
Definition ui_ncurses.c:653
void ui_restore_wins()
Restore the state of all windows in the UI. This function refreshes the standard screen and all surfa...
int ui_draw_ch(UiSurface *s, ss_t w, const char c)
Draw a character in a surface window.
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
UiSurface * stdsfc
Definition ui_ncurses.c:46
int ui_wclrtobot(UiSurface *s, ss_t w)
Set the style of a surface window.
int ui_wclrtoeol(UiSurface *s, ss_t w)
Clear to the end of the line in a surface window.
int ui_mvwadd_wchnstr(UiSurface *s, ss_t w, uint y, uint x, const UiCell *cmplx_buf, uint n)
Draw a complex character string at a specific position in a surface window, with a maximum length.
int ui_waddstr(UiSurface *s, ss_t w, const char *text)
Draw a text string in a surface window.
int ui_mvwaddnwstr(UiSurface *s, ss_t w, uint y, uint x, const wchar_t *wstr, int m)
Draw a wide-character string at a specific position in a surface window, with a maximum length.
int ui_waddwstr(UiSurface *s, ss_t w, const wchar_t *wstr)
Draw a wide-character string in a surface window.
int ui_mvwaddch(UiSurface *s, ss_t w, uint y, uint x, const char c)
Draw a character in a surface window.
int ui_waddnstr(UiSurface *s, ss_t w, const char *text, int m)
Draw a text string in a surface window, with a maximum length.
int ui_mvwaddnstr(UiSurface *s, ss_t w, uint y, uint x, const char *text, int m)
Draw a text string at a specific position in a surface window, with a maximum length.
int ui_mvwadd_wchstr(UiSurface *s, ss_t w, uint y, uint x, const UiCell *cmplx_buf)
Draw a complex character string at a specific position in a surface window.
int ui_mvwaddwstr(UiSurface *s, ss_t w, uint y, uint x, const wchar_t *wstr)
Draw a wide-character string at a specific position in a surface window.
int ui_mvwaddstr(UiSurface *s, ss_t w, uint y, uint x, const char *text)
Draw a text string at a specific position in a surface window.
int ui_mvwadd_wch(UiSurface *s, ss_t w, uint y, uint x, const UiCell *cell)
Draw a complex character at a specific position in a surface window.
int ui_mvwaddstr_fill(UiSurface *s, ss_t w, uint y, uint x, const char *str, int m)
Draw a text string at a specific position in a surface window, filling the remaining space with space...
int ui_wadd_wch(UiSurface *s, ss_t w, const UiCell *cell)
Draw a complex character in a surface window.
int ui_waddnwstr(UiSurface *s, ss_t w, const wchar_t *wstr, int m)
Draw a wide-character string in a surface window, with a maximum length.
int ui_wadd_wchstr(UiSurface *s, ss_t w, const UiCell *cmplx_buf)
Draw a complex character string in a surface window.
int ui_wadd_wchnstr(UiSurface *s, ss_t w, const UiCell *cmplx_buf, uint n)
Draw a complex character string in a surface window, with a maximum length.
int mk_chimera(UiCell *cell, char c)
create a cell with specified character, using background cell style and channels
struct ncvisual * ui_display_image(struct notcurses *nc, UiMultiMedia *mm, const char *image_file, int y, int x, int begy, int begx)
display an image on the terminal using NotCurses
int ui_waddch(UiSurface *s, ss_t w, const char c)
on specified window, at current location, add character
#define MAXLEN
Definition curskeys.c:15
NcVisual * ncv
Definition ui_backend.h:776
UiSurface * sfc
Definition ui_backend.h:777