1 #ifndef NOTCURSES_NOTCURSES
2 #define NOTCURSES_NOTCURSES
3
4 #include <time.h>
5 #include <ctype.h>
6 #include <wchar.h>
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <string.h>
12 #include <signal.h>
13 #include <limits.h>
14 #include <stdbool.h>
15 #include <notcurses/ncport.h>
16 #include <notcurses/nckeys.h>
17 #include <notcurses/ncseqs.h>
18
19 #ifdef __cplusplus
20 extern "C" {
21 #define RESTRICT
22 #define _Static_assert(...)
23 #else
24 #define RESTRICT restrict
25 #endif
26
27 #ifndef __MINGW64__
28 #define API __attribute__((visibility("default")))
29 #else
30 #define API __declspec(dllexport)
31 #endif
32 #define ALLOC __attribute__((malloc)) __attribute__((warn_unused_result))
33
34 // Get a human-readable string describing the running Notcurses version.
35 API const char* notcurses_version(void);
36 // Cannot be inline, as we want to get the versions of the actual Notcurses
37 // library we loaded, not what we compile against.
38 API void notcurses_version_components(int* major, int* minor, int* patch, int* tweak);
39
40 struct notcurses; // Notcurses state for a given terminal, composed of ncplanes
41 struct ncplane; // a drawable Notcurses surface, composed of cells
42 struct ncvisual; // a visual bit of multimedia opened with LibAV|OIIO
43 struct ncuplot; // uint64_t histogram
44 struct ncdplot; // double histogram
45 struct ncprogbar; // progress bar
46 struct ncfdplane; // i/o wrapper to dump file descriptor to plane
47 struct ncsubproc; // ncfdplane wrapper with subprocess management
48 struct ncselector;// widget supporting selecting 1 from a list of options
49 struct ncmultiselector; // widget supporting selecting 0..n from n options
50 struct ncreader; // widget supporting free string input ala readline
51 struct ncfadectx; // context for a palette fade operation
52 struct nctablet; // grouped item within an ncreel
53 struct ncreel; // hierarchical block-based data browser
54 struct nctab; // grouped item within an nctabbed
55 struct nctabbed; // widget with one tab visible at a time
56 struct ncdirect; // direct mode context
57
58 // we never blit full blocks, but instead spaces (more efficient) with the
59 // background set to the desired foreground. these need be kept in the same
60 // order as the blitters[] definition in lib/blit.c.
61 typedef enum {
62 NCBLIT_DEFAULT, // let the ncvisual pick
63 NCBLIT_1x1, // space, compatible with ASCII
64 NCBLIT_2x1, // halves + 1x1 (space) ▄▀
65 NCBLIT_2x2, // quadrants + 2x1 ▗▐ ▖▀▟▌▙
66 NCBLIT_3x2, // sextants (*NOT* 2x2)
67 NCBLIT_BRAILLE, // 4 rows, 2 cols (braille) ⡀⡄⡆⡇⢀⣀⣄⣆⣇⢠⣠⣤⣦⣧⢰⣰⣴⣶⣷⢸⣸⣼⣾⣿
68 NCBLIT_PIXEL, // pixel graphics
69 // these blitters are suitable only for plots, not general media
70 NCBLIT_4x1, // four vertical levels █▆▄▂
71 NCBLIT_8x1, // eight vertical levels █▇▆▅▄▃▂▁
72 } ncblitter_e;
73
74 // Alignment within a plane or terminal. Left/right-justified, or centered.
75 typedef enum {
76 NCALIGN_UNALIGNED,
77 NCALIGN_LEFT,
78 NCALIGN_CENTER,
79 NCALIGN_RIGHT,
80 } ncalign_e;
81
82 #define NCALIGN_TOP NCALIGN_LEFT
83 #define NCALIGN_BOTTOM NCALIGN_RIGHT
84
85 // How to scale an ncvisual during rendering. NCSCALE_NONE will apply no
86 // scaling. NCSCALE_SCALE scales a visual to the plane's size, maintaining
87 // aspect ratio. NCSCALE_STRETCH stretches and scales the image in an attempt
88 // to fill the entirety of the plane. NCSCALE_NONE_HIRES and
89 // NCSCALE_SCALE_HIRES behave like their counterparts, but admit blitters
90 // which don't preserve aspect ratio.
91 typedef enum {
92 NCSCALE_NONE,
93 NCSCALE_SCALE,
94 NCSCALE_STRETCH,
95 NCSCALE_NONE_HIRES,
96 NCSCALE_SCALE_HIRES,
97 } ncscale_e;
98
99 // background cannot be highcontrast, only foreground
100 #define NCALPHA_HIGHCONTRAST 0x30000000ull
101 #define NCALPHA_TRANSPARENT 0x20000000ull
102 #define NCALPHA_BLEND 0x10000000ull
103 #define NCALPHA_OPAQUE 0x00000000ull
104
105 // we support palette-indexed color up to 8 bits.
106 #define NCPALETTESIZE 256
107
108 // Does this glyph completely obscure the background? If so, there's no need
109 // to emit a background when rasterizing, a small optimization. These are
110 // also used to track regions into which we must not cellblit.
111 #define NC_NOBACKGROUND_MASK 0x8700000000000000ull
112 // if this bit is set, we are *not* using the default background color
113 #define NC_BGDEFAULT_MASK 0x0000000040000000ull
114 // extract these bits to get the background RGB value
115 #define NC_BG_RGB_MASK 0x0000000000ffffffull
116 // if this bit *and* NC_BGDEFAULT_MASK are set, we're using a
117 // palette-indexed background color
118 #define NC_BG_PALETTE 0x0000000008000000ull
119 // extract these bits to get the background alpha mask
120 #define NC_BG_ALPHA_MASK 0x30000000ull
121
122 // initialize a 32-bit channel pair with specified RGB
123 #define NCCHANNEL_INITIALIZER(r, g, b) \
124 (((uint32_t)r << 16u) + ((uint32_t)g << 8u) + (b) + NC_BGDEFAULT_MASK)
125
126 // initialize a 64-bit channel pair with specified RGB fg/bg
127 #define NCCHANNELS_INITIALIZER(fr, fg, fb, br, bg, bb) \
128 ((NCCHANNEL_INITIALIZER(fr, fg, fb) << 32ull) + \
129 (NCCHANNEL_INITIALIZER(br, bg, bb)))
130
131 // These lowest-level functions manipulate a channel encodings directly. Users
132 // will typically manipulate ncplanes' and nccells' channels through their
133 // APIs, rather than calling these explicitly.
134
135 // Extract the 2-bit alpha component from a 32-bit channel. It is not
136 // shifted down, and can be directly compared to NCALPHA_* values.
137 static inline unsigned
ncchannel_alpha(uint32_t channel)138 ncchannel_alpha(uint32_t channel){
139 return channel & NC_BG_ALPHA_MASK;
140 }
141
142 // Set the 2-bit alpha component of the 32-bit channel. Background channels
143 // must not be set to NCALPHA_HIGHCONTRAST. It is an error if alpha contains
144 // any bits other than NCALPHA_*.
145 static inline int
ncchannel_set_alpha(uint32_t * channel,unsigned alpha)146 ncchannel_set_alpha(uint32_t* channel, unsigned alpha){
147 if(alpha & ~NC_BG_ALPHA_MASK){
148 return -1;
149 }
150 *channel = alpha | (*channel & ~NC_BG_ALPHA_MASK);
151 if(alpha != NCALPHA_OPAQUE){
152 *channel |= NC_BGDEFAULT_MASK;
153 }
154 return 0;
155 }
156
157 // Is this channel using the "default color" rather than RGB/palette-indexed?
158 static inline bool
ncchannel_default_p(uint32_t channel)159 ncchannel_default_p(uint32_t channel){
160 return !(channel & NC_BGDEFAULT_MASK);
161 }
162
163 // Mark the channel as using its default color. Alpha is set opaque.
164 static inline uint32_t
ncchannel_set_default(uint32_t * channel)165 ncchannel_set_default(uint32_t* channel){
166 *channel &= ~NC_BGDEFAULT_MASK; // turn off not-default bit
167 ncchannel_set_alpha(channel, NCALPHA_OPAQUE);
168 return *channel;
169 }
170
171 // Is this channel using palette-indexed color?
172 static inline bool
ncchannel_palindex_p(uint32_t channel)173 ncchannel_palindex_p(uint32_t channel){
174 return !ncchannel_default_p(channel) && (channel & NC_BG_PALETTE);
175 }
176
177 // Extract the palette index from a channel. Only valid if
178 // ncchannel_palindex_p() would return true for the channel.
179 static inline unsigned
ncchannel_palindex(uint32_t channel)180 ncchannel_palindex(uint32_t channel){
181 return channel & 0xff;
182 }
183
184 // Mark the channel as using the specified palette color. It is an error if
185 // the index is negative, or greater than NCPALETTESIZE. Alpha is set opaque.
186 static inline int
ncchannel_set_palindex(uint32_t * channel,int idx)187 ncchannel_set_palindex(uint32_t* channel, int idx){
188 if(idx < 0 || idx >= NCPALETTESIZE){
189 return -1;
190 }
191 ncchannel_set_alpha(channel, NCALPHA_OPAQUE);
192 *channel &= 0xff000000ull;
193 *channel |= NC_BGDEFAULT_MASK | NC_BG_PALETTE | idx;
194 return 0;
195 }
196
197 // Is this channel using RGB color?
198 static inline bool
ncchannel_rgb_p(uint32_t channel)199 ncchannel_rgb_p(uint32_t channel){
200 // bitwise or is intentional (allows compiler more freedom)
201 return !(ncchannel_default_p(channel) | ncchannel_palindex_p(channel));
202 }
203
204 // Extract the 8-bit red component from a 32-bit channel. Only valid if
205 // ncchannel_rgb_p() would return true for the channel.
206 static inline unsigned
ncchannel_r(uint32_t channel)207 ncchannel_r(uint32_t channel){
208 return (channel & 0xff0000u) >> 16u;
209 }
210
211 // Extract the 8-bit green component from a 32-bit channel. Only valid if
212 // ncchannel_rgb_p() would return true for the channel.
213 static inline unsigned
ncchannel_g(uint32_t channel)214 ncchannel_g(uint32_t channel){
215 return (channel & 0x00ff00u) >> 8u;
216 }
217
218 // Extract the 8-bit blue component from a 32-bit channel. Only valid if
219 // ncchannel_rgb_p() would return true for the channel.
220 static inline unsigned
ncchannel_b(uint32_t channel)221 ncchannel_b(uint32_t channel){
222 return (channel & 0x0000ffu);
223 }
224
225 // Extract the three 8-bit R/G/B components from a 32-bit channel.
226 // Only valid if ncchannel_rgb_p() would return true for the channel.
227 static inline unsigned
ncchannel_rgb8(uint32_t channel,unsigned * RESTRICT r,unsigned * RESTRICT g,unsigned * RESTRICT b)228 ncchannel_rgb8(uint32_t channel, unsigned* RESTRICT r, unsigned* RESTRICT g,
229 unsigned* RESTRICT b){
230 *r = ncchannel_r(channel);
231 *g = ncchannel_g(channel);
232 *b = ncchannel_b(channel);
233 return channel;
234 }
235
236 // Set the three 8-bit components of a 32-bit channel, and mark it as not using
237 // the default color. Retain the other bits unchanged. Any value greater than
238 // 255 will result in a return of -1 and no change to the channel.
239 static inline int
ncchannel_set_rgb8(uint32_t * channel,unsigned r,unsigned g,unsigned b)240 ncchannel_set_rgb8(uint32_t* channel, unsigned r, unsigned g, unsigned b){
241 if(r >= 256 || g >= 256 || b >= 256){
242 return -1;
243 }
244 uint32_t c = (r << 16u) | (g << 8u) | b;
245 // clear the existing rgb bits, clear the palette index indicator, set
246 // the not-default bit, and or in the new rgb.
247 *channel = (*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | c;
248 return 0;
249 }
250
251 // Same, but provide an assembled, packed 24 bits of rgb.
252 static inline int
ncchannel_set(uint32_t * channel,uint32_t rgb)253 ncchannel_set(uint32_t* channel, uint32_t rgb){
254 if(rgb > 0xffffffu){
255 return -1;
256 }
257 *channel = (*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | rgb;
258 return 0;
259 }
260
261 // Set the three 8-bit components of a 32-bit channel, and mark it as not using
262 // the default color. Retain the other bits unchanged. r, g, and b will be
263 // clipped to the range [0..255].
264 static inline void
ncchannel_set_rgb8_clipped(uint32_t * channel,int r,int g,int b)265 ncchannel_set_rgb8_clipped(uint32_t* channel, int r, int g, int b){
266 if(r >= 256){
267 r = 255;
268 }
269 if(g >= 256){
270 g = 255;
271 }
272 if(b >= 256){
273 b = 255;
274 }
275 if(r <= -1){
276 r = 0;
277 }
278 if(g <= -1){
279 g = 0;
280 }
281 if(b <= -1){
282 b = 0;
283 }
284 uint32_t c = (r << 16u) | (g << 8u) | b;
285 *channel = (*channel & ~(NC_BG_RGB_MASK | NC_BG_PALETTE)) | NC_BGDEFAULT_MASK | c;
286 }
287
288 // Extract the 32-bit background channel from a channel pair.
289 static inline uint32_t
ncchannels_bchannel(uint64_t channels)290 ncchannels_bchannel(uint64_t channels){
291 return channels & 0xfffffffflu;
292 }
293
294 // Extract the 32-bit foreground channel from a channel pair.
295 static inline uint32_t
ncchannels_fchannel(uint64_t channels)296 ncchannels_fchannel(uint64_t channels){
297 return ncchannels_bchannel(channels >> 32u);
298 }
299
300 static inline bool
ncchannels_bg_rgb_p(uint64_t channels)301 ncchannels_bg_rgb_p(uint64_t channels){
302 return ncchannel_rgb_p(ncchannels_bchannel(channels));
303 }
304
305 static inline bool
ncchannels_fg_rgb_p(uint64_t channels)306 ncchannels_fg_rgb_p(uint64_t channels){
307 return ncchannel_rgb_p(ncchannels_fchannel(channels));
308 }
309
310 // Extract 2 bits of background alpha from 'channels', shifted to LSBs.
311 static inline unsigned
ncchannels_bg_alpha(uint64_t channels)312 ncchannels_bg_alpha(uint64_t channels){
313 return ncchannel_alpha(ncchannels_bchannel(channels));
314 }
315
316 // Set the 32-bit background channel of a channel pair.
317 static inline uint64_t
ncchannels_set_bchannel(uint64_t * channels,uint32_t channel)318 ncchannels_set_bchannel(uint64_t* channels, uint32_t channel){
319 return *channels = (*channels & 0xffffffff00000000llu) | channel;
320 }
321
322 // Set the 32-bit foreground channel of a channel pair.
323 static inline uint64_t
ncchannels_set_fchannel(uint64_t * channels,uint32_t channel)324 ncchannels_set_fchannel(uint64_t* channels, uint32_t channel){
325 return *channels = (*channels & 0xfffffffflu) | ((uint64_t)channel << 32u);
326 }
327
328 // Set the 2-bit alpha component of the background channel.
329 static inline int
ncchannels_set_bg_alpha(uint64_t * channels,unsigned alpha)330 ncchannels_set_bg_alpha(uint64_t* channels, unsigned alpha){
331 if(alpha == NCALPHA_HIGHCONTRAST){ // forbidden for background alpha
332 return -1;
333 }
334 uint32_t channel = ncchannels_bchannel(*channels);
335 if(ncchannel_set_alpha(&channel, alpha) < 0){
336 return -1;
337 }
338 ncchannels_set_bchannel(channels, channel);
339 return 0;
340 }
341
342 // Extract 2 bits of foreground alpha from 'channels', shifted to LSBs.
343 static inline unsigned
ncchannels_fg_alpha(uint64_t channels)344 ncchannels_fg_alpha(uint64_t channels){
345 return ncchannel_alpha(ncchannels_fchannel(channels));
346 }
347
348 // Set the 2-bit alpha component of the foreground channel.
349 static inline int
ncchannels_set_fg_alpha(uint64_t * channels,unsigned alpha)350 ncchannels_set_fg_alpha(uint64_t* channels, unsigned alpha){
351 uint32_t channel = ncchannels_fchannel(*channels);
352 if(ncchannel_set_alpha(&channel, alpha) < 0){
353 return -1;
354 }
355 *channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
356 return 0;
357 }
358
359 // Returns the channels with the fore- and background's color information
360 // swapped, but without touching housekeeping bits. Alpha is retained unless
361 // it would lead to an illegal state: HIGHCONTRAST, TRANSPARENT, and BLEND
362 // are taken to OPAQUE unless the new value is RGB.
363 static inline uint64_t
ncchannels_reverse(uint64_t channels)364 ncchannels_reverse(uint64_t channels){
365 const uint64_t raw = ((uint64_t)ncchannels_bchannel(channels) << 32u) +
366 ncchannels_fchannel(channels);
367 const uint64_t statemask = ((NC_NOBACKGROUND_MASK | NC_BG_ALPHA_MASK) << 32u) |
368 NC_NOBACKGROUND_MASK | NC_BG_ALPHA_MASK;
369 uint64_t ret = raw & ~statemask;
370 ret |= channels & statemask;
371 if(ncchannels_bg_alpha(ret) != NCALPHA_OPAQUE){
372 if(!ncchannels_bg_rgb_p(ret)){
373 ncchannels_set_bg_alpha(&ret, NCALPHA_OPAQUE);
374 }
375 }
376 if(ncchannels_fg_alpha(ret) != NCALPHA_OPAQUE){
377 if(!ncchannels_fg_rgb_p(ret)){
378 ncchannels_set_fg_alpha(&ret, NCALPHA_OPAQUE);
379 }
380 }
381 return ret;
382 }
383
384 // Creates a new channel pair using 'fchan' as the foreground channel
385 // and 'bchan' as the background channel.
386 static inline uint64_t
ncchannels_combine(uint32_t fchan,uint32_t bchan)387 ncchannels_combine(uint32_t fchan, uint32_t bchan){
388 uint64_t channels = 0;
389 ncchannels_set_fchannel(&channels, fchan);
390 ncchannels_set_bchannel(&channels, bchan);
391 return channels;
392 }
393
394 static inline unsigned
ncchannels_fg_palindex(uint64_t channels)395 ncchannels_fg_palindex(uint64_t channels){
396 return ncchannel_palindex(ncchannels_fchannel(channels));
397 }
398
399 static inline unsigned
ncchannels_bg_palindex(uint64_t channels)400 ncchannels_bg_palindex(uint64_t channels){
401 return ncchannel_palindex(ncchannels_bchannel(channels));
402 }
403
404 // Extract 24 bits of foreground RGB from 'channels', shifted to LSBs.
405 static inline uint32_t
ncchannels_fg_rgb(uint64_t channels)406 ncchannels_fg_rgb(uint64_t channels){
407 return ncchannels_fchannel(channels) & NC_BG_RGB_MASK;
408 }
409
410 // Extract 24 bits of background RGB from 'channels', shifted to LSBs.
411 static inline uint32_t
ncchannels_bg_rgb(uint64_t channels)412 ncchannels_bg_rgb(uint64_t channels){
413 return ncchannels_bchannel(channels) & NC_BG_RGB_MASK;
414 }
415
416 // Extract 24 bits of foreground RGB from 'channels', split into subchannels.
417 static inline uint32_t
ncchannels_fg_rgb8(uint64_t channels,unsigned * r,unsigned * g,unsigned * b)418 ncchannels_fg_rgb8(uint64_t channels, unsigned* r, unsigned* g, unsigned* b){
419 return ncchannel_rgb8(ncchannels_fchannel(channels), r, g, b);
420 }
421
422 // Extract 24 bits of background RGB from 'channels', split into subchannels.
423 static inline uint32_t
ncchannels_bg_rgb8(uint64_t channels,unsigned * r,unsigned * g,unsigned * b)424 ncchannels_bg_rgb8(uint64_t channels, unsigned* r, unsigned* g, unsigned* b){
425 return ncchannel_rgb8(ncchannels_bchannel(channels), r, g, b);
426 }
427
428 // Set the r, g, and b channels for the foreground component of this 64-bit
429 // 'channels' variable, and mark it as not using the default color.
430 static inline int
ncchannels_set_fg_rgb8(uint64_t * channels,unsigned r,unsigned g,unsigned b)431 ncchannels_set_fg_rgb8(uint64_t* channels, unsigned r, unsigned g, unsigned b){
432 uint32_t channel = ncchannels_fchannel(*channels);
433 if(ncchannel_set_rgb8(&channel, r, g, b) < 0){
434 return -1;
435 }
436 *channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
437 return 0;
438 }
439
440 // Same, but clips to [0..255].
441 static inline void
ncchannels_set_fg_rgb8_clipped(uint64_t * channels,int r,int g,int b)442 ncchannels_set_fg_rgb8_clipped(uint64_t* channels, int r, int g, int b){
443 uint32_t channel = ncchannels_fchannel(*channels);
444 ncchannel_set_rgb8_clipped(&channel, r, g, b);
445 *channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
446 }
447
448 static inline int
ncchannels_set_fg_palindex(uint64_t * channels,int idx)449 ncchannels_set_fg_palindex(uint64_t* channels, int idx){
450 uint32_t channel = ncchannels_fchannel(*channels);
451 if(ncchannel_set_palindex(&channel, idx) < 0){
452 return -1;
453 }
454 *channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
455 return 0;
456 }
457
458 // Same, but set an assembled 24 bit channel at once.
459 static inline int
ncchannels_set_fg_rgb(uint64_t * channels,unsigned rgb)460 ncchannels_set_fg_rgb(uint64_t* channels, unsigned rgb){
461 uint32_t channel = ncchannels_fchannel(*channels);
462 if(ncchannel_set(&channel, rgb) < 0){
463 return -1;
464 }
465 *channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
466 return 0;
467 }
468
469 // Set the r, g, and b channels for the background component of this 64-bit
470 // 'channels' variable, and mark it as not using the default color.
471 static inline int
ncchannels_set_bg_rgb8(uint64_t * channels,unsigned r,unsigned g,unsigned b)472 ncchannels_set_bg_rgb8(uint64_t* channels, unsigned r, unsigned g, unsigned b){
473 uint32_t channel = ncchannels_bchannel(*channels);
474 if(ncchannel_set_rgb8(&channel, r, g, b) < 0){
475 return -1;
476 }
477 ncchannels_set_bchannel(channels, channel);
478 return 0;
479 }
480
481 // Same, but clips to [0..255].
482 static inline void
ncchannels_set_bg_rgb8_clipped(uint64_t * channels,int r,int g,int b)483 ncchannels_set_bg_rgb8_clipped(uint64_t* channels, int r, int g, int b){
484 uint32_t channel = ncchannels_bchannel(*channels);
485 ncchannel_set_rgb8_clipped(&channel, r, g, b);
486 ncchannels_set_bchannel(channels, channel);
487 }
488
489 // Set the cell's background palette index, set the background palette index
490 // bit, set it background-opaque, and clear the background default color bit.
491 static inline int
ncchannels_set_bg_palindex(uint64_t * channels,int idx)492 ncchannels_set_bg_palindex(uint64_t* channels, int idx){
493 uint32_t channel = ncchannels_bchannel(*channels);
494 if(ncchannel_set_palindex(&channel, idx) < 0){
495 return -1;
496 }
497 ncchannels_set_bchannel(channels, channel);
498 return 0;
499 }
500
501 // Same, but set an assembled 24 bit channel at once.
502 static inline int
ncchannels_set_bg_rgb(uint64_t * channels,unsigned rgb)503 ncchannels_set_bg_rgb(uint64_t* channels, unsigned rgb){
504 uint32_t channel = ncchannels_bchannel(*channels);
505 if(ncchannel_set(&channel, rgb) < 0){
506 return -1;
507 }
508 ncchannels_set_bchannel(channels, channel);
509 return 0;
510 }
511
512 // Is the foreground using the "default foreground color"?
513 static inline bool
ncchannels_fg_default_p(uint64_t channels)514 ncchannels_fg_default_p(uint64_t channels){
515 return ncchannel_default_p(ncchannels_fchannel(channels));
516 }
517
518 // Is the foreground using indexed palette color?
519 static inline bool
ncchannels_fg_palindex_p(uint64_t channels)520 ncchannels_fg_palindex_p(uint64_t channels){
521 return ncchannel_palindex_p(ncchannels_fchannel(channels));
522 }
523
524 // Is the background using the "default background color"? The "default
525 // background color" must generally be used to take advantage of
526 // terminal-effected transparency.
527 static inline bool
ncchannels_bg_default_p(uint64_t channels)528 ncchannels_bg_default_p(uint64_t channels){
529 return ncchannel_default_p(ncchannels_bchannel(channels));
530 }
531
532 // Is the background using indexed palette color?
533 static inline bool
ncchannels_bg_palindex_p(uint64_t channels)534 ncchannels_bg_palindex_p(uint64_t channels){
535 return ncchannel_palindex_p(ncchannels_bchannel(channels));
536 }
537
538 // Mark the foreground channel as using its default color.
539 static inline uint64_t
ncchannels_set_fg_default(uint64_t * channels)540 ncchannels_set_fg_default(uint64_t* channels){
541 uint32_t channel = ncchannels_fchannel(*channels);
542 ncchannel_set_default(&channel);
543 ncchannels_set_fchannel(channels, channel);
544 return *channels;
545 }
546
547 // Mark the background channel as using its default color.
548 static inline uint64_t
ncchannels_set_bg_default(uint64_t * channels)549 ncchannels_set_bg_default(uint64_t* channels){
550 uint32_t channel = ncchannels_bchannel(*channels);
551 ncchannel_set_default(&channel);
552 ncchannels_set_bchannel(channels, channel);
553 return *channels;
554 }
555
556 // 0x0--0x10ffff can be UTF-8-encoded with only 4 bytes
557 #define WCHAR_MAX_UTF8BYTES 4
558
559 // Returns the number of columns occupied by the longest valid prefix of a
560 // multibyte (UTF-8) string. If an invalid character is encountered, -1 will be
561 // returned, and the number of valid bytes and columns will be written into
562 // *|validbytes| and *|validwidth| (assuming them non-NULL). If the entire
563 // string is valid, *|validbytes| and *|validwidth| reflect the entire string.
564 API int ncstrwidth(const char* egcs, int* validbytes, int* validwidth);
565
566 // input functions like notcurses_get() return ucs32-encoded uint32_t. convert
567 // a series of uint32_t to utf8. result must be at least 4 bytes per input
568 // uint32_t (6 bytes per uint32_t will future-proof against Unicode expansion).
569 // the number of bytes used is returned, or -1 if passed illegal ucs32, or too
570 // small of a buffer.
571 API int notcurses_ucs32_to_utf8(const uint32_t* ucs32, unsigned ucs32count,
572 unsigned char* resultbuf, size_t buflen);
573
574 // An nccell corresponds to a single character cell on some plane, which can be
575 // occupied by a single grapheme cluster (some root spacing glyph, along with
576 // possible combining characters, which might span multiple columns). At any
577 // cell, we can have a theoretically arbitrarily long UTF-8 EGC, a foreground
578 // color, a background color, and an attribute set. Valid grapheme cluster
579 // contents include:
580 //
581 // * A NUL terminator,
582 // * A single control character, followed by a NUL terminator,
583 // * At most one spacing character, followed by zero or more nonspacing
584 // characters, followed by a NUL terminator.
585 //
586 // Multi-column characters can only have a single style/color throughout.
587 // Existence is suffering, and thus wcwidth() is not reliable. It's just
588 // quoting whether or not the EGC contains a "Wide Asian" double-width
589 // character. This is set for some things, like most emoji, and not set for
590 // other things, like cuneiform. True display width is a *function of the
591 // font and terminal*. Among the longest Unicode codepoints is
592 //
593 // U+FDFD ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM ﷽
594 //
595 // wcwidth() rather optimistically claims this most exalted glyph to occupy
596 // a single column. BiDi text is too complicated for me to even get into here.
597 // Be assured there are no easy answers; ours is indeed a disturbing Universe.
598 //
599 // Each nccell occupies 16 static bytes (128 bits). The surface is thus ~1.6MB
600 // for a (pretty large) 500x200 terminal. At 80x43, it's less than 64KB.
601 // Dynamic requirements (the egcpool) can add up to 16MB to an ncplane, but
602 // such large pools are unlikely in common use.
603 //
604 // We implement some small alpha compositing. Foreground and background both
605 // have two bits of inverted alpha. The actual grapheme written to a cell is
606 // the topmost non-zero grapheme. If its alpha is 00, its foreground color is
607 // used unchanged. If its alpha is 10, its foreground color is derived entirely
608 // from cells underneath it. Otherwise, the result will be a composite.
609 // Likewise for the background. If the bottom of a coordinate's zbuffer is
610 // reached with a cumulative alpha of zero, the default is used. In this way,
611 // a terminal configured with transparent background can be supported through
612 // multiple occluding ncplanes. A foreground alpha of 11 requests high-contrast
613 // text (relative to the computed background). A background alpha of 11 is
614 // currently forbidden.
615 //
616 // Default color takes precedence over palette or RGB, and cannot be used with
617 // transparency. Indexed palette takes precedence over RGB. It cannot
618 // meaningfully set transparency, but it can be mixed into a cascading color.
619 // RGB is used if neither default terminal colors nor palette indexing are in
620 // play, and fully supports all transparency options.
621 //
622 // This structure is exposed only so that most functions can be inlined. Do not
623 // directly modify or access the fields of this structure; use the API.
624 typedef struct nccell {
625 // These 32 bits, together with the associated plane's associated egcpool,
626 // completely define this cell's EGC. Unless the EGC requires more than four
627 // bytes to encode as UTF-8, it will be inlined here. If more than four bytes
628 // are required, it will be spilled into the egcpool. In either case, there's
629 // a NUL-terminated string available without copying, because (1) the egcpool
630 // is all NUL-terminated sequences and (2) the fifth byte of this struct (the
631 // gcluster_backstop field, see below) is guaranteed to be zero, as are any
632 // unused bytes in gcluster.
633 //
634 // The gcluster + gcluster_backstop thus form a valid C string of between 0
635 // and 4 non-NUL bytes. Interpreting them in this fashion requires that
636 // gcluster be stored as a little-endian number (strings have no byte order).
637 // This gives rise to three simple rules:
638 //
639 // * when storing to gcluster from a numeric, always use htole()
640 // * when loading from gcluster for numeric use, always use htole()
641 // * when referencing gcluster as a string, always use a pointer cast
642 //
643 // Uses of gcluster ought thus always have exactly one htole() or pointer
644 // cast associated with them, and we otherwise always work as host-endian.
645 //
646 // A spilled EGC is indicated by the value 0x01XXXXXX. This cannot alias a
647 // true supra-ASCII EGC, because UTF-8 only encodes bytes <= 0x80 when they
648 // are single-byte ASCII-derived values. The XXXXXX is interpreted as a 24-bit
649 // index into the egcpool. These pools may thus be up to 16MB.
650 //
651 // The cost of this scheme is that the character 0x01 (SOH) cannot be encoded
652 // in a nccell, which we want anyway. It must not be allowed through the API,
653 // or havoc will result.
654 uint32_t gcluster; // 4B → 4B little endian EGC
655 uint8_t gcluster_backstop; // 1B → 5B (8 bits of zero)
656 // we store the column width in this field. for a multicolumn EGC of N
657 // columns, there will be N nccells, and each has a width of N...for now.
658 // eventually, such an EGC will set more than one subsequent cell to
659 // WIDE_RIGHT, and this won't be necessary. it can then be used as a
660 // bytecount. see #1203. FIXME iff width >= 2, the cell is part of a
661 // multicolumn glyph. whether a cell is the left or right side of the glyph
662 // can be determined by checking whether ->gcluster is zero.
663 uint8_t width; // 1B → 6B (8 bits of EGC column width)
664 uint16_t stylemask; // 2B → 8B (16 bits of NCSTYLE_* attributes)
665 // (channels & 0x8000000000000000ull): blitted to upper-left quadrant
666 // (channels & 0x4000000000000000ull): foreground is *not* "default color"
667 // (channels & 0x3000000000000000ull): foreground alpha (2 bits)
668 // (channels & 0x0800000000000000ull): foreground uses palette index
669 // (channels & 0x0400000000000000ull): blitted to upper-right quadrant
670 // (channels & 0x0200000000000000ull): blitted to lower-left quadrant
671 // (channels & 0x0100000000000000ull): blitted to lower-right quadrant
672 // (channels & 0x00ffffff00000000ull): foreground in 3x8 RGB (rrggbb) / pindex
673 // (channels & 0x0000000080000000ull): reserved, must be 0
674 // (channels & 0x0000000040000000ull): background is *not* "default color"
675 // (channels & 0x0000000030000000ull): background alpha (2 bits)
676 // (channels & 0x0000000008000000ull): background uses palette index
677 // (channels & 0x0000000007000000ull): reserved, must be 0
678 // (channels & 0x0000000000ffffffull): background in 3x8 RGB (rrggbb) / pindex
679 // At render time, these 24-bit values are quantized down to terminal
680 // capabilities, if necessary. There's a clear path to 10-bit support should
681 // we one day need it, but keep things cagey for now. "default color" is
682 // best explained by color(3NCURSES). ours is the same concept. until the
683 // "not default color" bit is set, any color you load will be ignored.
684 uint64_t channels; // + 8B == 16B
685 } nccell;
686
687 // do *not* load invalid EGCs using these macros! there is no way for us to
688 // protect against such misuse here. problems *will* ensue. similarly, do not
689 // set channel flags other than colors/alpha. we assign non-printing glyphs
690 // a width of 1 to match utf8_egc_len()'s behavior for whitespace/NUL.
691 #define NCCELL_INITIALIZER(c, s, chan) { .gcluster = (htole(c)), .gcluster_backstop = 0,\
692 .width = (uint8_t)((wcwidth(c) < 0 || !c) ? 1 : wcwidth(c)), .stylemask = (s), .channels = (chan), }
693 // python fails on #define CELL_CHAR_INITIALIZER(c) CELL_INITIALIZER(c, 0, 0)
694 #define NCCELL_CHAR_INITIALIZER(c) { .gcluster = (htole(c)), .gcluster_backstop = 0,\
695 .width = (uint8_t)((wcwidth(c) < 0 || !c) ? 1 : wcwidth(c)), .stylemask = 0, .channels = 0, }
696 // python fails on #define CELL_TRIVIAL_INITIALIZER CELL_CHAR_INITIALIZER(0)
697 #define NCCELL_TRIVIAL_INITIALIZER { .gcluster = 0, .gcluster_backstop = 0,\
698 .width = 1, .stylemask = 0, .channels = 0, }
699
700 static inline void
nccell_init(nccell * c)701 nccell_init(nccell* c){
702 memset(c, 0, sizeof(*c));
703 }
704
705 // Breaks the UTF-8 string in 'gcluster' down, setting up the nccell 'c'.
706 // Returns the number of bytes copied out of 'gcluster', or -1 on failure. The
707 // styling of the cell is left untouched, but any resources are released.
708 API int nccell_load(struct ncplane* n, nccell* c, const char* gcluster);
709
710 // nccell_load(), plus blast the styling with 'attr' and 'channels'.
711 static inline int
nccell_prime(struct ncplane * n,nccell * c,const char * gcluster,uint16_t stylemask,uint64_t channels)712 nccell_prime(struct ncplane* n, nccell* c, const char* gcluster,
713 uint16_t stylemask, uint64_t channels){
714 c->stylemask = stylemask;
715 c->channels = channels;
716 int ret = nccell_load(n, c, gcluster);
717 return ret;
718 }
719
720 // Duplicate 'c' into 'targ'; both must be/will be bound to 'n'. Returns -1 on
721 // failure, and 0 on success.
722 API int nccell_duplicate(struct ncplane* n, nccell* targ, const nccell* c);
723
724 // Release resources held by the nccell 'c'.
725 API void nccell_release(struct ncplane* n, nccell* c);
726
727 // if you want reverse video, try ncchannels_reverse(). if you want blink, try
728 // ncplane_pulse(). if you want protection, put things on a different plane.
729 #define NCSTYLE_MASK 0xffffu
730 #define NCSTYLE_ITALIC 0x0010u
731 #define NCSTYLE_UNDERLINE 0x0008u
732 #define NCSTYLE_UNDERCURL 0x0004u
733 #define NCSTYLE_BOLD 0x0002u
734 #define NCSTYLE_STRUCK 0x0001u
735 #define NCSTYLE_NONE 0
736
737 // Set the specified style bits for the nccell 'c', whether they're actively
738 // supported or not. Only the lower 16 bits are meaningful.
739 static inline void
nccell_set_styles(nccell * c,unsigned stylebits)740 nccell_set_styles(nccell* c, unsigned stylebits){
741 c->stylemask = stylebits & NCSTYLE_MASK;
742 }
743
744 // Extract the style bits from the nccell.
745 static inline uint16_t
nccell_styles(const nccell * c)746 nccell_styles(const nccell* c){
747 return c->stylemask;
748 }
749
750 // Add the specified styles (in the LSBs) to the nccell's existing spec,
751 // whether they're actively supported or not.
752 static inline void
nccell_on_styles(nccell * c,unsigned stylebits)753 nccell_on_styles(nccell* c, unsigned stylebits){
754 c->stylemask |= (stylebits & NCSTYLE_MASK);
755 }
756
757 // Remove the specified styles (in the LSBs) from the nccell's existing spec.
758 static inline void
nccell_off_styles(nccell * c,unsigned stylebits)759 nccell_off_styles(nccell* c, unsigned stylebits){
760 c->stylemask &= ~(stylebits & NCSTYLE_MASK);
761 }
762
763 // Use the default color for the foreground.
764 static inline void
nccell_set_fg_default(nccell * c)765 nccell_set_fg_default(nccell* c){
766 ncchannels_set_fg_default(&c->channels);
767 }
768
769 // Use the default color for the background.
770 static inline void
nccell_set_bg_default(nccell * c)771 nccell_set_bg_default(nccell* c){
772 ncchannels_set_bg_default(&c->channels);
773 }
774
775 static inline int
nccell_set_fg_alpha(nccell * c,int alpha)776 nccell_set_fg_alpha(nccell* c, int alpha){
777 return ncchannels_set_fg_alpha(&c->channels, alpha);
778 }
779
780 static inline int
nccell_set_bg_alpha(nccell * c,int alpha)781 nccell_set_bg_alpha(nccell* c, int alpha){
782 return ncchannels_set_bg_alpha(&c->channels, alpha);
783 }
784
785 // Is the cell part of a multicolumn element?
786 static inline bool
nccell_double_wide_p(const nccell * c)787 nccell_double_wide_p(const nccell* c){
788 return (c->width >= 2);
789 }
790
791 // Is this the right half of a wide character?
792 static inline bool
nccell_wide_right_p(const nccell * c)793 nccell_wide_right_p(const nccell* c){
794 return nccell_double_wide_p(c) && c->gcluster == 0;
795 }
796
797 // Is this the left half of a wide character?
798 static inline bool
nccell_wide_left_p(const nccell * c)799 nccell_wide_left_p(const nccell* c){
800 return nccell_double_wide_p(c) && c->gcluster;
801 }
802
803 // return a pointer to the NUL-terminated EGC referenced by 'c'. this pointer
804 // can be invalidated by any further operation on the plane 'n', so...watch out!
805 API __attribute__ ((returns_nonnull)) const char*
806 nccell_extended_gcluster(const struct ncplane* n, const nccell* c);
807
808 // return the number of columns occupied by 'c'. see ncstrwidth() for an
809 // equivalent for multiple EGCs.
810 static inline unsigned
nccell_cols(const nccell * c)811 nccell_cols(const nccell* c){
812 return c->width ? c->width : 1;
813 }
814
815 // copy the UTF8-encoded EGC out of the nccell. the result is not tied to any
816 // ncplane, and persists across erases / destruction.
817 ALLOC static inline char*
nccell_strdup(const struct ncplane * n,const nccell * c)818 nccell_strdup(const struct ncplane* n, const nccell* c){
819 return strdup(nccell_extended_gcluster(n, c));
820 }
821
822 // Extract the three elements of a nccell.
823 static inline char*
nccell_extract(const struct ncplane * n,const nccell * c,uint16_t * stylemask,uint64_t * channels)824 nccell_extract(const struct ncplane* n, const nccell* c,
825 uint16_t* stylemask, uint64_t* channels){
826 if(stylemask){
827 *stylemask = c->stylemask;
828 }
829 if(channels){
830 *channels = c->channels;
831 }
832 return nccell_strdup(n, c);
833 }
834
835 // Returns true if the two nccells are distinct EGCs, attributes, or channels.
836 // The actual egcpool index needn't be the same--indeed, the planes needn't even
837 // be the same. Only the expanded EGC must be equal. The EGC must be bit-equal;
838 // it would probably be better to test whether they're Unicode-equal FIXME.
839 // probably needs be fixed up for sprixels FIXME.
840 static inline bool
nccellcmp(const struct ncplane * n1,const nccell * RESTRICT c1,const struct ncplane * n2,const nccell * RESTRICT c2)841 nccellcmp(const struct ncplane* n1, const nccell* RESTRICT c1,
842 const struct ncplane* n2, const nccell* RESTRICT c2){
843 if(c1->stylemask != c2->stylemask){
844 return true;
845 }
846 if(c1->channels != c2->channels){
847 return true;
848 }
849 return strcmp(nccell_extended_gcluster(n1, c1), nccell_extended_gcluster(n2, c2));
850 }
851
852 // Load a 7-bit char 'ch' into the nccell 'c'. Returns the number of bytes
853 // used, or -1 on error.
854 static inline int
nccell_load_char(struct ncplane * n,nccell * c,char ch)855 nccell_load_char(struct ncplane* n, nccell* c, char ch){
856 char gcluster[2];
857 gcluster[0] = ch;
858 gcluster[1] = '\0';
859 return nccell_load(n, c, gcluster);
860 }
861
862 // Load a UTF-8 encoded EGC of up to 4 bytes into the nccell 'c'. Returns the
863 // number of bytes used, or -1 on error.
864 static inline int
nccell_load_egc32(struct ncplane * n,nccell * c,uint32_t egc)865 nccell_load_egc32(struct ncplane* n, nccell* c, uint32_t egc){
866 char gcluster[sizeof(egc) + 1];
867 egc = htole(egc);
868 memcpy(gcluster, &egc, sizeof(egc));
869 gcluster[4] = '\0';
870 return nccell_load(n, c, gcluster);
871 }
872
873 // Load a UCS-32 codepoint into the nccell 'c'. Returns the number of bytes
874 // used, or -1 on error.
875 static inline int
nccell_load_ucs32(struct ncplane * n,nccell * c,uint32_t u)876 nccell_load_ucs32(struct ncplane* n, nccell* c, uint32_t u){
877 unsigned char utf8[WCHAR_MAX_UTF8BYTES];
878 if(notcurses_ucs32_to_utf8(&u, 1, utf8, sizeof(utf8)) < 0){
879 return -1;
880 }
881 uint32_t utf8asegc;
882 _Static_assert(WCHAR_MAX_UTF8BYTES == sizeof(utf8asegc),
883 "WCHAR_MAX_UTF8BYTES didn't equal sizeof(uint32_t)");
884 memcpy(&utf8asegc, utf8, sizeof(utf8));
885 return nccell_load_egc32(n, c, utf8asegc);
886 }
887
888 // These log levels consciously map cleanly to those of libav; Notcurses itself
889 // does not use this full granularity. The log level does not affect the opening
890 // and closing banners, which can be disabled via the notcurses_option struct's
891 // 'suppress_banner'. Note that if stderr is connected to the same terminal on
892 // which we're rendering, any kind of logging will disrupt the output (which is
893 // undesirable). The "default" zero value is NCLOGLEVEL_PANIC.
894 typedef enum {
895 NCLOGLEVEL_SILENT = -1,// default. print nothing once fullscreen service begins
896 NCLOGLEVEL_PANIC = 0, // print diagnostics related to catastrophic failure
897 NCLOGLEVEL_FATAL = 1, // we're hanging around, but we've had a horrible fault
898 NCLOGLEVEL_ERROR = 2, // we can't keep doing this, but we can do other things
899 NCLOGLEVEL_WARNING = 3,// you probably don't want what's happening to happen
900 NCLOGLEVEL_INFO = 4, // "standard information"
901 NCLOGLEVEL_VERBOSE = 5,// "detailed information"
902 NCLOGLEVEL_DEBUG = 6, // this is honestly a bit much
903 NCLOGLEVEL_TRACE = 7, // there's probably a better way to do what you want
904 } ncloglevel_e;
905
906 // Bits for notcurses_options->flags.
907
908 // notcurses_init() will call setlocale() to inspect the current locale. If
909 // that locale is "C" or "POSIX", it will call setlocale(LC_ALL, "") to set
910 // the locale according to the LANG environment variable. Ideally, this will
911 // result in UTF8 being enabled, even if the client app didn't call
912 // setlocale() itself. Unless you're certain that you're invoking setlocale()
913 // prior to notcurses_init(), you should not set this bit. Even if you are
914 // invoking setlocale(), this behavior shouldn't be an issue unless you're
915 // doing something weird (setting a locale not based on LANG).
916 #define NCOPTION_INHIBIT_SETLOCALE 0x0001ull
917
918 // We typically try to clear any preexisting bitmaps. If we ought *not* try
919 // to do this, pass NCOPTION_NO_CLEAR_BITMAPS. Note that they might still
920 // get cleared even if this is set, and they might not get cleared even if
921 // this is not set. It's a tough world out there.
922 #define NCOPTION_NO_CLEAR_BITMAPS 0x0002ull
923
924 // We typically install a signal handler for SIGWINCH that generates a resize
925 // event in the notcurses_get() queue. Set to inhibit this handler.
926 #define NCOPTION_NO_WINCH_SIGHANDLER 0x0004ull
927
928 // We typically install a signal handler for SIG{INT, ILL, SEGV, ABRT, TERM,
929 // QUIT} that restores the screen, and then calls the old signal handler. Set
930 // to inhibit registration of these signal handlers.
931 #define NCOPTION_NO_QUIT_SIGHANDLERS 0x0008ull
932
933 // Initialize the standard plane's virtual cursor to match the physical cursor
934 // at context creation time. Together with NCOPTION_NO_ALTERNATE_SCREEN and a
935 // scrolling standard plane, this facilitates easy scrolling-style programs in
936 // rendered mode.
937 #define NCOPTION_PRESERVE_CURSOR 0x0010ull
938
939 // Notcurses typically prints version info in notcurses_init() and performance
940 // info in notcurses_stop(). This inhibits that output.
941 #define NCOPTION_SUPPRESS_BANNERS 0x0020ull
942
943 // If smcup/rmcup capabilities are indicated, Notcurses defaults to making use
944 // of the "alternate screen". This flag inhibits use of smcup/rmcup.
945 #define NCOPTION_NO_ALTERNATE_SCREEN 0x0040ull
946
947 // Do not modify the font. Notcurses might attempt to change the font slightly,
948 // to support certain glyphs (especially on the Linux console). If this is set,
949 // no such modifications will be made. Note that font changes will not affect
950 // anything but the virtual console/terminal in which Notcurses is running.
951 #define NCOPTION_NO_FONT_CHANGES 0x0080ull
952
953 // Input may be freely dropped. This ought be provided when the program does not
954 // intend to handle input. Otherwise, input can accumulate in internal buffers,
955 // eventually preventing Notcurses from processing terminal messages.
956 #define NCOPTION_DRAIN_INPUT 0x0100ull
957
958 // "CLI mode" is just NCOPTION_NO_CLEAR_BITMAPS | NCOPTION_NO_ALTERNATE_SCREEN |
959 // NCOPTION_PRESERVE_CURSOR, plus enabling scrolling on the standard plane.
960
961 // Configuration for notcurses_init().
962 typedef struct notcurses_options {
963 // The name of the terminfo database entry describing this terminal. If NULL,
964 // the environment variable TERM is used. Failure to open the terminal
965 // definition will result in failure to initialize notcurses.
966 const char* termtype;
967 // Progressively higher log levels result in more logging to stderr. By
968 // default, nothing is printed to stderr once fullscreen service begins.
969 ncloglevel_e loglevel;
970 // Desirable margins. If all are 0 (default), we will render to the entirety
971 // of the screen. If the screen is too small, we do what we can--this is
972 // strictly best-effort. Absolute coordinates are relative to the rendering
973 // area ((0, 0) is always the origin of the rendering area).
974 unsigned margin_t, margin_r, margin_b, margin_l;
975 // General flags; see NCOPTION_*. This is expressed as a bitfield so that
976 // future options can be added without reshaping the struct. Undefined bits
977 // must be set to 0.
978 uint64_t flags;
979 } notcurses_options;
980
981 // Lex a margin argument according to the standard Notcurses definition. There
982 // can be either a single number, which will define all margins equally, or
983 // there can be four numbers separated by commas.
984 API int notcurses_lex_margins(const char* op, notcurses_options* opts)
985 __attribute__ ((nonnull (1)));
986
987 // Lex a blitter.
988 API int notcurses_lex_blitter(const char* op, ncblitter_e* blitter)
989 __attribute__ ((nonnull (1)));
990
991 // Get the name of a blitter.
992 API const char* notcurses_str_blitter(ncblitter_e blitter);
993
994 // Lex a scaling mode (one of "none", "stretch", "scale", "hires",
995 // "scalehi", or "inflate").
996 API int notcurses_lex_scalemode(const char* op, ncscale_e* scalemode)
997 __attribute__ ((nonnull (1)));
998
999 // Get the name of a scaling mode.
1000 API const char* notcurses_str_scalemode(ncscale_e scalemode);
1001
1002 // Initialize a Notcurses context on the connected terminal at 'fp'. 'fp' must
1003 // be a tty. You'll usually want stdout. NULL can be supplied for 'fp', in
1004 // which case /dev/tty will be opened. Returns NULL on error, including any
1005 // failure initializing terminfo.
1006 API ALLOC struct notcurses* notcurses_init(const notcurses_options* opts, FILE* fp);
1007
1008 // The same as notcurses_init(), but without any multimedia functionality,
1009 // allowing for a svelter binary. Link with notcurses-core if this is used.
1010 API ALLOC struct notcurses* notcurses_core_init(const notcurses_options* opts, FILE* fp);
1011
1012 // Destroy a Notcurses context. A NULL 'nc' is a no-op.
1013 API int notcurses_stop(struct notcurses* nc);
1014
1015 // Shift to the alternate screen, if available. If already using the alternate
1016 // screen, this returns 0 immediately. If the alternate screen is not
1017 // available, this returns -1 immediately. Entering the alternate screen turns
1018 // off scrolling for the standard plane.
1019 API int notcurses_enter_alternate_screen(struct notcurses* nc)
1020 __attribute__ ((nonnull (1)));
1021
1022 // Exit the alternate screen. Immediately returns 0 if not currently using the
1023 // alternate screen.
1024 API int notcurses_leave_alternate_screen(struct notcurses* nc)
1025 __attribute__ ((nonnull (1)));
1026
1027 // Get a reference to the standard plane (one matching our current idea of the
1028 // terminal size) for this terminal. The standard plane always exists, and its
1029 // origin is always at the uppermost, leftmost cell of the terminal.
1030 API struct ncplane* notcurses_stdplane(struct notcurses* nc)
1031 __attribute__ ((nonnull (1)));
1032 API const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc)
1033 __attribute__ ((nonnull (1)));
1034
1035 // Return the topmost plane of the pile containing 'n'.
1036 API struct ncplane* ncpile_top(struct ncplane* n)
1037 __attribute__ ((nonnull (1)));
1038
1039 // Return the bottommost plane of the pile containing 'n'.
1040 API struct ncplane* ncpile_bottom(struct ncplane* n)
1041 __attribute__ ((nonnull (1)));
1042
1043 // Return the topmost plane of the standard pile.
1044 static inline struct ncplane*
notcurses_top(struct notcurses * n)1045 notcurses_top(struct notcurses* n){
1046 return ncpile_top(notcurses_stdplane(n));
1047 }
1048
1049 // Return the bottommost plane of the standard pile.
1050 static inline struct ncplane*
notcurses_bottom(struct notcurses * n)1051 notcurses_bottom(struct notcurses* n){
1052 return ncpile_bottom(notcurses_stdplane(n));
1053 }
1054
1055 // Renders the pile of which 'n' is a part. Rendering this pile again will blow
1056 // away the render. To actually write out the render, call ncpile_rasterize().
1057 API int ncpile_render(struct ncplane* n)
1058 __attribute__ ((nonnull (1)));
1059
1060 // Make the physical screen match the last rendered frame from the pile of
1061 // which 'n' is a part. This is a blocking call. Don't call this before the
1062 // pile has been rendered (doing so will likely result in a blank screen).
1063 API int ncpile_rasterize(struct ncplane* n)
1064 __attribute__ ((nonnull (1)));
1065
1066 // Renders and rasterizes the standard pile in one shot. Blocking call.
1067 static inline int
notcurses_render(struct notcurses * nc)1068 notcurses_render(struct notcurses* nc){
1069 struct ncplane* stdn = notcurses_stdplane(nc);
1070 if(ncpile_render(stdn)){
1071 return -1;
1072 }
1073 return ncpile_rasterize(stdn);
1074 }
1075
1076 // Perform the rendering and rasterization portion of ncpile_render() and
1077 // ncpile_rasterize(), but do not write the resulting buffer out to the
1078 // terminal. Using this function, the user can control the writeout process.
1079 // The returned buffer must be freed by the caller.
1080 API int ncpile_render_to_buffer(struct ncplane* p, char** buf, size_t* buflen)
1081 __attribute__ ((nonnull (1, 2, 3)));
1082
1083 // Write the last rendered frame, in its entirety, to 'fp'. If a frame has
1084 // not yet been rendered, nothing will be written.
1085 API int ncpile_render_to_file(struct ncplane* p, FILE* fp)
1086 __attribute__ ((nonnull (1, 2)));
1087
1088 // Destroy all ncplanes other than the stdplane.
1089 API void notcurses_drop_planes(struct notcurses* nc)
1090 __attribute__ ((nonnull (1)));
1091
1092 // All input is taken from stdin. We attempt to read a single UTF8-encoded
1093 // Unicode codepoint, *not* an entire Extended Grapheme Cluster. It is also
1094 // possible that we will read a special keypress, i.e. anything that doesn't
1095 // correspond to a Unicode codepoint (e.g. arrow keys, function keys, screen
1096 // resize events, etc.). These are mapped into a Unicode's area beyond the
1097 // 17 65536-entry Planes, starting at U+1115000. See <notcurses/nckeys.h>.
1098 //
1099 // notcurses_get_nblock() is nonblocking. notcurses_get_blocking() blocks
1100 // until a codepoint or special key is read, or until interrupted by a signal.
1101 // notcurses_get() allows an optional timeout to be controlled.
1102 //
1103 // In the case of a valid read, a 32-bit Unicode codepoint is returned. 0 is
1104 // returned to indicate that no input was available. Otherwise (including on
1105 // EOF) (uint32_t)-1 is returned.
1106
1107 // Is the event a synthesized mouse event?
1108 static inline bool
nckey_mouse_p(uint32_t r)1109 nckey_mouse_p(uint32_t r){
1110 return r >= NCKEY_MOTION && r <= NCKEY_BUTTON11;
1111 }
1112
1113 // An input event. Cell coordinates are currently defined only for mouse
1114 // events. It is not guaranteed that we can set the modifiers for a given
1115 // ncinput. We encompass single Unicode codepoints, not complete EGCs.
1116 typedef struct ncinput {
1117 uint32_t id; // Unicode codepoint or synthesized NCKEY event
1118 int y, x; // y/x cell coordinate of event, -1 for undefined
1119 char utf8[5]; // utf8 representation, if one exists
1120 bool alt; // was alt held?
1121 bool shift; // was shift held?
1122 bool ctrl; // was ctrl held?
1123 // FIXME kitty protocol also exposes hyper, meta, caps_lock, num_lock
1124 enum {
1125 NCTYPE_UNKNOWN,
1126 NCTYPE_PRESS,
1127 NCTYPE_REPEAT,
1128 NCTYPE_RELEASE,
1129 } evtype;
1130 int ypx, xpx; // pixel offsets within cell, -1 for undefined
1131 } ncinput;
1132
1133 // compare two ncinput structs for data equality.
1134 static inline bool
ncinput_equal_p(const ncinput * n1,const ncinput * n2)1135 ncinput_equal_p(const ncinput* n1, const ncinput* n2){
1136 if(n1->id != n2->id){
1137 return false;
1138 }
1139 if(n1->y != n2->y || n1->x != n2->x){
1140 return false;
1141 }
1142 if(n1->alt != n2->alt || n1->shift != n2->shift || n1->ctrl != n2->ctrl){
1143 return false;
1144 }
1145 if(n1->evtype != n2->evtype){
1146 return false;
1147 }
1148 return true;
1149 }
1150
1151 // Read a UTF-32-encoded Unicode codepoint from input. This might only be part
1152 // of a larger EGC. Provide a NULL 'ts' to block at length, and otherwise a
1153 // timespec specifying an absolute deadline calculated using CLOCK_MONOTONIC.
1154 // Returns a single Unicode code point, or a synthesized special key constant,
1155 // or (uint32_t)-1 on error. Returns 0 on a timeout. If an event is processed,
1156 // the return value is the 'id' field from that event. 'ni' may be NULL.
1157 API uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts,
1158 ncinput* ni)
1159 __attribute__ ((nonnull (1)));
1160
1161 // Acquire up to 'vcount' ncinputs at the vector 'ni'. The number read will be
1162 // returned, or -1 on error without any reads, 0 on timeout.
1163 API int notcurses_getvec(struct notcurses* n, const struct timespec* ts,
1164 ncinput* ni, int vcount)
1165 __attribute__ ((nonnull (1, 3)));
1166
1167 // Get a file descriptor suitable for input event poll()ing. When this
1168 // descriptor becomes available, you can call notcurses_get_nblock(),
1169 // and input ought be ready. This file descriptor is *not* necessarily
1170 // the file descriptor associated with stdin (but it might be!).
1171 API int notcurses_inputready_fd(struct notcurses* n)
1172 __attribute__ ((nonnull (1)));
1173
1174 // 'ni' may be NULL if the caller is uninterested in event details. If no event
1175 // is immediately ready, returns 0.
1176 static inline uint32_t
notcurses_get_nblock(struct notcurses * n,ncinput * ni)1177 notcurses_get_nblock(struct notcurses* n, ncinput* ni){
1178 struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
1179 return notcurses_get(n, &ts, ni);
1180 }
1181
1182 // 'ni' may be NULL if the caller is uninterested in event details. Blocks
1183 // until an event is processed or a signal is received (including resize events).
1184 static inline uint32_t
notcurses_get_blocking(struct notcurses * n,ncinput * ni)1185 notcurses_get_blocking(struct notcurses* n, ncinput* ni){
1186 return notcurses_get(n, NULL, ni);
1187 }
1188
1189 // Was 'ni' free of modifiers?
1190 static inline bool
ncinput_nomod_p(const ncinput * ni)1191 ncinput_nomod_p(const ncinput* ni){
1192 return !(ni->alt | ni->ctrl | ni->shift);
1193 }
1194
1195 #define NCMICE_NO_EVENTS 0
1196 #define NCMICE_MOVE_EVENT 0x1
1197 #define NCMICE_BUTTON_EVENT 0x2
1198 #define NCMICE_DRAG_EVENT 0x4
1199 #define NCMICE_ALL_EVENTS 0x7
1200
1201 // Enable mice events according to 'eventmask'; an eventmask of 0 will disable
1202 // all mice tracking. On failure, -1 is returned. On success, 0 is returned, and
1203 // mouse events will be published to notcurses_get().
1204 API int notcurses_mice_enable(struct notcurses* n, unsigned eventmask)
1205 __attribute__ ((nonnull (1)));
1206
1207 // Disable mouse events. Any events in the input queue can still be delivered.
1208 __attribute__ ((nonnull (1))) static inline int
notcurses_mice_disable(struct notcurses * n)1209 notcurses_mice_disable(struct notcurses* n){
1210 return notcurses_mice_enable(n, NCMICE_NO_EVENTS);
1211 }
1212
1213 // Disable signals originating from the terminal's line discipline, i.e.
1214 // SIGINT (^C), SIGQUIT (^\), and SIGTSTP (^Z). They are enabled by default.
1215 API int notcurses_linesigs_disable(struct notcurses* n)
1216 __attribute__ ((nonnull (1)));
1217
1218 // Restore signals originating from the terminal's line discipline, i.e.
1219 // SIGINT (^C), SIGQUIT (^\), and SIGTSTP (^Z), if disabled.
1220 API int notcurses_linesigs_enable(struct notcurses* n)
1221 __attribute__ ((nonnull (1)));
1222
1223 // Refresh the physical screen to match what was last rendered (i.e., without
1224 // reflecting any changes since the last call to notcurses_render()). This is
1225 // primarily useful if the screen is externally corrupted, or if an
1226 // NCKEY_RESIZE event has been read and you're not yet ready to render. The
1227 // current screen geometry is returned in 'y' and 'x', if they are not NULL.
1228 API int notcurses_refresh(struct notcurses* n, unsigned* RESTRICT y, unsigned* RESTRICT x)
1229 __attribute__ ((nonnull (1)));
1230
1231 // Extract the Notcurses context to which this plane is attached.
1232 API struct notcurses* ncplane_notcurses(const struct ncplane* n)
1233 __attribute__ ((nonnull (1)));
1234
1235 API const struct notcurses* ncplane_notcurses_const(const struct ncplane* n)
1236 __attribute__ ((nonnull (1)));
1237
1238 // Return the dimensions of this ncplane. y or x may be NULL.
1239 API void ncplane_dim_yx(const struct ncplane* n, unsigned* RESTRICT y, unsigned* RESTRICT x)
1240 __attribute__ ((nonnull (1)));
1241
1242 // Get a reference to the standard plane (one matching our current idea of the
1243 // terminal size) for this terminal. The standard plane always exists, and its
1244 // origin is always at the uppermost, leftmost cell of the terminal.
1245 API struct ncplane* notcurses_stdplane(struct notcurses* nc);
1246 API const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
1247
1248 // notcurses_stdplane(), plus free bonus dimensions written to non-NULL y/x!
1249 static inline struct ncplane*
notcurses_stddim_yx(struct notcurses * nc,unsigned * RESTRICT y,unsigned * RESTRICT x)1250 notcurses_stddim_yx(struct notcurses* nc, unsigned* RESTRICT y, unsigned* RESTRICT x){
1251 struct ncplane* s = notcurses_stdplane(nc); // can't fail
1252 ncplane_dim_yx(s, y, x); // accepts NULL
1253 return s;
1254 }
1255
1256 static inline const struct ncplane*
notcurses_stddim_yx_const(const struct notcurses * nc,unsigned * RESTRICT y,unsigned * RESTRICT x)1257 notcurses_stddim_yx_const(const struct notcurses* nc, unsigned* RESTRICT y, unsigned* RESTRICT x){
1258 const struct ncplane* s = notcurses_stdplane_const(nc); // can't fail
1259 ncplane_dim_yx(s, y, x); // accepts NULL
1260 return s;
1261 }
1262
1263 static inline unsigned
ncplane_dim_y(const struct ncplane * n)1264 ncplane_dim_y(const struct ncplane* n){
1265 unsigned dimy;
1266 ncplane_dim_yx(n, &dimy, NULL);
1267 return dimy;
1268 }
1269
1270 static inline unsigned
ncplane_dim_x(const struct ncplane * n)1271 ncplane_dim_x(const struct ncplane* n){
1272 unsigned dimx;
1273 ncplane_dim_yx(n, NULL, &dimx);
1274 return dimx;
1275 }
1276
1277 // Retrieve pixel geometry for the display region ('pxy', 'pxx'), each cell
1278 // ('celldimy', 'celldimx'), and the maximum displayable bitmap ('maxbmapy',
1279 // 'maxbmapx'). If bitmaps are not supported, or if there is no artificial
1280 // limit on bitmap size, 'maxbmapy' and 'maxbmapx' will be 0. Any of the
1281 // geometry arguments may be NULL.
1282 API void ncplane_pixel_geom(const struct ncplane* n,
1283 unsigned* RESTRICT pxy, unsigned* RESTRICT pxx,
1284 unsigned* RESTRICT celldimy, unsigned* RESTRICT celldimx,
1285 unsigned* RESTRICT maxbmapy, unsigned* RESTRICT maxbmapx)
1286 __attribute__ ((nonnull (1)));
1287
1288 // Return our current idea of the terminal dimensions in rows and cols.
1289 static inline void
notcurses_term_dim_yx(const struct notcurses * n,unsigned * RESTRICT rows,unsigned * RESTRICT cols)1290 notcurses_term_dim_yx(const struct notcurses* n, unsigned* RESTRICT rows, unsigned* RESTRICT cols){
1291 ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
1292 }
1293
1294 // Retrieve the contents of the specified cell as last rendered. Returns the EGC
1295 // or NULL on error. This EGC must be free()d by the caller. The stylemask and
1296 // channels are written to 'stylemask' and 'channels', respectively.
1297 API char* notcurses_at_yx(struct notcurses* nc, unsigned yoff, unsigned xoff,
1298 uint16_t* stylemask, uint64_t* channels)
1299 __attribute__ ((nonnull (1)));
1300
1301 // Horizontal alignment relative to the parent plane. Use ncalign_e for 'x'.
1302 #define NCPLANE_OPTION_HORALIGNED 0x0001ull
1303 // Vertical alignment relative to the parent plane. Use ncalign_e for 'y'.
1304 #define NCPLANE_OPTION_VERALIGNED 0x0002ull
1305 // Maximize relative to the parent plane, modulo the provided margins. The
1306 // margins are best-effort; the plane will always be at least 1 column by
1307 // 1 row. If the margins can be effected, the plane will be sized to all
1308 // remaining space. 'y' and 'x' are overloaded as the top and left margins
1309 // when this flag is used. 'rows' and 'cols' must be 0 when this flag is
1310 // used. This flag is exclusive with both of the alignment flags.
1311 #define NCPLANE_OPTION_MARGINALIZED 0x0004ull
1312 // If this plane is bound to a scrolling plane, it ought *not* scroll along
1313 // with the parent (it will still move with the parent, maintaining its
1314 // relative position, if the parent is moved to a new location).
1315 #define NCPLANE_OPTION_FIXED 0x0008ull
1316 // Enable automatic growth of the plane to accommodate output. Creating a
1317 // plane with this flag is equivalent to immediately calling
1318 // ncplane_set_autogrow(p, true) following plane creation.
1319 #define NCPLANE_OPTION_AUTOGROW 0x0010ull
1320 // Enable vertical scrolling of the plane to accommodate output. Creating a
1321 // plane with this flag is equivalent to immediately calling
1322 // ncplane_set_scrolling(p, true) following plane creation.
1323 #define NCPLANE_OPTION_VSCROLL 0x0020ull
1324
1325 typedef struct ncplane_options {
1326 int y; // vertical placement relative to parent plane
1327 int x; // horizontal placement relative to parent plane
1328 unsigned rows; // rows, must be >0 unless NCPLANE_OPTION_MARGINALIZED
1329 unsigned cols; // columns, must be >0 unless NCPLANE_OPTION_MARGINALIZED
1330 void* userptr; // user curry, may be NULL
1331 const char* name; // name (used only for debugging), may be NULL
1332 int (*resizecb)(struct ncplane*); // callback when parent is resized
1333 uint64_t flags; // closure over NCPLANE_OPTION_*
1334 unsigned margin_b, margin_r; // margins (require NCPLANE_OPTION_MARGINALIZED)
1335 } ncplane_options;
1336
1337 // Create a new ncplane bound to plane 'n', at the offset 'y'x'x' (relative to
1338 // the origin of 'n') and the specified size. The number of 'rows' and 'cols'
1339 // must both be positive. This plane is initially at the top of the z-buffer,
1340 // as if ncplane_move_top() had been called on it. The void* 'userptr' can be
1341 // retrieved (and reset) later. A 'name' can be set, used in debugging.
1342 API ALLOC struct ncplane* ncplane_create(struct ncplane* n, const ncplane_options* nopts)
1343 __attribute__ ((nonnull (1, 2)));
1344
1345 // Same as ncplane_create(), but creates a new pile. The returned plane will
1346 // be the top, bottom, and root of this new pile.
1347 API ALLOC struct ncplane* ncpile_create(struct notcurses* nc, const ncplane_options* nopts)
1348 __attribute__ ((nonnull (1, 2)));
1349
1350 // Utility resize callbacks. When a parent plane is resized, it invokes each
1351 // child's resize callback. Any logic can be run in a resize callback, but
1352 // these are some generically useful ones.
1353
1354 // resize the plane to the visual region's size (used for the standard plane).
1355 API int ncplane_resize_maximize(struct ncplane* n);
1356
1357 // resize the plane to its parent's size, attempting to enforce the margins
1358 // supplied along with NCPLANE_OPTION_MARGINALIZED.
1359 API int ncplane_resize_marginalized(struct ncplane* n);
1360
1361 // realign the plane 'n' against its parent, using the alignments specified
1362 // with NCPLANE_OPTION_HORALIGNED and/or NCPLANE_OPTION_VERALIGNED.
1363 API int ncplane_resize_realign(struct ncplane* n);
1364
1365 // move the plane such that it is entirely within its parent, if possible.
1366 // no resizing is performed.
1367 API int ncplane_resize_placewithin(struct ncplane* n);
1368
1369 // Replace the ncplane's existing resizecb with 'resizecb' (which may be NULL).
1370 // The standard plane's resizecb may not be changed.
1371 API void ncplane_set_resizecb(struct ncplane* n, int(*resizecb)(struct ncplane*));
1372
1373 // Returns the ncplane's current resize callback.
1374 API int (*ncplane_resizecb(const struct ncplane* n))(struct ncplane*);
1375
1376 // Set the plane's name (may be NULL), replacing any current name.
1377 API int ncplane_set_name(struct ncplane* n, const char* name)
1378 __attribute__ ((nonnull (1)));
1379
1380 // Return a heap-allocated copy of the plane's name, or NULL if it has none.
1381 API ALLOC char* ncplane_name(const struct ncplane* n)
1382 __attribute__ ((nonnull (1)));
1383
1384 // Plane 'n' will be unbound from its parent plane, and will be made a bound
1385 // child of 'newparent'. It is an error if 'n' or 'newparent' are NULL. If
1386 // 'newparent' is equal to 'n', 'n' becomes the root of a new pile, unless 'n'
1387 // is already the root of a pile, in which case this is a no-op. Returns 'n'.
1388 // The standard plane cannot be reparented. Any planes bound to 'n' are
1389 // reparented to the previous parent of 'n'.
1390 API struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent)
1391 __attribute__ ((nonnull (1, 2)));
1392
1393 // The same as ncplane_reparent(), except any planes bound to 'n' come along
1394 // with it to its new destination. Their z-order is maintained. If 'newparent'
1395 // is an ancestor of 'n', NULL is returned, and no changes are made.
1396 API struct ncplane* ncplane_reparent_family(struct ncplane* n, struct ncplane* newparent)
1397 __attribute__ ((nonnull (1, 2)));
1398
1399 // Duplicate an existing ncplane. The new plane will have the same geometry,
1400 // will duplicate all content, and will start with the same rendering state.
1401 // The new plane will be immediately above the old one on the z axis, and will
1402 // be bound to the same parent (unless 'n' is a root plane, in which case the
1403 // new plane will be bound to it). Bound planes are *not* duplicated; the new
1404 // plane is bound to the parent of 'n', but has no bound planes.
1405 API ALLOC struct ncplane* ncplane_dup(const struct ncplane* n, void* opaque)
1406 __attribute__ ((nonnull (1)));
1407
1408 // provided a coordinate relative to the origin of 'src', map it to the same
1409 // absolute coordinate relative to the origin of 'dst'. either or both of 'y'
1410 // and 'x' may be NULL. if 'dst' is NULL, it is taken to be the standard plane.
1411 API void ncplane_translate(const struct ncplane* src, const struct ncplane* dst,
1412 int* RESTRICT y, int* RESTRICT x)
1413 __attribute__ ((nonnull (1)));
1414
1415 // Fed absolute 'y'/'x' coordinates, determine whether that coordinate is
1416 // within the ncplane 'n'. If not, return false. If so, return true. Either
1417 // way, translate the absolute coordinates relative to 'n'. If the point is not
1418 // within 'n', these coordinates will not be within the dimensions of the plane.
1419 API bool ncplane_translate_abs(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x)
1420 __attribute__ ((nonnull (1)));
1421
1422 // All planes are created with scrolling disabled. Scrolling can be dynamically
1423 // controlled with ncplane_set_scrolling(). Returns true if scrolling was
1424 // previously enabled, or false if it was disabled.
1425 API bool ncplane_set_scrolling(struct ncplane* n, unsigned scrollp)
1426 __attribute__ ((nonnull (1)));
1427
1428 API bool ncplane_scrolling_p(const struct ncplane* n)
1429 __attribute__ ((nonnull (1)));
1430
1431 // By default, planes are created with autogrow disabled. Autogrow can be
1432 // dynamically controlled with ncplane_set_autogrow(). Returns true if
1433 // autogrow was previously enabled, or false if it was disabled.
1434 API bool ncplane_set_autogrow(struct ncplane* n, unsigned growp)
1435 __attribute__ ((nonnull (1)));
1436
1437 API bool ncplane_autogrow_p(const struct ncplane* n)
1438 __attribute__ ((nonnull (1)));
1439
1440 // Palette API. Some terminals only support 256 colors, but allow the full
1441 // palette to be specified with arbitrary RGB colors. In all cases, it's more
1442 // performant to use indexed colors, since it's much less data to write to the
1443 // terminal. If you can limit yourself to 256 colors, that's probably best.
1444
1445 typedef struct ncpalette {
1446 uint32_t chans[NCPALETTESIZE]; // RGB values as regular ol' channels
1447 } ncpalette;
1448
1449 // Create a new palette store. It will be initialized with notcurses' best
1450 // knowledge of the currently configured palette. The palette upon startup
1451 // cannot be reliably detected, sadly.
1452 API ALLOC ncpalette* ncpalette_new(struct notcurses* nc)
1453 __attribute__ ((nonnull (1)));
1454
1455 // Attempt to configure the terminal with the provided palette 'p'. Does not
1456 // transfer ownership of 'p'; ncpalette_free() can (ought) still be called.
1457 API int ncpalette_use(struct notcurses* nc, const ncpalette* p)
1458 __attribute__ ((nonnull (1, 2)));
1459
1460 // Manipulate entries in the palette store 'p'. These are *not* locked.
1461 static inline int
ncpalette_set_rgb8(ncpalette * p,int idx,unsigned r,unsigned g,unsigned b)1462 ncpalette_set_rgb8(ncpalette* p, int idx, unsigned r, unsigned g, unsigned b){
1463 if(idx < 0 || (size_t)idx > sizeof(p->chans) / sizeof(*p->chans)){
1464 return -1;
1465 }
1466 return ncchannel_set_rgb8(&p->chans[idx], r, g, b);
1467 }
1468
1469 static inline int
ncpalette_set(ncpalette * p,int idx,unsigned rgb)1470 ncpalette_set(ncpalette* p, int idx, unsigned rgb){
1471 if(idx < 0 || (size_t)idx > sizeof(p->chans) / sizeof(*p->chans)){
1472 return -1;
1473 }
1474 return ncchannel_set(&p->chans[idx], rgb);
1475 }
1476
1477 static inline int
ncpalette_get_rgb8(const ncpalette * p,int idx,unsigned * RESTRICT r,unsigned * RESTRICT g,unsigned * RESTRICT b)1478 ncpalette_get_rgb8(const ncpalette* p, int idx, unsigned* RESTRICT r, unsigned* RESTRICT g, unsigned* RESTRICT b){
1479 if(idx < 0 || (size_t)idx > sizeof(p->chans) / sizeof(*p->chans)){
1480 return -1;
1481 }
1482 return ncchannel_rgb8(p->chans[idx], r, g, b);
1483 }
1484
1485 // Free the palette store 'p'.
1486 API void ncpalette_free(ncpalette* p);
1487
1488 // Capabilities, derived from terminfo, environment variables, and queries
1489 typedef struct nccapabilities {
1490 unsigned colors; // size of palette for indexed colors
1491 bool utf8; // are we using utf-8 encoding? from nl_langinfo(3)
1492 bool rgb; // 24bit color? COLORTERM/heuristics/terminfo 'rgb'
1493 bool can_change_colors; // can we change the palette? terminfo 'ccc'
1494 // these are assigned wholly through TERM- and query-based heuristics
1495 bool halfblocks;// we assume halfblocks, but some are known to lack them
1496 bool quadrants; // do we have (good, vetted) Unicode 1 quadrant support?
1497 bool sextants; // do we have (good, vetted) Unicode 13 sextant support?
1498 bool braille; // do we have Braille support? (linux console does not)
1499 } nccapabilities;
1500
1501 // Returns a 16-bit bitmask of supported curses-style attributes
1502 // (NCSTYLE_UNDERLINE, NCSTYLE_BOLD, etc.) The attribute is only
1503 // indicated as supported if the terminal can support it together with color.
1504 // For more information, see the "ncv" capability in terminfo(5).
1505 API uint16_t notcurses_supported_styles(const struct notcurses* nc)
1506 __attribute__ ((nonnull (1))) __attribute__ ((pure));
1507
1508 // Returns the number of simultaneous colors claimed to be supported, or 1 if
1509 // there is no color support. Note that several terminal emulators advertise
1510 // more colors than they actually support, downsampling internally.
1511 API unsigned notcurses_palette_size(const struct notcurses* nc)
1512 __attribute__ ((nonnull (1))) __attribute__ ((pure));
1513
1514 // Returns the name (and sometimes version) of the terminal, as Notcurses
1515 // has been best able to determine.
1516 ALLOC API char* notcurses_detected_terminal(const struct notcurses* nc)
1517 __attribute__ ((nonnull (1)));
1518
1519 API const nccapabilities* notcurses_capabilities(const struct notcurses* n)
1520 __attribute__ ((nonnull (1)));
1521
1522 // pixel blitting implementations. informative only; don't special-case
1523 // based off any of this information!
1524 typedef enum {
1525 NCPIXEL_NONE = 0,
1526 NCPIXEL_SIXEL, // sixel
1527 NCPIXEL_LINUXFB, // linux framebuffer
1528 NCPIXEL_ITERM2, // iTerm2
1529 // C=1 (disabling scrolling) was only introduced in 0.20.0, at the same
1530 // time as animation. prior to this, graphics had to be entirely redrawn
1531 // on any change, and it wasn't possible to use the bottom line.
1532 NCPIXEL_KITTY_STATIC,
1533 // until 0.22.0's introduction of 'a=c' for self-referential composition, we
1534 // had to keep a complete copy of the RGBA data, in case a wiped cell needed
1535 // to be rebuilt. we'd otherwise have to unpack the glyph and store it into
1536 // the auxvec on the fly.
1537 NCPIXEL_KITTY_ANIMATED,
1538 // with 0.22.0, we only ever write transparent cells after writing the
1539 // original image (which we now deflate, since we needn't unpack it later).
1540 // the only data we need keep is the auxvecs.
1541 NCPIXEL_KITTY_SELFREF,
1542 } ncpixelimpl_e;
1543
1544 // Can we blit pixel-accurate bitmaps?
1545 API ncpixelimpl_e notcurses_check_pixel_support(const struct notcurses* nc)
1546 __attribute__ ((nonnull (1))) __attribute__ ((pure));
1547
1548 // Can we set the "hardware" palette? Requires the "ccc" terminfo capability,
1549 // and that the number of colors supported is at least the size of our
1550 // ncpalette structure.
1551 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
nccapability_canchangecolor(const nccapabilities * caps)1552 nccapability_canchangecolor(const nccapabilities* caps){
1553 if(!caps->can_change_colors){
1554 return false;
1555 }
1556 ncpalette* p;
1557 if(caps->colors < sizeof(p->chans) / sizeof(*p->chans)){
1558 return false;
1559 }
1560 return true;
1561 }
1562
1563 // Can we emit 24-bit, three-channel RGB foregrounds and backgrounds?
1564 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_cantruecolor(const struct notcurses * nc)1565 notcurses_cantruecolor(const struct notcurses* nc){
1566 return notcurses_capabilities(nc)->rgb;
1567 }
1568
1569 // Can we directly specify RGB values per cell, or only use palettes?
1570 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canchangecolor(const struct notcurses * nc)1571 notcurses_canchangecolor(const struct notcurses* nc){
1572 return nccapability_canchangecolor(notcurses_capabilities(nc));
1573 }
1574
1575 // Can we fade? Fading requires either the "rgb" or "ccc" terminfo capability.
1576 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canfade(const struct notcurses * n)1577 notcurses_canfade(const struct notcurses* n){
1578 return notcurses_canchangecolor(n) || notcurses_cantruecolor(n);
1579 }
1580
1581 // Can we load images? This requires being built against FFmpeg/OIIO.
1582 API bool notcurses_canopen_images(const struct notcurses* nc)
1583 __attribute__ ((pure));
1584
1585 // Can we load videos? This requires being built against FFmpeg.
1586 API bool notcurses_canopen_videos(const struct notcurses* nc)
1587 __attribute__ ((pure));
1588
1589 // Is our encoding UTF-8? Requires LANG being set to a UTF8 locale.
1590 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canutf8(const struct notcurses * nc)1591 notcurses_canutf8(const struct notcurses* nc){
1592 return notcurses_capabilities(nc)->utf8;
1593 }
1594
1595 // Can we reliably use Unicode halfblocks? Any Unicode implementation can.
1596 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canhalfblock(const struct notcurses * nc)1597 notcurses_canhalfblock(const struct notcurses* nc){
1598 return notcurses_canutf8(nc);
1599 }
1600
1601 // Can we reliably use Unicode quadrants?
1602 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canquadrant(const struct notcurses * nc)1603 notcurses_canquadrant(const struct notcurses* nc){
1604 return notcurses_canutf8(nc) && notcurses_capabilities(nc)->quadrants;
1605 }
1606
1607 // Can we reliably use Unicode 13 sextants?
1608 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_cansextant(const struct notcurses * nc)1609 notcurses_cansextant(const struct notcurses* nc){
1610 return notcurses_canutf8(nc) && notcurses_capabilities(nc)->sextants;
1611 }
1612
1613 // Can we reliably use Unicode Braille?
1614 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canbraille(const struct notcurses * nc)1615 notcurses_canbraille(const struct notcurses* nc){
1616 return notcurses_canutf8(nc) && notcurses_capabilities(nc)->braille;
1617 }
1618
1619 // Can we blit pixel-accurate bitmaps?
1620 __attribute__ ((nonnull (1))) __attribute__ ((pure)) static inline bool
notcurses_canpixel(const struct notcurses * nc)1621 notcurses_canpixel(const struct notcurses* nc){
1622 return notcurses_check_pixel_support(nc) != NCPIXEL_NONE;
1623 }
1624
1625 // whenever a new field is added here, ensure we add the proper rule to
1626 // notcurses_stats_reset(), so that values are preserved in the stash stats.
1627 typedef struct ncstats {
1628 // purely increasing stats
1629 uint64_t renders; // successful ncpile_render() runs
1630 uint64_t writeouts; // successful ncpile_rasterize() runs
1631 uint64_t failed_renders; // aborted renders, should be 0
1632 uint64_t failed_writeouts; // aborted writes
1633 uint64_t raster_bytes; // bytes emitted to ttyfp
1634 int64_t raster_max_bytes; // max bytes emitted for a frame
1635 int64_t raster_min_bytes; // min bytes emitted for a frame
1636 uint64_t render_ns; // nanoseconds spent rendering
1637 int64_t render_max_ns; // max ns spent in render for a frame
1638 int64_t render_min_ns; // min ns spent in render for a frame
1639 uint64_t raster_ns; // nanoseconds spent rasterizing
1640 int64_t raster_max_ns; // max ns spent in raster for a frame
1641 int64_t raster_min_ns; // min ns spent in raster for a frame
1642 uint64_t writeout_ns; // nanoseconds spent writing frames to terminal
1643 int64_t writeout_max_ns; // max ns spent writing out a frame
1644 int64_t writeout_min_ns; // min ns spent writing out a frame
1645 uint64_t cellelisions; // cells we elided entirely thanks to damage maps
1646 uint64_t cellemissions; // total number of cells emitted to terminal
1647 uint64_t fgelisions; // RGB fg elision count
1648 uint64_t fgemissions; // RGB fg emissions
1649 uint64_t bgelisions; // RGB bg elision count
1650 uint64_t bgemissions; // RGB bg emissions
1651 uint64_t defaultelisions; // default color was emitted
1652 uint64_t defaultemissions; // default color was elided
1653 uint64_t refreshes; // refresh requests (non-optimized redraw)
1654 uint64_t sprixelemissions; // sprixel draw count
1655 uint64_t sprixelelisions; // sprixel elision count
1656 uint64_t sprixelbytes; // sprixel bytes emitted
1657 uint64_t appsync_updates; // how many application-synchronized updates?
1658 uint64_t input_errors; // errors processing control sequences/utf8
1659 uint64_t input_events; // characters returned to userspace
1660 uint64_t hpa_gratuitous; // unnecessary hpas issued
1661 uint64_t cell_geo_changes; // cell geometry changes (resizes)
1662 uint64_t pixel_geo_changes;// pixel geometry changes (font resize)
1663
1664 // current state -- these can decrease
1665 uint64_t fbbytes; // total bytes devoted to all active framebuffers
1666 unsigned planes; // number of planes currently in existence
1667 } ncstats;
1668
1669 // Allocate an ncstats object. Use this rather than allocating your own, since
1670 // future versions of Notcurses might enlarge this structure.
1671 API ALLOC ncstats* notcurses_stats_alloc(const struct notcurses* nc
1672 __attribute__ ((unused)))
1673 __attribute__ ((nonnull (1)));
1674
1675 // Acquire an atomic snapshot of the Notcurses object's stats.
1676 API void notcurses_stats(struct notcurses* nc, ncstats* stats)
1677 __attribute__ ((nonnull (1, 2)));
1678
1679 // Reset all cumulative stats (immediate ones, such as fbbytes, are not reset),
1680 // first copying them into |*stats| (if |stats| is not NULL).
1681 API void notcurses_stats_reset(struct notcurses* nc, ncstats* stats)
1682 __attribute__ ((nonnull (1)));
1683
1684 // Resize the specified ncplane. The four parameters 'keepy', 'keepx',
1685 // 'keepleny', and 'keeplenx' define a subset of the ncplane to keep,
1686 // unchanged. This may be a region of size 0, though none of these four
1687 // parameters may be negative. 'keepx' and 'keepy' are relative to the ncplane.
1688 // They must specify a coordinate within the ncplane's totality. 'yoff' and
1689 // 'xoff' are relative to 'keepy' and 'keepx', and place the upper-left corner
1690 // of the resized ncplane. Finally, 'ylen' and 'xlen' are the dimensions of the
1691 // ncplane after resizing. 'ylen' must be greater than or equal to 'keepleny',
1692 // and 'xlen' must be greater than or equal to 'keeplenx'. It is an error to
1693 // attempt to resize the standard plane. If either of 'keepleny' or 'keeplenx'
1694 // is non-zero, both must be non-zero.
1695 //
1696 // Essentially, the kept material does not move. It serves to anchor the
1697 // resized plane. If there is no kept material, the plane can move freely.
1698 API int ncplane_resize(struct ncplane* n, int keepy, int keepx,
1699 unsigned keepleny, unsigned keeplenx,
1700 int yoff, int xoff,
1701 unsigned ylen, unsigned xlen);
1702
1703 // Resize the plane, retaining what data we can (everything, unless we're
1704 // shrinking in some dimension). Keep the origin where it is.
1705 static inline int
ncplane_resize_simple(struct ncplane * n,unsigned ylen,unsigned xlen)1706 ncplane_resize_simple(struct ncplane* n, unsigned ylen, unsigned xlen){
1707 unsigned oldy, oldx;
1708 ncplane_dim_yx(n, &oldy, &oldx); // current dimensions of 'n'
1709 unsigned keepleny = oldy > ylen ? ylen : oldy;
1710 unsigned keeplenx = oldx > xlen ? xlen : oldx;
1711 return ncplane_resize(n, 0, 0, keepleny, keeplenx, 0, 0, ylen, xlen);
1712 }
1713
1714 // Destroy the specified ncplane. None of its contents will be visible after
1715 // the next call to notcurses_render(). It is an error to attempt to destroy
1716 // the standard plane.
1717 API int ncplane_destroy(struct ncplane* n);
1718
1719 // Set the ncplane's base nccell to 'c'. The base cell is used for purposes of
1720 // rendering anywhere that the ncplane's gcluster is 0. Note that the base cell
1721 // is not affected by ncplane_erase(). 'c' must not be a secondary cell from a
1722 // multicolumn EGC.
1723 API int ncplane_set_base_cell(struct ncplane* n, const nccell* c);
1724
1725 // Set the ncplane's base nccell. It will be used for purposes of rendering
1726 // anywhere that the ncplane's gcluster is 0. Note that the base cell is not
1727 // affected by ncplane_erase(). 'egc' must be an extended grapheme cluster.
1728 // Returns the number of bytes copied out of 'gcluster', or -1 on failure.
1729 API int ncplane_set_base(struct ncplane* n, const char* egc,
1730 uint16_t stylemask, uint64_t channels);
1731
1732 // Extract the ncplane's base nccell into 'c'. The reference is invalidated if
1733 // 'ncp' is destroyed.
1734 API int ncplane_base(struct ncplane* n, nccell* c);
1735
1736 // Get the origin of plane 'n' relative to its bound plane, or pile (if 'n' is
1737 // a root plane). To get absolute coordinates, use ncplane_abs_yx().
1738 API void ncplane_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x)
1739 __attribute__ ((nonnull (1)));
1740 API int ncplane_y(const struct ncplane* n) __attribute__ ((pure));
1741 API int ncplane_x(const struct ncplane* n) __attribute__ ((pure));
1742
1743 // Move this plane relative to the standard plane, or the plane to which it is
1744 // bound (if it is bound to a plane). It is an error to attempt to move the
1745 // standard plane.
1746 API int ncplane_move_yx(struct ncplane* n, int y, int x);
1747
1748 // Move this plane relative to its current location. Negative values move up
1749 // and left, respectively. Pass 0 to hold an axis constant.
1750 __attribute__ ((nonnull (1))) static inline int
ncplane_move_rel(struct ncplane * n,int y,int x)1751 ncplane_move_rel(struct ncplane* n, int y, int x){
1752 int oy, ox;
1753 ncplane_yx(n, &oy, &ox);
1754 return ncplane_move_yx(n, oy + y, ox + x);
1755 }
1756
1757 // Get the origin of plane 'n' relative to its pile. Either or both of 'x' and
1758 // 'y' may be NULL.
1759 API void ncplane_abs_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x)
1760 __attribute__ ((nonnull (1)));
1761 API int ncplane_abs_y(const struct ncplane* n) __attribute__ ((pure));
1762 API int ncplane_abs_x(const struct ncplane* n) __attribute__ ((pure));
1763
1764 // Get the plane to which the plane 'n' is bound, if any.
1765 API struct ncplane* ncplane_parent(struct ncplane* n)
1766 __attribute__ ((nonnull (1)));
1767 API const struct ncplane* ncplane_parent_const(const struct ncplane* n)
1768 __attribute__ ((nonnull (1)));
1769
1770 // Return non-zero iff 'n' is a proper descendent of 'ancestor'.
1771 static inline int
ncplane_descendant_p(const struct ncplane * n,const struct ncplane * ancestor)1772 ncplane_descendant_p(const struct ncplane* n, const struct ncplane* ancestor){
1773 for(const struct ncplane* parent = ncplane_parent_const(n) ; parent != ancestor ; parent = ncplane_parent_const(parent)){
1774 if(ncplane_parent_const(parent) == parent){ // reached a root plane
1775 return 0;
1776 }
1777 }
1778 return 1;
1779 }
1780
1781 // Splice ncplane 'n' out of the z-buffer, and reinsert it above 'above'.
1782 // Returns non-zero if 'n' is already in the desired location. 'n' and
1783 // 'above' must not be the same plane. If 'above' is NULL, 'n' is moved
1784 // to the bottom of its pile.
1785 API int ncplane_move_above(struct ncplane* RESTRICT n,
1786 struct ncplane* RESTRICT above)
1787 __attribute__ ((nonnull (1)));
1788
1789 // Splice ncplane 'n' out of the z-buffer, and reinsert it below 'below'.
1790 // Returns non-zero if 'n' is already in the desired location. 'n' and
1791 // 'below' must not be the same plane. If 'below' is NULL, 'n' is moved to
1792 // the top of its pile.
1793 API int ncplane_move_below(struct ncplane* RESTRICT n,
1794 struct ncplane* RESTRICT below)
1795 __attribute__ ((nonnull (1)));
1796
1797 // Splice ncplane 'n' out of the z-buffer; reinsert it at the top or bottom.
1798 __attribute__ ((nonnull (1)))
1799 static inline void
ncplane_move_top(struct ncplane * n)1800 ncplane_move_top(struct ncplane* n){
1801 ncplane_move_below(n, NULL);
1802 }
1803
1804 __attribute__ ((nonnull (1)))
1805 static inline void
ncplane_move_bottom(struct ncplane * n)1806 ncplane_move_bottom(struct ncplane* n){
1807 ncplane_move_above(n, NULL);
1808 }
1809
1810 // Splice ncplane 'n' and its bound planes out of the z-buffer, and reinsert
1811 // them above or below 'targ'. Relative order will be maintained between the
1812 // reinserted planes. For a plane E bound to C, with z-ordering A B C D E,
1813 // moving the C family to the top results in C E A B D, while moving it to
1814 // the bottom results in A B D C E.
1815 API int ncplane_move_family_above(struct ncplane* n, struct ncplane* targ)
1816 __attribute__ ((nonnull (1)));
1817
1818 API int ncplane_move_family_below(struct ncplane* n, struct ncplane* targ)
1819 __attribute__ ((nonnull (1)));
1820
1821 __attribute__ ((nonnull (1)))
1822 static inline void
ncplane_move_family_top(struct ncplane * n)1823 ncplane_move_family_top(struct ncplane* n){
1824 ncplane_move_family_below(n, NULL);
1825 }
1826
1827 __attribute__ ((nonnull (1)))
1828 static inline void
ncplane_move_family_bottom(struct ncplane * n)1829 ncplane_move_family_bottom(struct ncplane* n){
1830 ncplane_move_family_above(n, NULL);
1831 }
1832
1833 // Return the plane below this one, or NULL if this is at the bottom.
1834 API struct ncplane* ncplane_below(struct ncplane* n)
1835 __attribute__ ((nonnull (1)));
1836
1837 // Return the plane above this one, or NULL if this is at the top.
1838 API struct ncplane* ncplane_above(struct ncplane* n)
1839 __attribute__ ((nonnull (1)));
1840
1841 // Effect |r| scroll events on the plane |n|. Returns an error if |n| is not
1842 // a scrolling plane, and otherwise returns the number of lines scrolled.
1843 API int ncplane_scrollup(struct ncplane* n, int r)
1844 __attribute__ ((nonnull (1)));
1845
1846 // Scroll |n| up until |child| is no longer hidden beneath it. Returns an
1847 // error if |child| is not a child of |n|, or |n| is not scrolling, or |child|
1848 // is fixed. Returns the number of scrolling events otherwise (might be 0).
1849 // If the child plane is not fixed, it will likely scroll as well.
1850 API int ncplane_scrollup_child(struct ncplane* n, const struct ncplane* child)
1851 __attribute__ ((nonnull (1, 2)));
1852
1853 // Rotate the plane π/2 radians clockwise or counterclockwise. This cannot
1854 // be performed on arbitrary planes, because glyphs cannot be arbitrarily
1855 // rotated. The glyphs which can be rotated are limited: line-drawing
1856 // characters, spaces, half blocks, and full blocks. The plane must have
1857 // an even number of columns. Use the ncvisual rotation for a more
1858 // flexible approach.
1859 API int ncplane_rotate_cw(struct ncplane* n);
1860 API int ncplane_rotate_ccw(struct ncplane* n);
1861
1862 // Retrieve the current contents of the cell under the cursor. The EGC is
1863 // returned, or NULL on error. This EGC must be free()d by the caller. The
1864 // stylemask and channels are written to 'stylemask' and 'channels', respectively.
1865 API char* ncplane_at_cursor(struct ncplane* n, uint16_t* stylemask, uint64_t* channels);
1866
1867 // Retrieve the current contents of the cell under the cursor into 'c'. This
1868 // cell is invalidated if the associated plane is destroyed. Returns the number
1869 // of bytes in the EGC, or -1 on error.
1870 API int ncplane_at_cursor_cell(struct ncplane* n, nccell* c);
1871
1872 // Retrieve the current contents of the specified cell. The EGC is returned, or
1873 // NULL on error. This EGC must be free()d by the caller. The stylemask and
1874 // channels are written to 'stylemask' and 'channels', respectively. The return
1875 // represents how the cell will be used during rendering, and thus integrates
1876 // any base cell where appropriate. If called upon the secondary columns of a
1877 // wide glyph, the EGC will be returned (i.e. this function does not distinguish
1878 // between the primary and secondary columns of a wide glyph).
1879 API char* ncplane_at_yx(const struct ncplane* n, int y, int x,
1880 uint16_t* stylemask, uint64_t* channels);
1881
1882 // Retrieve the current contents of the specified cell into 'c'. This cell is
1883 // invalidated if the associated plane is destroyed. Returns the number of
1884 // bytes in the EGC, or -1 on error. Unlike ncplane_at_yx(), when called upon
1885 // the secondary columns of a wide glyph, the return can be distinguished from
1886 // the primary column (nccell_wide_right_p(c) will return true).
1887 API int ncplane_at_yx_cell(struct ncplane* n, int y, int x, nccell* c);
1888
1889 // Create a flat string from the EGCs of the selected region of the ncplane
1890 // 'n'. Start at the plane's 'begy'x'begx' coordinate (which must lie on the
1891 // plane), continuing for 'leny'x'lenx' cells. Either or both of 'leny' and
1892 // 'lenx' can be specified as 0 to go through the boundary of the plane.
1893 // -1 can be specified for 'begx'/'begy' to use the current cursor location.
1894 API char* ncplane_contents(struct ncplane* n, int begy, int begx,
1895 unsigned leny, unsigned lenx);
1896
1897 // Manipulate the opaque user pointer associated with this plane.
1898 // ncplane_set_userptr() returns the previous userptr after replacing
1899 // it with 'opaque'. the others simply return the userptr.
1900 API void* ncplane_set_userptr(struct ncplane* n, void* opaque);
1901 API void* ncplane_userptr(struct ncplane* n);
1902
1903 // Find the center coordinate of a plane, preferring the top/left in the
1904 // case of an even number of rows/columns (in such a case, there will be one
1905 // more cell to the bottom/right of the center than the top/left). The
1906 // center is then modified relative to the plane's origin.
1907 API void ncplane_center_abs(const struct ncplane* n, int* RESTRICT y,
1908 int* RESTRICT x);
1909
1910 // Create an RGBA flat array from the selected region of the ncplane 'nc'.
1911 // Start at the plane's 'begy'x'begx' coordinate (which must lie on the
1912 // plane), continuing for 'leny'x'lenx' cells. Either or both of 'leny' and
1913 // 'lenx' can be specified as 0 to go through the boundary of the plane.
1914 // Only glyphs from the specified ncblitset may be present. If 'pxdimy' and/or
1915 // 'pxdimx' are non-NULL, they will be filled in with the total pixel geometry.
1916 API ALLOC uint32_t* ncplane_as_rgba(const struct ncplane* n, ncblitter_e blit,
1917 int begy, int begx,
1918 unsigned leny, unsigned lenx,
1919 unsigned* pxdimy, unsigned* pxdimx)
1920 __attribute__ ((nonnull (1)));
1921
1922 // Return the offset into 'availu' at which 'u' ought be output given the
1923 // requirements of 'align'. Return -INT_MAX on invalid 'align'. Undefined
1924 // behavior on negative 'availu' or 'u'.
1925 static inline int
notcurses_align(int availu,ncalign_e align,int u)1926 notcurses_align(int availu, ncalign_e align, int u){
1927 if(align == NCALIGN_LEFT || align == NCALIGN_TOP){
1928 return 0;
1929 }
1930 if(align == NCALIGN_CENTER){
1931 return (availu - u) / 2;
1932 }
1933 if(align == NCALIGN_RIGHT || align == NCALIGN_BOTTOM){
1934 return availu - u;
1935 }
1936 return -INT_MAX; // invalid |align|
1937 }
1938
1939 // Return the column at which 'c' cols ought start in order to be aligned
1940 // according to 'align' within ncplane 'n'. Return -INT_MAX on invalid
1941 // 'align'. Undefined behavior on negative 'c'.
1942 static inline int
ncplane_halign(const struct ncplane * n,ncalign_e align,int c)1943 ncplane_halign(const struct ncplane* n, ncalign_e align, int c){
1944 return notcurses_align(ncplane_dim_x(n), align, c);
1945 }
1946
1947 // Return the row at which 'r' rows ought start in order to be aligned
1948 // according to 'align' within ncplane 'n'. Return -INT_MAX on invalid
1949 // 'align'. Undefined behavior on negative 'r'.
1950 static inline int
ncplane_valign(const struct ncplane * n,ncalign_e align,int r)1951 ncplane_valign(const struct ncplane* n, ncalign_e align, int r){
1952 return notcurses_align(ncplane_dim_y(n), align, r);
1953 }
1954
1955 // Move the cursor to the specified position (the cursor needn't be visible).
1956 // Pass -1 as either coordinate to hold that axis constant. Returns -1 if the
1957 // move would place the cursor outside the plane.
1958 API int ncplane_cursor_move_yx(struct ncplane* n, int y, int x)
1959 __attribute__ ((nonnull (1)));
1960
1961 // Move the cursor relative to the current cursor position (the cursor needn't
1962 // be visible). Returns -1 on error, including target position exceeding the
1963 // plane's dimensions.
1964 API int ncplane_cursor_move_rel(struct ncplane* n, int y, int x)
1965 __attribute__ ((nonnull (1)));
1966
1967 // Move the cursor to 0, 0. Can't fail.
1968 API void ncplane_home(struct ncplane* n)
1969 __attribute__ ((nonnull (1)));
1970
1971 // Get the current position of the cursor within n. y and/or x may be NULL.
1972 API void ncplane_cursor_yx(const struct ncplane* n, unsigned* RESTRICT y, unsigned* RESTRICT x)
1973 __attribute__ ((nonnull (1)));
1974
1975 // Get the current channels or attribute word for ncplane 'n'.
1976 API uint64_t ncplane_channels(const struct ncplane* n)
1977 __attribute__ ((nonnull (1)));
1978
1979 // Return the current styling for this ncplane.
1980 API uint16_t ncplane_styles(const struct ncplane* n)
1981 __attribute__ ((nonnull (1)));
1982
1983 // Replace the cell at the specified coordinates with the provided cell 'c',
1984 // and advance the cursor by the width of the cell (but not past the end of the
1985 // plane). On success, returns the number of columns the cursor was advanced.
1986 // 'c' must already be associated with 'n'. On failure, -1 is returned.
1987 API int ncplane_putc_yx(struct ncplane* n, int y, int x, const nccell* c)
1988 __attribute__ ((nonnull (1, 4)));
1989
1990 // Call ncplane_putc_yx() for the current cursor location.
1991 static inline int
ncplane_putc(struct ncplane * n,const nccell * c)1992 ncplane_putc(struct ncplane* n, const nccell* c){
1993 return ncplane_putc_yx(n, -1, -1, c);
1994 }
1995
1996 // Replace the cell at the specified coordinates with the provided 7-bit char
1997 // 'c'. Advance the cursor by 1. On success, returns 1. On failure, returns -1.
1998 // This works whether the underlying char is signed or unsigned.
1999 static inline int
ncplane_putchar_yx(struct ncplane * n,int y,int x,char c)2000 ncplane_putchar_yx(struct ncplane* n, int y, int x, char c){
2001 nccell ce = NCCELL_INITIALIZER((uint32_t)c, ncplane_styles(n), ncplane_channels(n));
2002 return ncplane_putc_yx(n, y, x, &ce);
2003 }
2004
2005 // Call ncplane_putchar_yx() at the current cursor location.
2006 static inline int
ncplane_putchar(struct ncplane * n,char c)2007 ncplane_putchar(struct ncplane* n, char c){
2008 return ncplane_putchar_yx(n, -1, -1, c);
2009 }
2010
2011 // Replace the EGC underneath us, but retain the styling. The current styling
2012 // of the plane will not be changed.
2013 API int ncplane_putchar_stained(struct ncplane* n, char c)
2014 __attribute__ ((nonnull (1)));
2015
2016 // Replace the cell at the specified coordinates with the provided EGC, and
2017 // advance the cursor by the width of the cluster (but not past the end of the
2018 // plane). On success, returns the number of columns the cursor was advanced.
2019 // On failure, -1 is returned. The number of bytes converted from gclust is
2020 // written to 'sbytes' if non-NULL.
2021 API int ncplane_putegc_yx(struct ncplane* n, int y, int x, const char* gclust,
2022 size_t* sbytes);
2023
2024 // Call ncplane_putegc_yx() at the current cursor location.
2025 static inline int
ncplane_putegc(struct ncplane * n,const char * gclust,size_t * sbytes)2026 ncplane_putegc(struct ncplane* n, const char* gclust, size_t* sbytes){
2027 return ncplane_putegc_yx(n, -1, -1, gclust, sbytes);
2028 }
2029
2030 // Replace the EGC underneath us, but retain the styling. The current styling
2031 // of the plane will not be changed.
2032 API int ncplane_putegc_stained(struct ncplane* n, const char* gclust, size_t* sbytes)
2033 __attribute__ ((nonnull (1, 2)));
2034
2035 // generate a heap-allocated UTF-8 encoding of the wide string 'src'.
2036 ALLOC static inline char*
ncwcsrtombs(const wchar_t * src)2037 ncwcsrtombs(const wchar_t* src){
2038 mbstate_t ps;
2039 memset(&ps, 0, sizeof(ps));
2040 size_t mbytes = wcsrtombs(NULL, &src, 0, &ps);
2041 if(mbytes == (size_t)-1){
2042 return NULL;
2043 }
2044 ++mbytes;
2045 char* mbstr = (char*)malloc(mbytes); // need cast for c++ callers
2046 if(mbstr == NULL){
2047 return NULL;
2048 }
2049 size_t s = wcsrtombs(mbstr, &src, mbytes, &ps);
2050 if(s == (size_t)-1){
2051 free(mbstr);
2052 return NULL;
2053 }
2054 return mbstr;
2055 }
2056
2057 // ncplane_putegc(), but following a conversion from wchar_t to UTF-8 multibyte.
2058 static inline int
ncplane_putwegc(struct ncplane * n,const wchar_t * gclust,size_t * sbytes)2059 ncplane_putwegc(struct ncplane* n, const wchar_t* gclust, size_t* sbytes){
2060 char* mbstr = ncwcsrtombs(gclust);
2061 if(mbstr == NULL){
2062 return -1;
2063 }
2064 int ret = ncplane_putegc(n, mbstr, sbytes);
2065 free(mbstr);
2066 return ret;
2067 }
2068
2069 // Call ncplane_putwegc() after successfully moving to y, x.
2070 static inline int
ncplane_putwegc_yx(struct ncplane * n,int y,int x,const wchar_t * gclust,size_t * sbytes)2071 ncplane_putwegc_yx(struct ncplane* n, int y, int x, const wchar_t* gclust,
2072 size_t* sbytes){
2073 if(ncplane_cursor_move_yx(n, y, x)){
2074 return -1;
2075 }
2076 return ncplane_putwegc(n, gclust, sbytes);
2077 }
2078
2079 // Replace the EGC underneath us, but retain the styling. The current styling
2080 // of the plane will not be changed.
2081 API int ncplane_putwegc_stained(struct ncplane* n, const wchar_t* gclust, size_t* sbytes)
2082 __attribute__ ((nonnull (1, 2)));
2083
2084 // Write a series of EGCs to the current location, using the current style.
2085 // They will be interpreted as a series of columns (according to the definition
2086 // of ncplane_putc()). Advances the cursor by some positive number of columns
2087 // (though not beyond the end of the plane); this number is returned on success.
2088 // On error, a non-positive number is returned, indicating the number of columns
2089 // which were written before the error.
2090 static inline int
ncplane_putstr_yx(struct ncplane * n,int y,int x,const char * gclusters)2091 ncplane_putstr_yx(struct ncplane* n, int y, int x, const char* gclusters){
2092 int ret = 0;
2093 while(*gclusters){
2094 size_t wcs;
2095 int cols = ncplane_putegc_yx(n, y, x, gclusters, &wcs);
2096 //fprintf(stderr, "wrote %.*s %d cols %zu bytes\n", (int)wcs, gclusters, cols, wcs);
2097 if(cols < 0){
2098 return -ret;
2099 }
2100 if(wcs == 0){
2101 break;
2102 }
2103 // after the first iteration, just let the cursor code control where we
2104 // print, so that scrolling is taken into account
2105 y = -1;
2106 x = -1;
2107 gclusters += wcs;
2108 ret += cols;
2109 }
2110 return ret;
2111 }
2112
2113 static inline int
ncplane_putstr(struct ncplane * n,const char * gclustarr)2114 ncplane_putstr(struct ncplane* n, const char* gclustarr){
2115 return ncplane_putstr_yx(n, -1, -1, gclustarr);
2116 }
2117
2118 static inline int
ncplane_putstr_aligned(struct ncplane * n,int y,ncalign_e align,const char * s)2119 ncplane_putstr_aligned(struct ncplane* n, int y, ncalign_e align, const char* s){
2120 int validbytes, validwidth;
2121 // we'll want to do the partial write if there's an error somewhere within
2122 ncstrwidth(s, &validbytes, &validwidth);
2123 int xpos = ncplane_halign(n, align, validwidth);
2124 if(xpos < 0){
2125 return -1;
2126 }
2127 return ncplane_putstr_yx(n, y, xpos, s);
2128 }
2129
2130 // Replace a string's worth of glyphs at the current cursor location, but
2131 // retain the styling. The current styling of the plane will not be changed.
2132 static inline int
ncplane_putstr_stained(struct ncplane * n,const char * gclusters)2133 ncplane_putstr_stained(struct ncplane* n, const char* gclusters){
2134 int ret = 0;
2135 while(*gclusters){
2136 size_t wcs;
2137 int cols = ncplane_putegc_stained(n, gclusters, &wcs);
2138 if(cols < 0){
2139 return -ret;
2140 }
2141 if(wcs == 0){
2142 break;
2143 }
2144 gclusters += wcs;
2145 ret += cols;
2146 }
2147 return ret;
2148 }
2149
2150 API int ncplane_putnstr_aligned(struct ncplane* n, int y, ncalign_e align, size_t s, const char* str)
2151 __attribute__ ((nonnull (1, 5)));
2152
2153 // Write a series of EGCs to the current location, using the current style.
2154 // They will be interpreted as a series of columns (according to the definition
2155 // of ncplane_putc()). Advances the cursor by some positive number of columns
2156 // (though not beyond the end of the plane); this number is returned on success.
2157 // On error, a non-positive number is returned, indicating the number of columns
2158 // which were written before the error. No more than 's' bytes will be written.
2159 static inline int
ncplane_putnstr_yx(struct ncplane * n,int y,int x,size_t s,const char * gclusters)2160 ncplane_putnstr_yx(struct ncplane* n, int y, int x, size_t s, const char* gclusters){
2161 int ret = 0;
2162 int offset = 0;
2163 //fprintf(stderr, "PUT %zu at %d/%d [%.*s]\n", s, y, x, (int)s, gclusters);
2164 while((size_t)offset < s && gclusters[offset]){
2165 size_t wcs;
2166 int cols = ncplane_putegc_yx(n, y, x, gclusters + offset, &wcs);
2167 if(cols < 0){
2168 return -ret;
2169 }
2170 if(wcs == 0){
2171 break;
2172 }
2173 // after the first iteration, just let the cursor code control where we
2174 // print, so that scrolling is taken into account
2175 y = -1;
2176 x = -1;
2177 offset += wcs;
2178 ret += cols;
2179 }
2180 return ret;
2181 }
2182
2183 static inline int
ncplane_putnstr(struct ncplane * n,size_t s,const char * gclustarr)2184 ncplane_putnstr(struct ncplane* n, size_t s, const char* gclustarr){
2185 return ncplane_putnstr_yx(n, -1, -1, s, gclustarr);
2186 }
2187
2188 // ncplane_putstr(), but following a conversion from wchar_t to UTF-8 multibyte.
2189 // FIXME do this as a loop over ncplane_putegc_yx and save the big allocation+copy
2190 static inline int
ncplane_putwstr_yx(struct ncplane * n,int y,int x,const wchar_t * gclustarr)2191 ncplane_putwstr_yx(struct ncplane* n, int y, int x, const wchar_t* gclustarr){
2192 // maximum of six UTF8-encoded bytes per wchar_t
2193 const size_t mbytes = (wcslen(gclustarr) * WCHAR_MAX_UTF8BYTES) + 1;
2194 char* mbstr = (char*)malloc(mbytes); // need cast for c++ callers
2195 if(mbstr == NULL){
2196 return -1;
2197 }
2198 mbstate_t ps;
2199 memset(&ps, 0, sizeof(ps));
2200 const wchar_t** gend = &gclustarr;
2201 size_t s = wcsrtombs(mbstr, gend, mbytes, &ps);
2202 if(s == (size_t)-1){
2203 free(mbstr);
2204 return -1;
2205 }
2206 int ret = ncplane_putstr_yx(n, y, x, mbstr);
2207 free(mbstr);
2208 return ret;
2209 }
2210
2211 static inline int
ncplane_putwstr_aligned(struct ncplane * n,int y,ncalign_e align,const wchar_t * gclustarr)2212 ncplane_putwstr_aligned(struct ncplane* n, int y, ncalign_e align,
2213 const wchar_t* gclustarr){
2214 int width = wcswidth(gclustarr, INT_MAX);
2215 int xpos = ncplane_halign(n, align, width);
2216 if(xpos < 0){
2217 return -1;
2218 }
2219 return ncplane_putwstr_yx(n, y, xpos, gclustarr);
2220 }
2221
2222 API int ncplane_putwstr_stained(struct ncplane* n, const wchar_t* gclustarr)
2223 __attribute__ ((nonnull (1, 2)));
2224
2225 static inline int
ncplane_putwstr(struct ncplane * n,const wchar_t * gclustarr)2226 ncplane_putwstr(struct ncplane* n, const wchar_t* gclustarr){
2227 return ncplane_putwstr_yx(n, -1, -1, gclustarr);
2228 }
2229
2230 // Replace the cell at the specified coordinates with the provided UTF-32
2231 // 'u'. Advance the cursor by the character's width as reported by wcwidth().
2232 // On success, returns the number of columns written. On failure, returns -1.
2233 static inline int
ncplane_pututf32_yx(struct ncplane * n,int y,int x,uint32_t u)2234 ncplane_pututf32_yx(struct ncplane* n, int y, int x, uint32_t u){
2235 if(u > WCHAR_MAX){
2236 return -1;
2237 }
2238 // we use MB_LEN_MAX (and potentially "waste" a few stack bytes to avoid
2239 // the greater sin of a VLA (and to be locale-independent).
2240 char utf8c[MB_LEN_MAX + 1];
2241 mbstate_t ps;
2242 memset(&ps, 0, sizeof(ps));
2243 // this isn't going to be valid for reconstructued surrogate pairs...
2244 // we need our own, or to use unistring or something.
2245 size_t s = wcrtomb(utf8c, u, &ps);
2246 if(s == (size_t)-1){
2247 return -1;
2248 }
2249 utf8c[s] = '\0';
2250 return ncplane_putegc_yx(n, y, x, utf8c, NULL);
2251 }
2252
2253 static inline int
ncplane_putwc_yx(struct ncplane * n,int y,int x,wchar_t w)2254 ncplane_putwc_yx(struct ncplane* n, int y, int x, wchar_t w){
2255 return ncplane_pututf32_yx(n, y, x, w);
2256 }
2257
2258 // Write 'w' at the current cursor position, using the plane's current styling.
2259 static inline int
ncplane_putwc(struct ncplane * n,wchar_t w)2260 ncplane_putwc(struct ncplane* n, wchar_t w){
2261 return ncplane_putwc_yx(n, -1, -1, w);
2262 }
2263
2264 // Write the first Unicode character from 'w' at the current cursor position,
2265 // using the plane's current styling. In environments where wchar_t is only
2266 // 16 bits (Windows, essentially), a single Unicode might require two wchar_t
2267 // values forming a surrogate pair. On environments with 32-bit wchar_t, this
2268 // should not happen. If w[0] is a surrogate, it is decoded together with
2269 // w[1], and passed as a single reconstructed UTF-32 character to
2270 // ncplane_pututf32(); 'wchars' will get a value of 2 in this case. 'wchars'
2271 // otherwise gets a value of 1. A surrogate followed by an invalid pairing
2272 // will set 'wchars' to 2, but return -1 immediately.
2273 static inline int
ncplane_putwc_utf32(struct ncplane * n,const wchar_t * w,unsigned * wchars)2274 ncplane_putwc_utf32(struct ncplane* n, const wchar_t* w, unsigned* wchars){
2275 uint32_t utf32;
2276 if(*w >= 0xd000 && *w <= 0xdbff){
2277 *wchars = 2;
2278 if(w[1] < 0xdc00 || w[1] > 0xdfff){
2279 return -1; // invalid surrogate pairing
2280 }
2281 utf32 = (w[0] & 0x3fflu) << 10lu;
2282 utf32 += (w[1] & 0x3fflu);
2283 }else{
2284 *wchars = 1;
2285 utf32 = *w;
2286 }
2287 return ncplane_pututf32_yx(n, -1, -1, utf32);
2288 }
2289
2290 // Write 'w' at the current cursor position, using any preexisting styling
2291 // at that cell.
2292 static inline int
ncplane_putwc_stained(struct ncplane * n,wchar_t w)2293 ncplane_putwc_stained(struct ncplane* n, wchar_t w){
2294 wchar_t warr[2] = { w, L'\0' };
2295 return ncplane_putwstr_stained(n, warr);
2296 }
2297
2298 // The ncplane equivalents of printf(3) and vprintf(3).
2299 API int ncplane_vprintf_aligned(struct ncplane* n, int y, ncalign_e align,
2300 const char* format, va_list ap)
2301 __attribute__ ((nonnull (1, 4)))
2302 __attribute__ ((format (printf, 4, 0)));
2303
2304 API int ncplane_vprintf_yx(struct ncplane* n, int y, int x,
2305 const char* format, va_list ap)
2306 __attribute__ ((nonnull (1, 4)))
2307 __attribute__ ((format (printf, 4, 0)));
2308
2309 static inline int
ncplane_vprintf(struct ncplane * n,const char * format,va_list ap)2310 ncplane_vprintf(struct ncplane* n, const char* format, va_list ap){
2311 return ncplane_vprintf_yx(n, -1, -1, format, ap);
2312 }
2313
2314 API int ncplane_vprintf_stained(struct ncplane* n, const char* format, va_list ap)
2315 __attribute__ ((nonnull (1, 2)))
2316 __attribute__ ((format (printf, 2, 0)));
2317
2318 static inline int
2319 ncplane_printf(struct ncplane* n, const char* format, ...)
2320 __attribute__ ((nonnull (1, 2)))
2321 __attribute__ ((format (printf, 2, 3)));
2322
2323 static inline int
ncplane_printf(struct ncplane * n,const char * format,...)2324 ncplane_printf(struct ncplane* n, const char* format, ...){
2325 va_list va;
2326 va_start(va, format);
2327 int ret = ncplane_vprintf(n, format, va);
2328 va_end(va);
2329 return ret;
2330 }
2331
2332 static inline int
2333 ncplane_printf_yx(struct ncplane* n, int y, int x, const char* format, ...)
2334 __attribute__ ((nonnull (1, 4))) __attribute__ ((format (printf, 4, 5)));
2335
2336 static inline int
ncplane_printf_yx(struct ncplane * n,int y,int x,const char * format,...)2337 ncplane_printf_yx(struct ncplane* n, int y, int x, const char* format, ...){
2338 va_list va;
2339 va_start(va, format);
2340 int ret = ncplane_vprintf_yx(n, y, x, format, va);
2341 va_end(va);
2342 return ret;
2343 }
2344
2345 static inline int
2346 ncplane_printf_aligned(struct ncplane* n, int y, ncalign_e align,
2347 const char* format, ...)
2348 __attribute__ ((nonnull (1, 4))) __attribute__ ((format (printf, 4, 5)));
2349
2350 static inline int
ncplane_printf_aligned(struct ncplane * n,int y,ncalign_e align,const char * format,...)2351 ncplane_printf_aligned(struct ncplane* n, int y, ncalign_e align, const char* format, ...){
2352 va_list va;
2353 va_start(va, format);
2354 int ret = ncplane_vprintf_aligned(n, y, align, format, va);
2355 va_end(va);
2356 return ret;
2357 }
2358
2359 static inline int
2360 ncplane_printf_stained(struct ncplane* n, const char* format, ...)
2361 __attribute__ ((nonnull (1, 2))) __attribute__ ((format (printf, 2, 3)));
2362
2363 static inline int
ncplane_printf_stained(struct ncplane * n,const char * format,...)2364 ncplane_printf_stained(struct ncplane* n, const char* format, ...){
2365 va_list va;
2366 va_start(va, format);
2367 int ret = ncplane_vprintf_stained(n, format, va);
2368 va_end(va);
2369 return ret;
2370 }
2371
2372 // Write the specified text to the plane, breaking lines sensibly, beginning at
2373 // the specified line. Returns the number of columns written. When breaking a
2374 // line, the line will be cleared to the end of the plane (the last line will
2375 // *not* be so cleared). The number of bytes written from the input is written
2376 // to '*bytes' if it is not NULL. Cleared columns are included in the return
2377 // value, but *not* included in the number of bytes written. Leaves the cursor
2378 // at the end of output. A partial write will be accomplished as far as it can;
2379 // determine whether the write completed by inspecting '*bytes'. Can output to
2380 // multiple rows even in the absence of scrolling, but not more rows than are
2381 // available. With scrolling enabled, arbitrary amounts of data can be emitted.
2382 // All provided whitespace is preserved -- ncplane_puttext() followed by an
2383 // appropriate ncplane_contents() will read back the original output.
2384 //
2385 // If 'y' is -1, the first row of output is taken relative to the current
2386 // cursor: it will be left-, right-, or center-aligned in whatever remains
2387 // of the row. On subsequent rows -- or if 'y' is not -1 -- the entire row can
2388 // be used, and alignment works normally.
2389 //
2390 // A newline at any point will move the cursor to the next row.
2391 API int ncplane_puttext(struct ncplane* n, int y, ncalign_e align,
2392 const char* text, size_t* bytes)
2393 __attribute__ ((nonnull (1, 4)));
2394
2395 // Draw horizontal or vertical lines using the specified cell, starting at the
2396 // current cursor position. The cursor will end at the cell following the last
2397 // cell output (even, perhaps counter-intuitively, when drawing vertical
2398 // lines), just as if ncplane_putc() was called at that spot. Return the
2399 // number of cells drawn on success. On error, return the negative number of
2400 // cells drawn. A length of 0 is an error, resulting in a return of -1.
2401 API int ncplane_hline_interp(struct ncplane* n, const nccell* c,
2402 unsigned len, uint64_t c1, uint64_t c2)
2403 __attribute__ ((nonnull (1, 2)));
2404
2405 __attribute__ ((nonnull (1, 2))) static inline int
ncplane_hline(struct ncplane * n,const nccell * c,unsigned len)2406 ncplane_hline(struct ncplane* n, const nccell* c, unsigned len){
2407 return ncplane_hline_interp(n, c, len, c->channels, c->channels);
2408 }
2409
2410 API int ncplane_vline_interp(struct ncplane* n, const nccell* c,
2411 unsigned len, uint64_t c1, uint64_t c2)
2412 __attribute__ ((nonnull (1, 2)));
2413
2414 __attribute__ ((nonnull (1, 2))) static inline int
ncplane_vline(struct ncplane * n,const nccell * c,unsigned len)2415 ncplane_vline(struct ncplane* n, const nccell* c, unsigned len){
2416 return ncplane_vline_interp(n, c, len, c->channels, c->channels);
2417 }
2418
2419 #define NCBOXMASK_TOP 0x0001
2420 #define NCBOXMASK_RIGHT 0x0002
2421 #define NCBOXMASK_BOTTOM 0x0004
2422 #define NCBOXMASK_LEFT 0x0008
2423 #define NCBOXGRAD_TOP 0x0010
2424 #define NCBOXGRAD_RIGHT 0x0020
2425 #define NCBOXGRAD_BOTTOM 0x0040
2426 #define NCBOXGRAD_LEFT 0x0080
2427 #define NCBOXCORNER_MASK 0x0300
2428 #define NCBOXCORNER_SHIFT 8u
2429
2430 // Draw a box with its upper-left corner at the current cursor position, and its
2431 // lower-right corner at 'ystop'x'xstop'. The 6 cells provided are used to draw the
2432 // upper-left, ur, ll, and lr corners, then the horizontal and vertical lines.
2433 // 'ctlword' is defined in the least significant byte, where bits [7, 4] are a
2434 // gradient mask, and [3, 0] are a border mask:
2435 // * 7, 3: top
2436 // * 6, 2: right
2437 // * 5, 1: bottom
2438 // * 4, 0: left
2439 // If the gradient bit is not set, the styling from the hl/vl cells is used for
2440 // the horizontal and vertical lines, respectively. If the gradient bit is set,
2441 // the color is linearly interpolated between the two relevant corner cells.
2442 //
2443 // By default, vertexes are drawn whether their connecting edges are drawn or
2444 // not. The value of the bits corresponding to NCBOXCORNER_MASK control this,
2445 // and are interpreted as the number of connecting edges necessary to draw a
2446 // given corner. At 0 (the default), corners are always drawn. At 3, corners
2447 // are never drawn (since at most 2 edges can touch a box's corner).
2448 API int ncplane_box(struct ncplane* n, const nccell* ul, const nccell* ur,
2449 const nccell* ll, const nccell* lr, const nccell* hline,
2450 const nccell* vline, unsigned ystop, unsigned xstop,
2451 unsigned ctlword);
2452
2453 // Draw a box with its upper-left corner at the current cursor position, having
2454 // dimensions 'ylen'x'xlen'. See ncplane_box() for more information. The
2455 // minimum box size is 2x2, and it cannot be drawn off-plane.
2456 static inline int
ncplane_box_sized(struct ncplane * n,const nccell * ul,const nccell * ur,const nccell * ll,const nccell * lr,const nccell * hline,const nccell * vline,unsigned ystop,unsigned xstop,unsigned ctlword)2457 ncplane_box_sized(struct ncplane* n, const nccell* ul, const nccell* ur,
2458 const nccell* ll, const nccell* lr, const nccell* hline,
2459 const nccell* vline, unsigned ystop, unsigned xstop,
2460 unsigned ctlword){
2461 unsigned y, x;
2462 ncplane_cursor_yx(n, &y, &x);
2463 return ncplane_box(n, ul, ur, ll, lr, hline, vline, y + ystop - 1,
2464 x + xstop - 1, ctlword);
2465 }
2466
2467 static inline int
ncplane_perimeter(struct ncplane * n,const nccell * ul,const nccell * ur,const nccell * ll,const nccell * lr,const nccell * hline,const nccell * vline,unsigned ctlword)2468 ncplane_perimeter(struct ncplane* n, const nccell* ul, const nccell* ur,
2469 const nccell* ll, const nccell* lr, const nccell* hline,
2470 const nccell* vline, unsigned ctlword){
2471 if(ncplane_cursor_move_yx(n, 0, 0)){
2472 return -1;
2473 }
2474 unsigned dimy, dimx;
2475 ncplane_dim_yx(n, &dimy, &dimx);
2476 return ncplane_box_sized(n, ul, ur, ll, lr, hline, vline, dimy, dimx, ctlword);
2477 }
2478
2479 // Starting at the specified coordinate, if its glyph is different from that of
2480 // 'c', 'c' is copied into it, and the original glyph is considered the fill
2481 // target. We do the same to all cardinally-connected cells having this same
2482 // fill target. Returns the number of cells polyfilled. An invalid initial y, x
2483 // is an error. Returns the number of cells filled, or -1 on error.
2484 API int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const nccell* c)
2485 __attribute__ ((nonnull (1, 4)));
2486
2487 // Draw a gradient with its upper-left corner at the position specified by 'y'/'x',
2488 // where -1 means the current cursor position in that dimension. The area is
2489 // specified by 'ylen'/'xlen', where 0 means "everything remaining below or
2490 // to the right, respectively." The glyph composed of 'egc' and 'styles' is
2491 // used for all cells. The channels specified by 'ul', 'ur', 'll', and 'lr'
2492 // are composed into foreground and background gradients. To do a vertical
2493 // gradient, 'ul' ought equal 'ur' and 'll' ought equal 'lr'. To do a
2494 // horizontal gradient, 'ul' ought equal 'll' and 'ur' ought equal 'ul'. To
2495 // color everything the same, all four channels should be equivalent. The
2496 // resulting alpha values are equal to incoming alpha values. Returns the
2497 // number of cells filled on success, or -1 on failure.
2498 // Palette-indexed color is not supported.
2499 //
2500 // Preconditions for gradient operations (error otherwise):
2501 //
2502 // all: only RGB colors, unless all four channels match as default
2503 // all: all alpha values must be the same
2504 // 1x1: all four colors must be the same
2505 // 1xN: both top and both bottom colors must be the same (vertical gradient)
2506 // Nx1: both left and both right colors must be the same (horizontal gradient)
2507 API int ncplane_gradient(struct ncplane* n, int y, int x, unsigned ylen,
2508 unsigned xlen, const char* egc, uint16_t styles,
2509 uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr)
2510 __attribute__ ((nonnull (1, 6)));
2511
2512 // Do a high-resolution gradient using upper blocks and synced backgrounds.
2513 // This doubles the number of vertical gradations, but restricts you to
2514 // half blocks (appearing to be full blocks). Returns the number of cells
2515 // filled on success, or -1 on error.
2516 API int ncplane_gradient2x1(struct ncplane* n, int y, int x, unsigned ylen,
2517 unsigned xlen, uint32_t ul, uint32_t ur,
2518 uint32_t ll, uint32_t lr)
2519 __attribute__ ((nonnull (1)));
2520
2521 // Set the given style throughout the specified region, keeping content and
2522 // channels unchanged. The upper left corner is at 'y', 'x', and -1 may be
2523 // specified to indicate the cursor's position in that dimension. The area
2524 // is specified by 'ylen', 'xlen', and 0 may be specified to indicate everything
2525 // remaining to the right and below, respectively. It is an error for any
2526 // coordinate to be outside the plane. Returns the number of cells set,
2527 // or -1 on failure.
2528 API int ncplane_format(struct ncplane* n, int y, int x, unsigned ylen,
2529 unsigned xlen, uint16_t stylemask)
2530 __attribute__ ((nonnull (1)));
2531
2532 // Set the given channels throughout the specified region, keeping content and
2533 // channels unchanged. The upper left corner is at 'y', 'x', and -1 may be
2534 // specified to indicate the cursor's position in that dimension. The area
2535 // is specified by 'ylen', 'xlen', and 0 may be specified to indicate everything
2536 // remaining to the right and below, respectively. It is an error for any
2537 // coordinate to be outside the plane. Returns the number of cells set,
2538 // or -1 on failure.
2539 API int ncplane_stain(struct ncplane* n, int y, int x, unsigned ylen,
2540 unsigned xlen, uint64_t ul, uint64_t ur,
2541 uint64_t ll, uint64_t lr)
2542 __attribute__ ((nonnull (1)));
2543
2544 // Merge the entirety of 'src' down onto the ncplane 'dst'. If 'src' does not
2545 // intersect with 'dst', 'dst' will not be changed, but it is not an error.
2546 API int ncplane_mergedown_simple(struct ncplane* RESTRICT src,
2547 struct ncplane* RESTRICT dst)
2548 __attribute__ ((nonnull (1, 2)));
2549
2550 // Merge the ncplane 'src' down onto the ncplane 'dst'. This is most rigorously
2551 // defined as "write to 'dst' the frame that would be rendered were the entire
2552 // stack made up only of the specified subregion of 'src' and, below it, the
2553 // subregion of 'dst' having the specified origin. Supply -1 to indicate the
2554 // current cursor position in the relevant dimension. Merging is independent of
2555 // the position of 'src' viz 'dst' on the z-axis. It is an error to define a
2556 // subregion that is not entirely contained within 'src'. It is an error to
2557 // define a target origin such that the projected subregion is not entirely
2558 // contained within 'dst'. Behavior is undefined if 'src' and 'dst' are
2559 // equivalent. 'dst' is modified, but 'src' remains unchanged. Neither 'src'
2560 // nor 'dst' may have sprixels. Lengths of 0 mean "everything left".
2561 API int ncplane_mergedown(struct ncplane* RESTRICT src,
2562 struct ncplane* RESTRICT dst,
2563 int begsrcy, int begsrcx,
2564 unsigned leny, unsigned lenx,
2565 int dsty, int dstx)
2566 __attribute__ ((nonnull (1, 2)));
2567
2568 // Erase every cell in the ncplane (each cell is initialized to the null glyph
2569 // and the default channels/styles). All cells associated with this ncplane are
2570 // invalidated, and must not be used after the call, *excluding* the base cell.
2571 // The cursor is homed. The plane's active attributes are unaffected.
2572 API void ncplane_erase(struct ncplane* n)
2573 __attribute__ ((nonnull (1)));
2574
2575 // Erase every cell in the region starting at {ystart, xstart} and having size
2576 // {|ylen|x|xlen|} for non-zero lengths. If ystart and/or xstart are -1, the current
2577 // cursor position along that axis is used; other negative values are an error. A
2578 // negative ylen means to move up from the origin, and a negative xlen means to move
2579 // left from the origin. A positive ylen moves down, and a positive xlen moves right.
2580 // A value of 0 for the length erases everything along that dimension. It is an error
2581 // if the starting coordinate is not in the plane, but the ending coordinate may be
2582 // outside the plane.
2583 //
2584 // For example, on a plane of 20 rows and 10 columns, with the cursor at row 10 and
2585 // column 5, the following would hold:
2586 //
2587 // (-1, -1, 0, 1): clears the column to the right of the cursor (column 6)
2588 // (-1, -1, 0, -1): clears the column to the left of the cursor (column 4)
2589 // (-1, -1, INT_MAX, 0): clears all rows with or below the cursor (rows 10--19)
2590 // (-1, -1, -INT_MAX, 0): clears all rows with or above the cursor (rows 0--10)
2591 // (-1, 4, 3, 3): clears from row 5, column 4 through row 7, column 6
2592 // (-1, 4, -3, -3): clears from row 5, column 4 through row 3, column 2
2593 // (4, -1, 0, 3): clears columns 5, 6, and 7
2594 // (-1, -1, 0, 0): clears the plane *if the cursor is in a legal position*
2595 // (0, 0, 0, 0): clears the plane in all cases
2596 API int ncplane_erase_region(struct ncplane* n, int ystart, int xstart,
2597 int ylen, int xlen)
2598 __attribute__ ((nonnull (1)));
2599
2600 // Extract 24 bits of foreground RGB from 'cl', shifted to LSBs.
2601 static inline uint32_t
nccell_fg_rgb(const nccell * cl)2602 nccell_fg_rgb(const nccell* cl){
2603 return ncchannels_fg_rgb(cl->channels);
2604 }
2605
2606 // Extract 24 bits of background RGB from 'cl', shifted to LSBs.
2607 static inline uint32_t
nccell_bg_rgb(const nccell * cl)2608 nccell_bg_rgb(const nccell* cl){
2609 return ncchannels_bg_rgb(cl->channels);
2610 }
2611
2612 // Extract 2 bits of foreground alpha from 'cl', shifted to LSBs.
2613 static inline uint32_t
nccell_fg_alpha(const nccell * cl)2614 nccell_fg_alpha(const nccell* cl){
2615 return ncchannels_fg_alpha(cl->channels);
2616 }
2617
2618 // Extract 2 bits of background alpha from 'cl', shifted to LSBs.
2619 static inline uint32_t
nccell_bg_alpha(const nccell * cl)2620 nccell_bg_alpha(const nccell* cl){
2621 return ncchannels_bg_alpha(cl->channels);
2622 }
2623
2624 // Extract 24 bits of foreground RGB from 'cl', split into components.
2625 static inline uint32_t
nccell_fg_rgb8(const nccell * cl,unsigned * r,unsigned * g,unsigned * b)2626 nccell_fg_rgb8(const nccell* cl, unsigned* r, unsigned* g, unsigned* b){
2627 return ncchannels_fg_rgb8(cl->channels, r, g, b);
2628 }
2629
2630 // Extract 24 bits of background RGB from 'cl', split into components.
2631 static inline uint32_t
nccell_bg_rgb8(const nccell * cl,unsigned * r,unsigned * g,unsigned * b)2632 nccell_bg_rgb8(const nccell* cl, unsigned* r, unsigned* g, unsigned* b){
2633 return ncchannels_bg_rgb8(cl->channels, r, g, b);
2634 }
2635
2636 // Set the r, g, and b cell for the foreground component of this 64-bit
2637 // 'cl' variable, and mark it as not using the default color.
2638 static inline int
nccell_set_fg_rgb8(nccell * cl,unsigned r,unsigned g,unsigned b)2639 nccell_set_fg_rgb8(nccell* cl, unsigned r, unsigned g, unsigned b){
2640 return ncchannels_set_fg_rgb8(&cl->channels, r, g, b);
2641 }
2642
2643 // Same, but clipped to [0..255].
2644 static inline void
nccell_set_fg_rgb8_clipped(nccell * cl,int r,int g,int b)2645 nccell_set_fg_rgb8_clipped(nccell* cl, int r, int g, int b){
2646 ncchannels_set_fg_rgb8_clipped(&cl->channels, r, g, b);
2647 }
2648
2649 // Same, but with an assembled 24-bit RGB value.
2650 static inline int
nccell_set_fg_rgb(nccell * c,uint32_t channel)2651 nccell_set_fg_rgb(nccell* c, uint32_t channel){
2652 return ncchannels_set_fg_rgb(&c->channels, channel);
2653 }
2654
2655 // Set the cell's foreground palette index, set the foreground palette index
2656 // bit, set it foreground-opaque, and clear the foreground default color bit.
2657 static inline int
nccell_set_fg_palindex(nccell * cl,int idx)2658 nccell_set_fg_palindex(nccell* cl, int idx){
2659 return ncchannels_set_fg_palindex(&cl->channels, idx);
2660 }
2661
2662 static inline uint32_t
nccell_fg_palindex(const nccell * cl)2663 nccell_fg_palindex(const nccell* cl){
2664 return ncchannels_fg_palindex(cl->channels);
2665 }
2666
2667 // Set the r, g, and b cell for the background component of this 64-bit
2668 // 'cl' variable, and mark it as not using the default color.
2669 static inline int
nccell_set_bg_rgb8(nccell * cl,unsigned r,unsigned g,unsigned b)2670 nccell_set_bg_rgb8(nccell* cl, unsigned r, unsigned g, unsigned b){
2671 return ncchannels_set_bg_rgb8(&cl->channels, r, g, b);
2672 }
2673
2674 // Same, but clipped to [0..255].
2675 static inline void
nccell_set_bg_rgb8_clipped(nccell * cl,int r,int g,int b)2676 nccell_set_bg_rgb8_clipped(nccell* cl, int r, int g, int b){
2677 ncchannels_set_bg_rgb8_clipped(&cl->channels, r, g, b);
2678 }
2679
2680 // Same, but with an assembled 24-bit RGB value. A value over 0xffffff
2681 // will be rejected, with a non-zero return value.
2682 static inline int
nccell_set_bg_rgb(nccell * c,uint32_t channel)2683 nccell_set_bg_rgb(nccell* c, uint32_t channel){
2684 return ncchannels_set_bg_rgb(&c->channels, channel);
2685 }
2686
2687 // Set the cell's background palette index, set the background palette index
2688 // bit, set it background-opaque, and clear the background default color bit.
2689 static inline int
nccell_set_bg_palindex(nccell * cl,int idx)2690 nccell_set_bg_palindex(nccell* cl, int idx){
2691 return ncchannels_set_bg_palindex(&cl->channels, idx);
2692 }
2693
2694 static inline uint32_t
nccell_bg_palindex(const nccell * cl)2695 nccell_bg_palindex(const nccell* cl){
2696 return ncchannels_bg_palindex(cl->channels);
2697 }
2698
2699 // Is the foreground using the "default foreground color"?
2700 static inline bool
nccell_fg_default_p(const nccell * cl)2701 nccell_fg_default_p(const nccell* cl){
2702 return ncchannels_fg_default_p(cl->channels);
2703 }
2704
2705 static inline bool
nccell_fg_palindex_p(const nccell * cl)2706 nccell_fg_palindex_p(const nccell* cl){
2707 return ncchannels_fg_palindex_p(cl->channels);
2708 }
2709
2710 // Is the background using the "default background color"? The "default
2711 // background color" must generally be used to take advantage of
2712 // terminal-effected transparency.
2713 static inline bool
nccell_bg_default_p(const nccell * cl)2714 nccell_bg_default_p(const nccell* cl){
2715 return ncchannels_bg_default_p(cl->channels);
2716 }
2717
2718 static inline bool
nccell_bg_palindex_p(const nccell * cl)2719 nccell_bg_palindex_p(const nccell* cl){
2720 return ncchannels_bg_palindex_p(cl->channels);
2721 }
2722
2723 // Extract the 32-bit working background channel from an ncplane.
2724 static inline uint32_t
ncplane_bchannel(const struct ncplane * n)2725 ncplane_bchannel(const struct ncplane* n){
2726 return ncchannels_bchannel(ncplane_channels(n));
2727 }
2728
2729 // Extract the 32-bit working foreground channel from an ncplane.
2730 static inline uint32_t
ncplane_fchannel(const struct ncplane * n)2731 ncplane_fchannel(const struct ncplane* n){
2732 return ncchannels_fchannel(ncplane_channels(n));
2733 }
2734
2735 API void ncplane_set_channels(struct ncplane* n, uint64_t channels);
2736
2737 // Set the specified style bits for the ncplane 'n', whether they're actively
2738 // supported or not.
2739 API void ncplane_set_styles(struct ncplane* n, unsigned stylebits);
2740
2741 // Add the specified styles to the ncplane's existing spec.
2742 API void ncplane_on_styles(struct ncplane* n, unsigned stylebits);
2743
2744 // Remove the specified styles from the ncplane's existing spec.
2745 API void ncplane_off_styles(struct ncplane* n, unsigned stylebits);
2746
2747 // Extract 24 bits of working foreground RGB from an ncplane, shifted to LSBs.
2748 static inline uint32_t
ncplane_fg_rgb(const struct ncplane * n)2749 ncplane_fg_rgb(const struct ncplane* n){
2750 return ncchannels_fg_rgb(ncplane_channels(n));
2751 }
2752
2753 // Extract 24 bits of working background RGB from an ncplane, shifted to LSBs.
2754 static inline uint32_t
ncplane_bg_rgb(const struct ncplane * n)2755 ncplane_bg_rgb(const struct ncplane* n){
2756 return ncchannels_bg_rgb(ncplane_channels(n));
2757 }
2758
2759 // Extract 2 bits of foreground alpha from 'struct ncplane', shifted to LSBs.
2760 static inline uint32_t
ncplane_fg_alpha(const struct ncplane * n)2761 ncplane_fg_alpha(const struct ncplane* n){
2762 return ncchannels_fg_alpha(ncplane_channels(n));
2763 }
2764
2765 // Is the plane's foreground using the "default foreground color"?
2766 static inline bool
ncplane_fg_default_p(const struct ncplane * n)2767 ncplane_fg_default_p(const struct ncplane* n){
2768 return ncchannels_fg_default_p(ncplane_channels(n));
2769 }
2770
2771 // Extract 2 bits of background alpha from 'struct ncplane', shifted to LSBs.
2772 static inline uint32_t
ncplane_bg_alpha(const struct ncplane * n)2773 ncplane_bg_alpha(const struct ncplane* n){
2774 return ncchannels_bg_alpha(ncplane_channels(n));
2775 }
2776
2777 // Is the plane's background using the "default background color"?
2778 static inline bool
ncplane_bg_default_p(const struct ncplane * n)2779 ncplane_bg_default_p(const struct ncplane* n){
2780 return ncchannels_bg_default_p(ncplane_channels(n));
2781 }
2782
2783 // Extract 24 bits of foreground RGB from 'n', split into components.
2784 static inline uint32_t
ncplane_fg_rgb8(const struct ncplane * n,unsigned * r,unsigned * g,unsigned * b)2785 ncplane_fg_rgb8(const struct ncplane* n, unsigned* r, unsigned* g, unsigned* b){
2786 return ncchannels_fg_rgb8(ncplane_channels(n), r, g, b);
2787 }
2788
2789 // Extract 24 bits of background RGB from 'n', split into components.
2790 static inline uint32_t
ncplane_bg_rgb8(const struct ncplane * n,unsigned * r,unsigned * g,unsigned * b)2791 ncplane_bg_rgb8(const struct ncplane* n, unsigned* r, unsigned* g, unsigned* b){
2792 return ncchannels_bg_rgb8(ncplane_channels(n), r, g, b);
2793 }
2794
2795 // Set an entire 32-bit channel of the plane
2796 API uint64_t ncplane_set_fchannel(struct ncplane* n, uint32_t channel);
2797 API uint64_t ncplane_set_bchannel(struct ncplane* n, uint32_t channel);
2798
2799 // Set the current fore/background color using RGB specifications. If the
2800 // terminal does not support directly-specified 3x8b cells (24-bit "TrueColor",
2801 // indicated by the "RGB" terminfo capability), the provided values will be
2802 // interpreted in some lossy fashion. None of r, g, or b may exceed 255.
2803 // "HP-like" terminals require setting foreground and background at the same
2804 // time using "color pairs"; Notcurses will manage color pairs transparently.
2805 API int ncplane_set_fg_rgb8(struct ncplane* n, unsigned r, unsigned g, unsigned b);
2806 API int ncplane_set_bg_rgb8(struct ncplane* n, unsigned r, unsigned g, unsigned b);
2807
2808 // Same, but clipped to [0..255].
2809 API void ncplane_set_bg_rgb8_clipped(struct ncplane* n, int r, int g, int b);
2810 API void ncplane_set_fg_rgb8_clipped(struct ncplane* n, int r, int g, int b);
2811
2812 // Same, but with rgb assembled into a channel (i.e. lower 24 bits).
2813 API int ncplane_set_fg_rgb(struct ncplane* n, uint32_t channel);
2814 API int ncplane_set_bg_rgb(struct ncplane* n, uint32_t channel);
2815
2816 // Use the default color for the foreground/background.
2817 API void ncplane_set_fg_default(struct ncplane* n);
2818 API void ncplane_set_bg_default(struct ncplane* n);
2819
2820 // Set the ncplane's foreground palette index, set the foreground palette index
2821 // bit, set it foreground-opaque, and clear the foreground default color bit.
2822 API int ncplane_set_fg_palindex(struct ncplane* n, int idx);
2823 API int ncplane_set_bg_palindex(struct ncplane* n, int idx);
2824
2825 // Set the alpha parameters for ncplane 'n'.
2826 API int ncplane_set_fg_alpha(struct ncplane* n, int alpha);
2827 API int ncplane_set_bg_alpha(struct ncplane* n, int alpha);
2828
2829 // Called for each fade iteration on 'ncp'. If anything but 0 is returned,
2830 // the fading operation ceases immediately, and that value is propagated out.
2831 // The recommended absolute display time target is passed in 'tspec'.
2832 typedef int (*fadecb)(struct notcurses* nc, struct ncplane* n,
2833 const struct timespec*, void* curry);
2834
2835 // Fade the ncplane out over the provided time, calling 'fader' at each
2836 // iteration. Requires a terminal which supports truecolor, or at least palette
2837 // modification (if the terminal uses a palette, our ability to fade planes is
2838 // limited, and affected by the complexity of the rest of the screen).
2839 API int ncplane_fadeout(struct ncplane* n, const struct timespec* ts,
2840 fadecb fader, void* curry)
2841 __attribute__ ((nonnull (1)));
2842
2843 // Fade the ncplane in over the specified time. Load the ncplane with the
2844 // target cells without rendering, then call this function. When it's done, the
2845 // ncplane will have reached the target levels, starting from zeroes.
2846 API int ncplane_fadein(struct ncplane* n, const struct timespec* ts,
2847 fadecb fader, void* curry)
2848 __attribute__ ((nonnull (1)));
2849
2850 // Rather than the simple ncplane_fade{in/out}(), ncfadectx_setup() can be
2851 // paired with a loop over ncplane_fade{in/out}_iteration() + ncfadectx_free().
2852 API ALLOC struct ncfadectx* ncfadectx_setup(struct ncplane* n)
2853 __attribute__ ((nonnull (1)));
2854
2855 // Return the number of iterations through which 'nctx' will fade.
2856 API int ncfadectx_iterations(const struct ncfadectx* nctx)
2857 __attribute__ ((nonnull (1)));
2858
2859 // Fade out through 'iter' iterations, where
2860 // 'iter' < 'ncfadectx_iterations(nctx)'.
2861 API int ncplane_fadeout_iteration(struct ncplane* n, struct ncfadectx* nctx,
2862 int iter, fadecb fader, void* curry)
2863 __attribute__ ((nonnull (1, 2)));
2864
2865 // Fade in through 'iter' iterations, where
2866 // 'iter' < 'ncfadectx_iterations(nctx)'.
2867 API int ncplane_fadein_iteration(struct ncplane* n, struct ncfadectx* nctx,
2868 int iter, fadecb fader, void* curry)
2869 __attribute__ ((nonnull (1, 2)));
2870
2871 // Pulse the plane in and out until the callback returns non-zero, relying on
2872 // the callback 'fader' to initiate rendering. 'ts' defines the half-period
2873 // (i.e. the transition from black to full brightness, or back again). Proper
2874 // use involves preparing (but not rendering) an ncplane, then calling
2875 // ncplane_pulse(), which will fade in from black to the specified colors.
2876 API int ncplane_pulse(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry)
2877 __attribute__ ((nonnull (1)));
2878
2879 // Release the resources associated with 'nctx'.
2880 API void ncfadectx_free(struct ncfadectx* nctx);
2881
2882 // load up six cells with the EGCs necessary to draw a box. returns 0 on
2883 // success, -1 on error. on error, any cells this function might
2884 // have loaded before the error are nccell_release()d. There must be at least
2885 // six EGCs in gcluster.
2886 static inline int
nccells_load_box(struct ncplane * n,uint32_t styles,uint64_t channels,nccell * ul,nccell * ur,nccell * ll,nccell * lr,nccell * hl,nccell * vl,const char * gclusters)2887 nccells_load_box(struct ncplane* n, uint32_t styles, uint64_t channels,
2888 nccell* ul, nccell* ur, nccell* ll, nccell* lr,
2889 nccell* hl, nccell* vl, const char* gclusters){
2890 int ulen;
2891 if((ulen = nccell_prime(n, ul, gclusters, styles, channels)) > 0){
2892 if((ulen = nccell_prime(n, ur, gclusters += ulen, styles, channels)) > 0){
2893 if((ulen = nccell_prime(n, ll, gclusters += ulen, styles, channels)) > 0){
2894 if((ulen = nccell_prime(n, lr, gclusters += ulen, styles, channels)) > 0){
2895 if((ulen = nccell_prime(n, hl, gclusters += ulen, styles, channels)) > 0){
2896 if(nccell_prime(n, vl, gclusters + ulen, styles, channels) > 0){
2897 return 0;
2898 }
2899 nccell_release(n, hl);
2900 }
2901 nccell_release(n, lr);
2902 }
2903 nccell_release(n, ll);
2904 }
2905 nccell_release(n, ur);
2906 }
2907 nccell_release(n, ul);
2908 }
2909 return -1;
2910 }
2911
2912 static inline int
nccells_ascii_box(struct ncplane * n,uint16_t attr,uint64_t channels,nccell * ul,nccell * ur,nccell * ll,nccell * lr,nccell * hl,nccell * vl)2913 nccells_ascii_box(struct ncplane* n, uint16_t attr, uint64_t channels,
2914 nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
2915 return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXASCII);
2916 }
2917
2918 static inline int
nccells_double_box(struct ncplane * n,uint16_t attr,uint64_t channels,nccell * ul,nccell * ur,nccell * ll,nccell * lr,nccell * hl,nccell * vl)2919 nccells_double_box(struct ncplane* n, uint16_t attr, uint64_t channels,
2920 nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
2921 if(notcurses_canutf8(ncplane_notcurses(n))){
2922 return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXDOUBLE);
2923 }
2924 return nccells_ascii_box(n, attr, channels, ul, ur, ll, lr, hl, vl);
2925 }
2926
2927 static inline int
nccells_rounded_box(struct ncplane * n,uint16_t attr,uint64_t channels,nccell * ul,nccell * ur,nccell * ll,nccell * lr,nccell * hl,nccell * vl)2928 nccells_rounded_box(struct ncplane* n, uint16_t attr, uint64_t channels,
2929 nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
2930 if(notcurses_canutf8(ncplane_notcurses(n))){
2931 return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXROUND);
2932 }
2933 return nccells_ascii_box(n, attr, channels, ul, ur, ll, lr, hl, vl);
2934 }
2935
2936 static inline int
nccells_light_box(struct ncplane * n,uint16_t attr,uint64_t channels,nccell * ul,nccell * ur,nccell * ll,nccell * lr,nccell * hl,nccell * vl)2937 nccells_light_box(struct ncplane* n, uint16_t attr, uint64_t channels,
2938 nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
2939 if(notcurses_canutf8(ncplane_notcurses(n))){
2940 return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXLIGHT);
2941 }
2942 return nccells_ascii_box(n, attr, channels, ul, ur, ll, lr, hl, vl);
2943 }
2944
2945 static inline int
nccells_heavy_box(struct ncplane * n,uint16_t attr,uint64_t channels,nccell * ul,nccell * ur,nccell * ll,nccell * lr,nccell * hl,nccell * vl)2946 nccells_heavy_box(struct ncplane* n, uint16_t attr, uint64_t channels,
2947 nccell* ul, nccell* ur, nccell* ll, nccell* lr, nccell* hl, nccell* vl){
2948 if(notcurses_canutf8(ncplane_notcurses(n))){
2949 return nccells_load_box(n, attr, channels, ul, ur, ll, lr, hl, vl, NCBOXHEAVY);
2950 }
2951 return nccells_ascii_box(n, attr, channels, ul, ur, ll, lr, hl, vl);
2952 }
2953
2954 static inline int
ncplane_rounded_box(struct ncplane * n,uint16_t styles,uint64_t channels,unsigned ystop,unsigned xstop,unsigned ctlword)2955 ncplane_rounded_box(struct ncplane* n, uint16_t styles, uint64_t channels,
2956 unsigned ystop, unsigned xstop, unsigned ctlword){
2957 int ret = 0;
2958 nccell ul = NCCELL_TRIVIAL_INITIALIZER, ur = NCCELL_TRIVIAL_INITIALIZER;
2959 nccell ll = NCCELL_TRIVIAL_INITIALIZER, lr = NCCELL_TRIVIAL_INITIALIZER;
2960 nccell hl = NCCELL_TRIVIAL_INITIALIZER, vl = NCCELL_TRIVIAL_INITIALIZER;
2961 if((ret = nccells_rounded_box(n, styles, channels, &ul, &ur, &ll, &lr, &hl, &vl)) == 0){
2962 ret = ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword);
2963 }
2964 nccell_release(n, &ul); nccell_release(n, &ur);
2965 nccell_release(n, &ll); nccell_release(n, &lr);
2966 nccell_release(n, &hl); nccell_release(n, &vl);
2967 return ret;
2968 }
2969
2970 static inline int
ncplane_perimeter_rounded(struct ncplane * n,uint16_t stylemask,uint64_t channels,unsigned ctlword)2971 ncplane_perimeter_rounded(struct ncplane* n, uint16_t stylemask,
2972 uint64_t channels, unsigned ctlword){
2973 if(ncplane_cursor_move_yx(n, 0, 0)){
2974 return -1;
2975 }
2976 unsigned dimy, dimx;
2977 ncplane_dim_yx(n, &dimy, &dimx);
2978 nccell ul = NCCELL_TRIVIAL_INITIALIZER;
2979 nccell ur = NCCELL_TRIVIAL_INITIALIZER;
2980 nccell ll = NCCELL_TRIVIAL_INITIALIZER;
2981 nccell lr = NCCELL_TRIVIAL_INITIALIZER;
2982 nccell vl = NCCELL_TRIVIAL_INITIALIZER;
2983 nccell hl = NCCELL_TRIVIAL_INITIALIZER;
2984 if(nccells_rounded_box(n, stylemask, channels, &ul, &ur, &ll, &lr, &hl, &vl)){
2985 return -1;
2986 }
2987 int r = ncplane_box_sized(n, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, ctlword);
2988 nccell_release(n, &ul); nccell_release(n, &ur);
2989 nccell_release(n, &ll); nccell_release(n, &lr);
2990 nccell_release(n, &hl); nccell_release(n, &vl);
2991 return r;
2992 }
2993
2994 static inline int
ncplane_rounded_box_sized(struct ncplane * n,uint16_t styles,uint64_t channels,unsigned ylen,unsigned xlen,unsigned ctlword)2995 ncplane_rounded_box_sized(struct ncplane* n, uint16_t styles, uint64_t channels,
2996 unsigned ylen, unsigned xlen, unsigned ctlword){
2997 unsigned y, x;
2998 ncplane_cursor_yx(n, &y, &x);
2999 return ncplane_rounded_box(n, styles, channels, y + ylen - 1,
3000 x + xlen - 1, ctlword);
3001 }
3002
3003 static inline int
ncplane_double_box(struct ncplane * n,uint16_t styles,uint64_t channels,unsigned ylen,unsigned xlen,unsigned ctlword)3004 ncplane_double_box(struct ncplane* n, uint16_t styles, uint64_t channels,
3005 unsigned ylen, unsigned xlen, unsigned ctlword){
3006 int ret = 0;
3007 nccell ul = NCCELL_TRIVIAL_INITIALIZER, ur = NCCELL_TRIVIAL_INITIALIZER;
3008 nccell ll = NCCELL_TRIVIAL_INITIALIZER, lr = NCCELL_TRIVIAL_INITIALIZER;
3009 nccell hl = NCCELL_TRIVIAL_INITIALIZER, vl = NCCELL_TRIVIAL_INITIALIZER;
3010 if((ret = nccells_double_box(n, styles, channels, &ul, &ur, &ll, &lr, &hl, &vl)) == 0){
3011 ret = ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, ylen, xlen, ctlword);
3012 }
3013 nccell_release(n, &ul); nccell_release(n, &ur);
3014 nccell_release(n, &ll); nccell_release(n, &lr);
3015 nccell_release(n, &hl); nccell_release(n, &vl);
3016 return ret;
3017 }
3018
3019 static inline int
ncplane_ascii_box(struct ncplane * n,uint16_t styles,uint64_t channels,unsigned ylen,unsigned xlen,unsigned ctlword)3020 ncplane_ascii_box(struct ncplane* n, uint16_t styles, uint64_t channels,
3021 unsigned ylen, unsigned xlen, unsigned ctlword){
3022 int ret = 0;
3023 nccell ul = NCCELL_TRIVIAL_INITIALIZER, ur = NCCELL_TRIVIAL_INITIALIZER;
3024 nccell ll = NCCELL_TRIVIAL_INITIALIZER, lr = NCCELL_TRIVIAL_INITIALIZER;
3025 nccell hl = NCCELL_TRIVIAL_INITIALIZER, vl = NCCELL_TRIVIAL_INITIALIZER;
3026 if((ret = nccells_ascii_box(n, styles, channels, &ul, &ur, &ll, &lr, &hl, &vl)) == 0){
3027 ret = ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, ylen, xlen, ctlword);
3028 }
3029 nccell_release(n, &ul); nccell_release(n, &ur);
3030 nccell_release(n, &ll); nccell_release(n, &lr);
3031 nccell_release(n, &hl); nccell_release(n, &vl);
3032 return ret;
3033 }
3034
3035 static inline int
ncplane_perimeter_double(struct ncplane * n,uint16_t stylemask,uint64_t channels,unsigned ctlword)3036 ncplane_perimeter_double(struct ncplane* n, uint16_t stylemask,
3037 uint64_t channels, unsigned ctlword){
3038 if(ncplane_cursor_move_yx(n, 0, 0)){
3039 return -1;
3040 }
3041 unsigned dimy, dimx;
3042 ncplane_dim_yx(n, &dimy, &dimx);
3043 nccell ul = NCCELL_TRIVIAL_INITIALIZER;
3044 nccell ur = NCCELL_TRIVIAL_INITIALIZER;
3045 nccell ll = NCCELL_TRIVIAL_INITIALIZER;
3046 nccell lr = NCCELL_TRIVIAL_INITIALIZER;
3047 nccell vl = NCCELL_TRIVIAL_INITIALIZER;
3048 nccell hl = NCCELL_TRIVIAL_INITIALIZER;
3049 if(nccells_double_box(n, stylemask, channels, &ul, &ur, &ll, &lr, &hl, &vl)){
3050 return -1;
3051 }
3052 int r = ncplane_box_sized(n, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, ctlword);
3053 nccell_release(n, &ul); nccell_release(n, &ur);
3054 nccell_release(n, &ll); nccell_release(n, &lr);
3055 nccell_release(n, &hl); nccell_release(n, &vl);
3056 return r;
3057 }
3058
3059 static inline int
ncplane_double_box_sized(struct ncplane * n,uint16_t styles,uint64_t channels,unsigned ylen,unsigned xlen,unsigned ctlword)3060 ncplane_double_box_sized(struct ncplane* n, uint16_t styles, uint64_t channels,
3061 unsigned ylen, unsigned xlen, unsigned ctlword){
3062 unsigned y, x;
3063 ncplane_cursor_yx(n, &y, &x);
3064 return ncplane_double_box(n, styles, channels, y + ylen - 1,
3065 x + xlen - 1, ctlword);
3066 }
3067
3068 // Open a visual at 'file', extract a codec and parameters, decode the first
3069 // image to memory.
3070 API ALLOC struct ncvisual* ncvisual_from_file(const char* file)
3071 __attribute__ ((nonnull (1)));
3072
3073 // Prepare an ncvisual, and its underlying plane, based off RGBA content in
3074 // memory at 'rgba'. 'rgba' is laid out as 'rows' lines, each of which is
3075 // 'rowstride' bytes in length. Each line has 'cols' 32-bit 8bpc RGBA pixels
3076 // followed by possible padding (there will be 'rowstride' - 'cols' * 4 bytes
3077 // of padding). The total size of 'rgba' is thus (rows * rowstride) bytes, of
3078 // which (rows * cols * 4) bytes are actual non-padding data.
3079 API ALLOC struct ncvisual* ncvisual_from_rgba(const void* rgba, int rows,
3080 int rowstride, int cols)
3081 __attribute__ ((nonnull (1)));
3082
3083 // ncvisual_from_rgba(), but the pixels are 3-byte RGB. A is filled in
3084 // throughout using 'alpha'.
3085 API ALLOC struct ncvisual* ncvisual_from_rgb_packed(const void* rgba, int rows,
3086 int rowstride, int cols,
3087 int alpha)
3088 __attribute__ ((nonnull (1)));
3089
3090 // ncvisual_from_rgba(), but the pixels are 4-byte RGBx. A is filled in
3091 // throughout using 'alpha'. rowstride must be a multiple of 4.
3092 API ALLOC struct ncvisual* ncvisual_from_rgb_loose(const void* rgba, int rows,
3093 int rowstride, int cols,
3094 int alpha)
3095 __attribute__ ((nonnull (1)));
3096
3097 // ncvisual_from_rgba(), but 'bgra' is arranged as BGRA. note that this is a
3098 // byte-oriented layout, despite being bunched in 32-bit pixels; the lowest
3099 // memory address ought be B, and A is reached by adding 3 to that address.
3100 API ALLOC struct ncvisual* ncvisual_from_bgra(const void* bgra, int rows,
3101 int rowstride, int cols)
3102 __attribute__ ((nonnull (1)));
3103
3104 // ncvisual_from_rgba(), but 'data' is 'pstride'-byte palette-indexed pixels,
3105 // arranged in 'rows' lines of 'rowstride' bytes each, composed of 'cols'
3106 // pixels. 'palette' is an array of at least 'palsize' ncchannels.
3107 API ALLOC struct ncvisual* ncvisual_from_palidx(const void* data, int rows,
3108 int rowstride, int cols,
3109 int palsize, int pstride,
3110 const uint32_t* palette)
3111 __attribute__ ((nonnull (1, 7)));
3112
3113 // Promote an ncplane 'n' to an ncvisual. The plane may contain only spaces,
3114 // half blocks, and full blocks. The latter will be checked, and any other
3115 // glyph will result in a NULL being returned. This function exists so that
3116 // planes can be subjected to ncvisual transformations. If possible, it's
3117 // better to create the ncvisual from memory using ncvisual_from_rgba().
3118 // Lengths of 0 are interpreted to mean "all available remaining area".
3119 API ALLOC struct ncvisual* ncvisual_from_plane(const struct ncplane* n,
3120 ncblitter_e blit,
3121 int begy, int begx,
3122 unsigned leny, unsigned lenx)
3123 __attribute__ ((nonnull (1)));
3124
3125 #define NCVISUAL_OPTION_NODEGRADE 0x0001ull // fail rather than degrade
3126 #define NCVISUAL_OPTION_BLEND 0x0002ull // use NCALPHA_BLEND with visual
3127 #define NCVISUAL_OPTION_HORALIGNED 0x0004ull // x is an alignment, not absolute
3128 #define NCVISUAL_OPTION_VERALIGNED 0x0008ull // y is an alignment, not absolute
3129 #define NCVISUAL_OPTION_ADDALPHA 0x0010ull // transcolor is in effect
3130 #define NCVISUAL_OPTION_CHILDPLANE 0x0020ull // interpret n as parent
3131 #define NCVISUAL_OPTION_NOINTERPOLATE 0x0040ull // non-interpolative scaling
3132
3133 struct ncvisual_options {
3134 // if no ncplane is provided, one will be created using the exact size
3135 // necessary to render the source with perfect fidelity (this might be
3136 // smaller or larger than the rendering area). if NCVISUAL_OPTION_CHILDPLANE
3137 // is provided, this must be non-NULL, and will be interpreted as the parent.
3138 struct ncplane* n;
3139 // the scaling is ignored if no ncplane is provided (it ought be NCSCALE_NONE
3140 // in this case). otherwise, the source is stretched/scaled relative to the
3141 // provided ncplane.
3142 ncscale_e scaling;
3143 // if an ncplane is provided, y and x specify where the visual will be
3144 // rendered on that plane. otherwise, they specify where the created ncplane
3145 // will be placed relative to the standard plane's origin. x is an ncalign_e
3146 // value if NCVISUAL_OPTION_HORALIGNED is provided. y is an ncalign_e if
3147 // NCVISUAL_OPTION_VERALIGNED is provided.
3148 int y, x;
3149 // the region of the visual that ought be rendered. for the entire visual,
3150 // pass an origin of 0, 0 and a size of 0, 0 (or the true height and width).
3151 // these numbers are all in terms of ncvisual pixels. negative values are
3152 // prohibited.
3153 unsigned begy, begx; // origin of rendered region in pixels
3154 unsigned leny, lenx; // size of rendered region in pixels
3155 // use NCBLIT_DEFAULT if you don't care, an appropriate blitter will be
3156 // chosen for your terminal, given your scaling. NCBLIT_PIXEL is never
3157 // chosen for NCBLIT_DEFAULT.
3158 ncblitter_e blitter; // glyph set to use (maps input to output cells)
3159 uint64_t flags; // bitmask over NCVISUAL_OPTION_*
3160 uint32_t transcolor; // treat this color as transparent under NCVISUAL_OPTION_ADDALPHA
3161 // pixel offsets within the cell. if NCBLIT_PIXEL is used, the bitmap will
3162 // be drawn offset from the upper-left cell's origin by these amounts. it is
3163 // an error if either number exceeds the cell-pixel geometry in its
3164 // dimension. if NCBLIT_PIXEL is not used, these fields are ignored.
3165 // this functionality can be used for smooth bitmap movement.
3166 unsigned pxoffy, pxoffx;
3167 };
3168
3169 // describes all geometries of an ncvisual: those which are inherent, and those
3170 // dependent upon a given rendering regime. pixy and pixx are the true internal
3171 // pixel geometry, taken directly from the load (and updated by
3172 // ncvisual_resize()). cdimy/cdimx are the cell-pixel geometry *at the time
3173 // of this call* (it can change with a font change, in which case all values
3174 // other than pixy/pixx are invalidated). rpixy/rpixx are the pixel geometry as
3175 // handed to the blitter, following any scaling. scaley/scalex are the number
3176 // of input pixels drawn to a single cell; when using NCBLIT_PIXEL, they are
3177 // equivalent to cdimy/cdimx. rcelly/rcellx are the cell geometry as written by
3178 // the blitter, following any padding (there is padding whenever rpix{y, x} is
3179 // not evenly divided by scale{y, x}, and also sometimes for Sixel).
3180 // maxpixely/maxpixelx are defined only when NCBLIT_PIXEL is used, and specify
3181 // the largest bitmap that the terminal is willing to accept. blitter is the
3182 // blitter which will be used, a function of the requested blitter and the
3183 // blitters actually supported by this environment. if no ncvisual was
3184 // supplied, only cdimy/cdimx are filled in.
3185 typedef struct ncvgeom {
3186 unsigned pixy, pixx; // true pixel geometry of ncvisual data
3187 unsigned cdimy, cdimx; // terminal cell geometry when this was calculated
3188 unsigned rpixy, rpixx; // rendered pixel geometry (per visual_options)
3189 unsigned rcelly, rcellx; // rendered cell geometry (per visual_options)
3190 unsigned scaley, scalex; // pixels per filled cell (scale == c for bitmaps)
3191 unsigned begy, begx; // upper-left corner of used region
3192 unsigned leny, lenx; // geometry of used region
3193 unsigned maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL
3194 ncblitter_e blitter; // blitter that will be used
3195 } ncvgeom;
3196
3197 // all-purpose ncvisual geometry solver. one or both of 'nc' and 'n' must be
3198 // non-NULL. if 'nc' is NULL, only pixy/pixx will be filled in, with the true
3199 // pixel geometry of 'n'. if 'n' is NULL, only cdimy/cdimx, blitter,
3200 // scaley/scalex, and maxpixely/maxpixelx are filled in. cdimy/cdimx and
3201 // maxpixely/maxpixelx are only ever filled in if we know them.
3202 API int ncvisual_geom(const struct notcurses* nc, const struct ncvisual* n,
3203 const struct ncvisual_options* vopts, ncvgeom* geom)
3204 __attribute__ ((nonnull (4)));
3205
3206 // Destroy an ncvisual. Rendered elements will not be disrupted, but the visual
3207 // can be neither decoded nor rendered any further.
3208 API void ncvisual_destroy(struct ncvisual* ncv);
3209
3210 // extract the next frame from an ncvisual. returns 1 on end of file, 0 on
3211 // success, and -1 on failure.
3212 API int ncvisual_decode(struct ncvisual* nc)
3213 __attribute__ ((nonnull (1)));
3214
3215 // decode the next frame ala ncvisual_decode(), but if we have reached the end,
3216 // rewind to the first frame of the ncvisual. a subsequent 'ncvisual_blit()'
3217 // will render the first frame, as if the ncvisual had been closed and reopened.
3218 // the return values remain the same as those of ncvisual_decode().
3219 API int ncvisual_decode_loop(struct ncvisual* nc)
3220 __attribute__ ((nonnull (1)));
3221
3222 // Rotate the visual 'rads' radians. Only M_PI/2 and -M_PI/2 are supported at
3223 // the moment, but this might change in the future.
3224 API int ncvisual_rotate(struct ncvisual* n, double rads)
3225 __attribute__ ((nonnull (1)));
3226
3227 // Scale the visual to 'rows' X 'columns' pixels, using the best scheme
3228 // available. This is a lossy transformation, unless the size is unchanged.
3229 API int ncvisual_resize(struct ncvisual* n, int rows, int cols)
3230 __attribute__ ((nonnull (1)));
3231
3232 // Scale the visual to 'rows' X 'columns' pixels, using non-interpolative
3233 // (naive) scaling. No new colors will be introduced as a result.
3234 API int ncvisual_resize_noninterpolative(struct ncvisual* n, int rows, int cols)
3235 __attribute__ ((nonnull (1)));
3236
3237 // Polyfill at the specified location within the ncvisual 'n', using 'rgba'.
3238 API int ncvisual_polyfill_yx(struct ncvisual* n, unsigned y, unsigned x, uint32_t rgba)
3239 __attribute__ ((nonnull (1)));
3240
3241 // Get the specified pixel from the specified ncvisual.
3242 API int ncvisual_at_yx(const struct ncvisual* n, unsigned y, unsigned x,
3243 uint32_t* pixel)
3244 __attribute__ ((nonnull (1, 4)));
3245
3246 // Set the specified pixel in the specified ncvisual.
3247 API int ncvisual_set_yx(const struct ncvisual* n, unsigned y, unsigned x,
3248 uint32_t pixel)
3249 __attribute__ ((nonnull (1)));
3250
3251 // Render the decoded frame according to the provided options (which may be
3252 // NULL). The plane used for rendering depends on vopts->n and vopts->flags.
3253 // If NCVISUAL_OPTION_CHILDPLANE is set, vopts->n must not be NULL, and the
3254 // plane will always be created as a child of vopts->n. If this flag is not
3255 // set, and vopts->n is NULL, a new plane is created as root of a new pile.
3256 // If the flag is not set and vopts->n is not NULL, we render to vopts->n.
3257 // A subregion of the visual can be rendered using 'begx', 'begy', 'lenx', and
3258 // 'leny'. Negative values for any of these are an error. It is an error to
3259 // specify any region beyond the boundaries of the frame. Returns the (possibly
3260 // newly-created) plane to which we drew. Pixels may not be blitted to the
3261 // standard plane.
3262 API struct ncplane* ncvisual_blit(struct notcurses* nc, struct ncvisual* ncv,
3263 const struct ncvisual_options* vopts)
3264 __attribute__ ((nonnull (2)));
3265
3266 // Create a new plane as prescribed in opts, either as a child of 'vopts->n',
3267 // or the root of a new pile if 'vopts->n' is NULL (or 'vopts' itself is NULL).
3268 // Blit 'ncv' to the created plane according to 'vopts'. If 'vopts->n' is
3269 // non-NULL, NCVISUAL_OPTION_CHILDPLANE must be supplied.
3270 __attribute__ ((nonnull (1, 2, 3))) static inline struct ncplane*
ncvisualplane_create(struct notcurses * nc,const struct ncplane_options * opts,struct ncvisual * ncv,struct ncvisual_options * vopts)3271 ncvisualplane_create(struct notcurses* nc, const struct ncplane_options* opts,
3272 struct ncvisual* ncv, struct ncvisual_options* vopts){
3273 struct ncplane* newn;
3274 if(vopts && vopts->n){
3275 if(vopts->flags & NCVISUAL_OPTION_CHILDPLANE){
3276 return NULL; // the whole point is to create a new plane
3277 }
3278 newn = ncplane_create(vopts->n, opts);
3279 }else{
3280 newn = ncpile_create(nc, opts);
3281 }
3282 if(newn == NULL){
3283 return NULL;
3284 }
3285 struct ncvisual_options v;
3286 if(!vopts){
3287 vopts = &v;
3288 memset(vopts, 0, sizeof(*vopts));
3289 }
3290 vopts->n = newn;
3291 if(ncvisual_blit(nc, ncv, vopts) == NULL){
3292 ncplane_destroy(newn);
3293 vopts->n = NULL;
3294 return NULL;
3295 }
3296 return newn;
3297 }
3298
3299 // If a subtitle ought be displayed at this time, return a new plane (bound
3300 // to 'parent' containing the subtitle, which might be text or graphics
3301 // (depending on the input format).
3302 API ALLOC struct ncplane* ncvisual_subtitle_plane(struct ncplane* parent,
3303 const struct ncvisual* ncv)
3304 __attribute__ ((nonnull (1, 2)));
3305
3306 // Get the default *media* (not plot) blitter for this environment when using
3307 // the specified scaling method. Currently, this means:
3308 // - if lacking UTF-8, NCBLIT_1x1
3309 // - otherwise, if not NCSCALE_STRETCH, NCBLIT_2x1
3310 // - otherwise, if sextants are not known to be good, NCBLIT_2x2
3311 // - otherwise NCBLIT_3x2
3312 // NCBLIT_2x2 and NCBLIT_3x2 both distort the original aspect ratio, thus
3313 // NCBLIT_2x1 is used outside of NCSCALE_STRETCH.
3314 API ncblitter_e ncvisual_media_defblitter(const struct notcurses* nc, ncscale_e scale)
3315 __attribute__ ((nonnull (1)));
3316
3317 // Called for each frame rendered from 'ncv'. If anything but 0 is returned,
3318 // the streaming operation ceases immediately, and that value is propagated out.
3319 // The recommended absolute display time target is passed in 'tspec'.
3320 typedef int (*ncstreamcb)(struct ncvisual*, struct ncvisual_options*,
3321 const struct timespec*, void*);
3322
3323 // Shut up and display my frames! Provide as an argument to ncvisual_stream().
3324 // If you'd like subtitles to be decoded, provide an ncplane as the curry. If the
3325 // curry is NULL, subtitles will not be displayed.
3326 API int ncvisual_simple_streamer(struct ncvisual* ncv, struct ncvisual_options* vopts,
3327 const struct timespec* tspec, void* curry)
3328 __attribute__ ((nonnull (1)));
3329
3330 // Stream the entirety of the media, according to its own timing. Blocking,
3331 // obviously. streamer may be NULL; it is otherwise called for each frame, and
3332 // its return value handled as outlined for streamcb. If streamer() returns
3333 // non-zero, the stream is aborted, and that value is returned. By convention,
3334 // return a positive number to indicate intentional abort from within
3335 // streamer(). 'timescale' allows the frame duration time to be scaled. For a
3336 // visual naturally running at 30FPS, a 'timescale' of 0.1 will result in
3337 // 300FPS, and a 'timescale' of 10 will result in 3FPS. It is an error to
3338 // supply 'timescale' less than or equal to 0.
3339 API int ncvisual_stream(struct notcurses* nc, struct ncvisual* ncv,
3340 float timescale, ncstreamcb streamer,
3341 const struct ncvisual_options* vopts, void* curry)
3342 __attribute__ ((nonnull (1, 2)));
3343
3344 // Blit a flat array 'data' of RGBA 32-bit values to the ncplane 'vopts->n',
3345 // which mustn't be NULL. the blit begins at 'vopts->y' and 'vopts->x' relative
3346 // to the specified plane. Each source row ought occupy 'linesize' bytes (this
3347 // might be greater than 'vopts->lenx' * 4 due to padding or partial blits). A
3348 // subregion of the input can be specified with the 'begy'x'begx' and
3349 // 'leny'x'lenx' fields from 'vopts'. Returns the number of pixels blitted, or
3350 // -1 on error.
3351 API int ncblit_rgba(const void* data, int linesize,
3352 const struct ncvisual_options* vopts)
3353 __attribute__ ((nonnull (1)));
3354
3355 // Same as ncblit_rgba(), but for BGRx.
3356 API int ncblit_bgrx(const void* data, int linesize,
3357 const struct ncvisual_options* vopts)
3358 __attribute__ ((nonnull (1)));
3359
3360 // Supply an alpha value [0..255] to be applied throughout.
3361 API int ncblit_rgb_packed(const void* data, int linesize,
3362 const struct ncvisual_options* vopts, int alpha)
3363 __attribute__ ((nonnull (1)));
3364
3365 // Supply an alpha value [0..255] to be applied throughout. linesize must be
3366 // a multiple of 4 for this RGBx data.
3367 API int ncblit_rgb_loose(const void* data, int linesize,
3368 const struct ncvisual_options* vopts, int alpha)
3369 __attribute__ ((nonnull (1)));
3370
3371 // The ncpixel API facilitates direct management of the pixels within an
3372 // ncvisual (ncvisuals keep a backing store of 32-bit RGBA pixels, and render
3373 // them down to terminal graphics in ncvisual_blit()).
3374 //
3375 // Per libav, we "store as BGRA on little-endian, and ARGB on big-endian".
3376 // This is an RGBA *byte-order* scheme. libav emits bytes, not words. Those
3377 // bytes are R-G-B-A. When read as words, on little endian this will be ABGR,
3378 // and on big-endian this will be RGBA. force everything to LE ABGR, a no-op
3379 // on (and thus favoring) little-endian. Take that, big-endian mafia!
3380
3381 // Extract the 8-bit alpha component from a pixel
3382 static inline unsigned
ncpixel_a(uint32_t pixel)3383 ncpixel_a(uint32_t pixel){
3384 return (htole(pixel) & 0xff000000ul) >> 24u;
3385 }
3386
3387 // Extract the 8-bit red component from an ABGR pixel
3388 static inline unsigned
ncpixel_r(uint32_t pixel)3389 ncpixel_r(uint32_t pixel){
3390 return (htole(pixel) & 0x000000fful);
3391 }
3392
3393 // Extract the 8-bit green component from an ABGR pixel
3394 static inline unsigned
ncpixel_g(uint32_t pixel)3395 ncpixel_g(uint32_t pixel){
3396 return (htole(pixel) & 0x0000ff00ul) >> 8u;
3397 }
3398
3399 // Extract the 8-bit blue component from an ABGR pixel
3400 static inline unsigned
ncpixel_b(uint32_t pixel)3401 ncpixel_b(uint32_t pixel){
3402 return (htole(pixel) & 0x00ff0000ul) >> 16u;
3403 }
3404
3405 // Set the 8-bit alpha component of an ABGR pixel
3406 static inline int
ncpixel_set_a(uint32_t * pixel,unsigned a)3407 ncpixel_set_a(uint32_t* pixel, unsigned a){
3408 if(a > 255){
3409 return -1;
3410 }
3411 *pixel = htole((htole(*pixel) & 0x00fffffful) | (a << 24u));
3412 return 0;
3413 }
3414
3415 // Set the 8-bit red component of an ABGR pixel
3416 static inline int
ncpixel_set_r(uint32_t * pixel,unsigned r)3417 ncpixel_set_r(uint32_t* pixel, unsigned r){
3418 if(r > 255){
3419 return -1;
3420 }
3421 *pixel = htole((htole(*pixel) & 0xffffff00ul) | r);
3422 return 0;
3423 }
3424
3425 // Set the 8-bit green component of an ABGR pixel
3426 static inline int
ncpixel_set_g(uint32_t * pixel,unsigned g)3427 ncpixel_set_g(uint32_t* pixel, unsigned g){
3428 if(g > 255){
3429 return -1;
3430 }
3431 *pixel = htole((htole(*pixel) & 0xffff00fful) | (g << 8u));
3432 return 0;
3433 }
3434
3435 // Set the 8-bit blue component of an ABGR pixel
3436 static inline int
ncpixel_set_b(uint32_t * pixel,unsigned b)3437 ncpixel_set_b(uint32_t* pixel, unsigned b){
3438 if(b > 255){
3439 return -1;
3440 }
3441 *pixel = htole((htole(*pixel) & 0xff00fffful) | (b << 16u));
3442 return 0;
3443 }
3444
3445 // Construct a libav-compatible ABGR pixel, clipping at [0, 255).
3446 static inline uint32_t
ncpixel(int r,int g,int b)3447 ncpixel(int r, int g, int b){
3448 uint32_t pixel = 0;
3449 ncpixel_set_a(&pixel, 0xff);
3450 if(r < 0) r = 0;
3451 if(r > 255) r = 255;
3452 ncpixel_set_r(&pixel, r);
3453 if(g < 0) g = 0;
3454 if(g > 255) g = 255;
3455 ncpixel_set_g(&pixel, g);
3456 if(b < 0) b = 0;
3457 if(b > 255) b = 255;
3458 ncpixel_set_b(&pixel, b);
3459 return pixel;
3460 }
3461
3462 // set the RGB values of an RGB pixel
3463 static inline int
ncpixel_set_rgb8(uint32_t * pixel,unsigned r,unsigned g,unsigned b)3464 ncpixel_set_rgb8(uint32_t* pixel, unsigned r, unsigned g, unsigned b){
3465 if(ncpixel_set_r(pixel, r) || ncpixel_set_g(pixel, g) || ncpixel_set_b(pixel, b)){
3466 return -1;
3467 }
3468 return 0;
3469 }
3470
3471 // An ncreel is a Notcurses region devoted to displaying zero or more
3472 // line-oriented, contained tablets between which the user may navigate. If at
3473 // least one tablets exists, there is a "focused tablet". As much of the focused
3474 // tablet as is possible is always displayed. If there is space left over, other
3475 // tablets are included in the display. Tablets can come and go at any time, and
3476 // can grow or shrink at any time.
3477 //
3478 // This structure is amenable to line- and page-based navigation via keystrokes,
3479 // scrolling gestures, trackballs, scrollwheels, touchpads, and verbal commands.
3480
3481 // is scrolling infinite (can one move down or up forever, or is an end
3482 // reached?). if true, 'circular' specifies how to handle the special case of
3483 // an incompletely-filled reel.
3484 #define NCREEL_OPTION_INFINITESCROLL 0x0001ull
3485 // is navigation circular (does moving down from the last tablet move to the
3486 // first, and vice versa)? only meaningful when infinitescroll is true. if
3487 // infinitescroll is false, this must be false.
3488 #define NCREEL_OPTION_CIRCULAR 0x0002ull
3489
3490 typedef struct ncreel_options {
3491 // Notcurses can draw a border around the ncreel, and also around the
3492 // component tablets. inhibit borders by setting all valid bits in the masks.
3493 // partially inhibit borders by setting individual bits in the masks. the
3494 // appropriate attr and pair values will be used to style the borders.
3495 // focused and non-focused tablets can have different styles. you can instead
3496 // draw your own borders, or forgo borders entirely.
3497 unsigned bordermask; // bitfield; 1s will not be drawn (see bordermaskbits)
3498 uint64_t borderchan; // attributes used for ncreel border
3499 unsigned tabletmask; // bitfield; same as bordermask but for tablet borders
3500 uint64_t tabletchan; // tablet border styling channel
3501 uint64_t focusedchan;// focused tablet border styling channel
3502 uint64_t flags; // bitfield over NCREEL_OPTION_*
3503 } ncreel_options;
3504
3505 // Take over the ncplane 'nc' and use it to draw a reel according to 'popts'.
3506 // The plane will be destroyed by ncreel_destroy(); this transfers ownership.
3507 API ALLOC struct ncreel* ncreel_create(struct ncplane* n, const ncreel_options* popts)
3508 __attribute__ ((nonnull (1)));
3509
3510 // Returns the ncplane on which this ncreel lives.
3511 API struct ncplane* ncreel_plane(struct ncreel* nr)
3512 __attribute__ ((nonnull (1)));
3513
3514 // Tablet draw callback, provided a tablet (from which the ncplane and userptr
3515 // may be extracted), and a bool indicating whether output ought be drawn from
3516 // the top (true) or bottom (false). Returns non-negative count of output lines,
3517 // which must be less than or equal to ncplane_dim_y(nctablet_plane(t)).
3518 typedef int (*tabletcb)(struct nctablet* t, bool drawfromtop);
3519
3520 // Add a new nctablet to the provided ncreel 'nr', having the callback object
3521 // 'opaque'. Neither, either, or both of 'after' and 'before' may be specified.
3522 // If neither is specified, the new tablet can be added anywhere on the reel.
3523 // If one or the other is specified, the tablet will be added before or after
3524 // the specified tablet. If both are specified, the tablet will be added to the
3525 // resulting location, assuming it is valid (after->next == before->prev); if
3526 // it is not valid, or there is any other error, NULL will be returned.
3527 API ALLOC struct nctablet* ncreel_add(struct ncreel* nr, struct nctablet* after,
3528 struct nctablet* before, tabletcb cb,
3529 void* opaque)
3530 __attribute__ ((nonnull (1)));
3531
3532 // Return the number of nctablets in the ncreel 'nr'.
3533 API int ncreel_tabletcount(const struct ncreel* nr)
3534 __attribute__ ((nonnull (1)));
3535
3536 // Delete the tablet specified by t from the ncreel 'nr'. Returns -1 if the
3537 // tablet cannot be found.
3538 API int ncreel_del(struct ncreel* nr, struct nctablet* t)
3539 __attribute__ ((nonnull (1)));
3540
3541 // Redraw the ncreel 'nr' in its entirety. The reel will be cleared, and
3542 // tablets will be lain out, using the focused tablet as a fulcrum. Tablet
3543 // drawing callbacks will be invoked for each visible tablet.
3544 API int ncreel_redraw(struct ncreel* nr)
3545 __attribute__ ((nonnull (1)));
3546
3547 // Offer input 'ni' to the ncreel 'nr'. If it's relevant, this function returns
3548 // true, and the input ought not be processed further. If it's irrelevant to
3549 // the reel, false is returned. Relevant inputs include:
3550 // * a mouse click on a tablet (focuses tablet)
3551 // * a mouse scrollwheel event (rolls reel)
3552 // * up, down, pgup, or pgdown (navigates among items)
3553 API bool ncreel_offer_input(struct ncreel* nr, const ncinput* ni)
3554 __attribute__ ((nonnull (1, 2)));
3555
3556 // Return the focused tablet, if any tablets are present. This is not a copy;
3557 // be careful to use it only for the duration of a critical section.
3558 API struct nctablet* ncreel_focused(struct ncreel* nr)
3559 __attribute__ ((nonnull (1)));
3560
3561 // Change focus to the next tablet, if one exists
3562 API struct nctablet* ncreel_next(struct ncreel* nr)
3563 __attribute__ ((nonnull (1)));
3564
3565 // Change focus to the previous tablet, if one exists
3566 API struct nctablet* ncreel_prev(struct ncreel* nr)
3567 __attribute__ ((nonnull (1)));
3568
3569 // Destroy an ncreel allocated with ncreel_create().
3570 API void ncreel_destroy(struct ncreel* nr);
3571
3572 // Returns a pointer to a user pointer associated with this nctablet.
3573 API void* nctablet_userptr(struct nctablet* t);
3574
3575 // Access the ncplane associated with nctablet 't', if one exists.
3576 API struct ncplane* nctablet_plane(struct nctablet* t);
3577
3578 // Takes an arbitrarily large number, and prints it into a fixed-size buffer by
3579 // adding the necessary SI suffix. Usually, pass a |NC[IB]?PREFIXSTRLEN+1|-sized
3580 // buffer to generate up to |NC[IB]?PREFIXCOLUMNS| columns' worth of EGCs. The
3581 // characteristic can occupy up through |mult-1| characters (3 for 1000, 4 for
3582 // 1024). The mantissa can occupy either zero or two characters.
3583
3584 // snprintf(3) is used internally, with 's' as its size bound. If the output
3585 // requires more size than is available, NULL will be returned.
3586 //
3587 // Floating-point is never used, because an IEEE758 double can only losslessly
3588 // represent integers through 2^53-1.
3589 //
3590 // 2^64-1 is 18446744073709551615, 18.45E(xa). KMGTPEZY thus suffice to handle
3591 // an 89-bit uintmax_t. Beyond Z(etta) and Y(otta) lie lands unspecified by SI.
3592 // 2^-63 is 0.000000000000000000108, 1.08a(tto).
3593 // val: value to print
3594 // s: maximum output size; see snprintf(3)
3595 // decimal: scaling. '1' if none has taken place.
3596 // buf: buffer in which string will be generated
3597 // omitdec: inhibit printing of all-0 decimal portions
3598 // mult: base of suffix system (almost always 1000 or 1024)
3599 // uprefix: character to print following suffix ('i' for kibibytes basically).
3600 // only printed if suffix is actually printed (input >= mult).
3601 //
3602 // You are encouraged to consult notcurses_metric(3).
3603 API const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal,
3604 char* buf, int omitdec, uintmax_t mult,
3605 int uprefix)
3606 __attribute__ ((nonnull (4)));
3607
3608 // The number of columns is one fewer, as the STRLEN expressions must leave
3609 // an extra byte open in case 'µ' (U+00B5, 0xC2 0xB5) shows up. NCPREFIXCOLUMNS
3610 // is the maximum number of columns used by a mult == 1000 (standard)
3611 // ncnmetric() call. NCIPREFIXCOLUMNS is the maximum number of columns used by a
3612 // mult == 1024 (digital information) ncnmetric(). NCBPREFIXSTRLEN is the maximum
3613 // number of columns used by a mult == 1024 call making use of the 'i' suffix.
3614 // This is the true number of columns; to set up a printf()-style maximum
3615 // field width, you should use NC[IB]PREFIXFMT (see below).
3616 #define NCPREFIXCOLUMNS 7
3617 #define NCIPREFIXCOLUMNS 8
3618 #define NCBPREFIXCOLUMNS 9
3619 #define NCPREFIXSTRLEN (NCPREFIXCOLUMNS + 1) // Does not include a '\0' (xxx.xxU)
3620 #define NCIPREFIXSTRLEN (NCIPREFIXCOLUMNS + 1) // Does not include a '\0' (xxxx.xxU)
3621 #define NCBPREFIXSTRLEN (NCBPREFIXCOLUMNS + 1) // Does not include a '\0' (xxxx.xxUi), i == prefix
3622 // Used as arguments to a variable field width (i.e. "%*s" -- these are the *).
3623 // We need this convoluted grotesquery to properly handle 'µ'.
3624 #define NCMETRICFWIDTH(x, cols) \
3625 ((int)(strlen(x) - ncstrwidth(x, NULL, NULL) + (cols)))
3626 #define NCPREFIXFMT(x) NCMETRICFWIDTH((x), NCPREFIXCOLUMNS), (x)
3627 #define NCIPREFIXFMT(x) NCMETRIXFWIDTH((x), NCIPREFIXCOLUMNS), (x)
3628 #define NCBPREFIXFMT(x) NCMETRICFWIDTH((x), NCBPREFIXCOLUMNS), (x)
3629
3630 // Mega, kilo, gigafoo. Use PREFIXSTRLEN + 1 and PREFIXCOLUMNS.
3631 static inline const char*
ncqprefix(uintmax_t val,uintmax_t decimal,char * buf,int omitdec)3632 ncqprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
3633 return ncnmetric(val, NCPREFIXSTRLEN + 1, decimal, buf, omitdec, 1000, '\0');
3634 }
3635
3636 // Mibi, kebi, gibibytes sans 'i' suffix. Use IPREFIXSTRLEN + 1.
3637 static inline const char*
nciprefix(uintmax_t val,uintmax_t decimal,char * buf,int omitdec)3638 nciprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
3639 return ncnmetric(val, NCIPREFIXSTRLEN + 1, decimal, buf, omitdec, 1024, '\0');
3640 }
3641
3642 // Mibi, kebi, gibibytes. Use BPREFIXSTRLEN + 1 and BPREFIXCOLUMNS.
3643 static inline const char*
ncbprefix(uintmax_t val,uintmax_t decimal,char * buf,int omitdec)3644 ncbprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
3645 return ncnmetric(val, NCBPREFIXSTRLEN + 1, decimal, buf, omitdec, 1024, 'i');
3646 }
3647
3648 // Get the default foreground color, if it is known. Returns -1 on error
3649 // (unknown foreground). On success, returns 0, writing the RGB value to
3650 // 'fg' (if non-NULL)
3651 API int notcurses_default_foreground(const struct notcurses* nc, uint32_t* fg)
3652 __attribute__ ((nonnull (1)));
3653
3654 // Get the default background color, if it is known. Returns -1 on error
3655 // (unknown background). On success, returns 0, writing the RGB value to
3656 // 'bg' (if non-NULL) and setting 'bgtrans' high iff the background color
3657 // is treated as transparent.
3658 API int notcurses_default_background(const struct notcurses* nc, uint32_t* bg)
3659 __attribute__ ((nonnull (1)));
3660
3661 // Enable or disable the terminal's cursor, if supported, placing it at
3662 // 'y', 'x'. Immediate effect (no need for a call to notcurses_render()).
3663 // It is an error if 'y', 'x' lies outside the standard plane. Can be
3664 // called while already visible to move the cursor.
3665 API int notcurses_cursor_enable(struct notcurses* nc, int y, int x)
3666 __attribute__ ((nonnull (1)));
3667
3668 // Disable the hardware cursor. It is an error to call this while the
3669 // cursor is already disabled.
3670 API int notcurses_cursor_disable(struct notcurses* nc)
3671 __attribute__ ((nonnull (1)));
3672
3673 // Get the current location of the terminal's cursor, whether visible or not.
3674 API int notcurses_cursor_yx(const struct notcurses* nc, int* y, int* x)
3675 __attribute__ ((nonnull (1)));
3676
3677 // Convert the plane's content to greyscale.
3678 API void ncplane_greyscale(struct ncplane* n)
3679 __attribute__ ((nonnull (1)));
3680
3681 // ╭──────────────────────────╮
3682 // │This is the primary header│
3683 // ╭──────────────────────this is the secondary header──────╮
3684 // │ ↑ │
3685 // │ option1 Long text #1 │
3686 // │ option2 Long text #2 │
3687 // │ option3 Long text #3 │
3688 // │ option4 Long text #4 │
3689 // │ option5 Long text #5 │
3690 // │ option6 Long text #6 │
3691 // │ ↓ │
3692 // ╰────────────────────────────────────here's the footer───╯
3693
3694 // selection widget -- an ncplane with a title header and a body section. the
3695 // body section supports infinite scrolling up and down.
3696 //
3697 // At all times, exactly one item is selected.
3698 struct ncselector_item {
3699 const char* option;
3700 const char* desc;
3701 };
3702
3703 typedef struct ncselector_options {
3704 const char* title; // title may be NULL, inhibiting riser, saving two rows.
3705 const char* secondary; // secondary may be NULL
3706 const char* footer; // footer may be NULL
3707 const struct ncselector_item* items; // initial items and descriptions
3708 // default item (selected at start), must be < itemcount unless itemcount is
3709 // 0, in which case 'defidx' must also be 0
3710 unsigned defidx;
3711 // maximum number of options to display at once, 0 to use all available space
3712 unsigned maxdisplay;
3713 // exhaustive styling options
3714 uint64_t opchannels; // option channels
3715 uint64_t descchannels; // description channels
3716 uint64_t titlechannels;// title channels
3717 uint64_t footchannels; // secondary and footer channels
3718 uint64_t boxchannels; // border channels
3719 uint64_t flags; // bitfield of NCSELECTOR_OPTION_*
3720 } ncselector_options;
3721
3722 API ALLOC struct ncselector* ncselector_create(struct ncplane* n, const ncselector_options* opts)
3723 __attribute__ ((nonnull (1)));
3724
3725 // Dynamically add or delete items. It is usually sufficient to supply a static
3726 // list of items via ncselector_options->items.
3727 API int ncselector_additem(struct ncselector* n, const struct ncselector_item* item);
3728 API int ncselector_delitem(struct ncselector* n, const char* item);
3729
3730 // Return reference to the selected option, or NULL if there are no items.
3731 API const char* ncselector_selected(const struct ncselector* n)
3732 __attribute__ ((nonnull (1)));
3733
3734 // Return a reference to the ncselector's underlying ncplane.
3735 API struct ncplane* ncselector_plane(struct ncselector* n)
3736 __attribute__ ((nonnull (1)));
3737
3738 // Move up or down in the list. A reference to the newly-selected item is
3739 // returned, or NULL if there are no items in the list.
3740 API const char* ncselector_previtem(struct ncselector* n)
3741 __attribute__ ((nonnull (1)));
3742 API const char* ncselector_nextitem(struct ncselector* n)
3743 __attribute__ ((nonnull (1)));
3744
3745 // Offer the input to the ncselector. If it's relevant, this function returns
3746 // true, and the input ought not be processed further. If it's irrelevant to
3747 // the selector, false is returned. Relevant inputs include:
3748 // * a mouse click on an item
3749 // * a mouse scrollwheel event
3750 // * a mouse click on the scrolling arrows
3751 // * up, down, pgup, or pgdown on an unrolled menu (navigates among items)
3752 API bool ncselector_offer_input(struct ncselector* n, const ncinput* nc)
3753 __attribute__ ((nonnull (1, 2)));
3754
3755 // Destroy the ncselector.
3756 API void ncselector_destroy(struct ncselector* n, char** item);
3757
3758 struct ncmselector_item {
3759 const char* option;
3760 const char* desc;
3761 bool selected;
3762 };
3763
3764 // ╭───────────────────╮
3765 // │ short round title │
3766 //╭now this secondary is also very, very, very outlandishly long, you see┤
3767 //│ ↑ │
3768 //│ ☐ Pa231 Protactinium-231 (162kg) │
3769 //│ ☐ U233 Uranium-233 (15kg) │
3770 //│ ☐ U235 Uranium-235 (50kg) │
3771 //│ ☐ Np236 Neptunium-236 (7kg) │
3772 //│ ☐ Np237 Neptunium-237 (60kg) │
3773 //│ ☐ Pu238 Plutonium-238 (10kg) │
3774 //│ ☐ Pu239 Plutonium-239 (10kg) │
3775 //│ ☐ Pu240 Plutonium-240 (40kg) │
3776 //│ ☐ Pu241 Plutonium-241 (13kg) │
3777 //│ ☐ Am241 Americium-241 (100kg) │
3778 //│ ↓ │
3779 //╰────────────────────────press q to exit (there is sartrev("no exit"))─╯
3780
3781 // multiselection widget -- a selector supporting multiple selections.
3782 //
3783 // Unlike the selector widget, zero to all of the items can be selected, but
3784 // also the widget does not support adding or removing items at runtime.
3785 typedef struct ncmultiselector_options {
3786 const char* title; // title may be NULL, inhibiting riser, saving two rows.
3787 const char* secondary; // secondary may be NULL
3788 const char* footer; // footer may be NULL
3789 const struct ncmselector_item* items; // initial items, descriptions, and statuses
3790 // maximum number of options to display at once, 0 to use all available space
3791 unsigned maxdisplay;
3792 // exhaustive styling options
3793 uint64_t opchannels; // option channels
3794 uint64_t descchannels; // description channels
3795 uint64_t titlechannels;// title channels
3796 uint64_t footchannels; // secondary and footer channels
3797 uint64_t boxchannels; // border channels
3798 uint64_t flags; // bitfield of NCMULTISELECTOR_OPTION_*
3799 } ncmultiselector_options;
3800
3801 API ALLOC struct ncmultiselector* ncmultiselector_create(struct ncplane* n, const ncmultiselector_options* opts)
3802 __attribute__ ((nonnull (1)));
3803
3804 // Return selected vector. An array of bools must be provided, along with its
3805 // length. If that length doesn't match the itemcount, it is an error.
3806 API int ncmultiselector_selected(struct ncmultiselector* n, bool* selected, unsigned count);
3807
3808 // Return a reference to the ncmultiselector's underlying ncplane.
3809 API struct ncplane* ncmultiselector_plane(struct ncmultiselector* n);
3810
3811 // Offer the input to the ncmultiselector. If it's relevant, this function
3812 // returns true, and the input ought not be processed further. If it's
3813 // irrelevant to the multiselector, false is returned. Relevant inputs include:
3814 // * a mouse click on an item
3815 // * a mouse scrollwheel event
3816 // * a mouse click on the scrolling arrows
3817 // * up, down, pgup, or pgdown on an unrolled menu (navigates among items)
3818 API bool ncmultiselector_offer_input(struct ncmultiselector* n, const ncinput* nc)
3819 __attribute__ ((nonnull (1, 2)));
3820
3821 // Destroy the ncmultiselector.
3822 API void ncmultiselector_destroy(struct ncmultiselector* n);
3823
3824 // nctree widget -- a vertical browser supporting line-based hierarchies.
3825 //
3826 // each item can have subitems, and has a curry. there is one callback for the
3827 // entirety of the nctree. visible items have the callback invoked upon their
3828 // curry and an ncplane. the ncplane can be reused across multiple invocations
3829 // of the callback.
3830
3831 // each item has a curry, and zero or more subitems.
3832 struct nctree_item {
3833 void* curry;
3834 struct nctree_item* subs;
3835 unsigned subcount;
3836 };
3837
3838 typedef struct nctree_options {
3839 const struct nctree_item* items; // top-level nctree_item array
3840 unsigned count; // size of |items|
3841 int (*nctreecb)(struct ncplane*, void*, int); // item callback function
3842 int indentcols; // columns to indent per level of hierarchy
3843 uint64_t flags; // bitfield of NCTREE_OPTION_*
3844 } nctree_options;
3845
3846 // |opts| may *not* be NULL, since it is necessary to define a callback
3847 // function.
3848 API ALLOC struct nctree* nctree_create(struct ncplane* n, const nctree_options* opts)
3849 __attribute__ ((nonnull (1, 2)));
3850
3851 // Returns the ncplane on which this nctree lives.
3852 API struct ncplane* nctree_plane(struct nctree* n)
3853 __attribute__ ((nonnull (1)));
3854
3855 // Redraw the nctree 'n' in its entirety. The tree will be cleared, and items
3856 // will be lain out, using the focused item as a fulcrum. Item-drawing
3857 // callbacks will be invoked for each visible item.
3858 API int nctree_redraw(struct nctree* n)
3859 __attribute__ ((nonnull (1)));
3860
3861 // Offer input 'ni' to the nctree 'n'. If it's relevant, this function returns
3862 // true, and the input ought not be processed further. If it's irrelevant to
3863 // the tree, false is returned. Relevant inputs include:
3864 // * a mouse click on an item (focuses item)
3865 // * a mouse scrollwheel event (srolls tree)
3866 // * up, down, pgup, or pgdown (navigates among items)
3867 API bool nctree_offer_input(struct nctree* n, const ncinput* ni)
3868 __attribute__ ((nonnull (1, 2)));
3869
3870 // Return the focused item, if any items are present. This is not a copy;
3871 // be careful to use it only for the duration of a critical section.
3872 API void* nctree_focused(struct nctree* n) __attribute__ ((nonnull (1)));
3873
3874 // Change focus to the next item.
3875 API void* nctree_next(struct nctree* n) __attribute__ ((nonnull (1)));
3876
3877 // Change focus to the previous item.
3878 API void* nctree_prev(struct nctree* n) __attribute__ ((nonnull (1)));
3879
3880 // Go to the item specified by the array |spec| (a spec is a series of unsigned
3881 // values, each identifying a subelement in the hierarchy thus far, terminated
3882 // by UINT_MAX). If the spec is invalid, NULL is returned, and the depth of the
3883 // first invalid spec is written to *|failspec|. Otherwise, the true depth is
3884 // written to *|failspec|, and the curry is returned (|failspec| is necessary
3885 // because the curry could itself be NULL).
3886 API void* nctree_goto(struct nctree* n, const unsigned* spec, int* failspec);
3887
3888 // Insert |add| into the nctree |n| at |spec|. The path up to the last element
3889 // must already exist. If an item already exists at the path, it will be moved
3890 // to make room for |add|.
3891 API int nctree_add(struct nctree* n, const unsigned* spec, const struct nctree_item* add)
3892 __attribute__ ((nonnull (1, 2, 3)));
3893
3894 // Delete the item at |spec|, including any subitems.
3895 API int nctree_del(struct nctree* n, const unsigned* spec)
3896 __attribute__ ((nonnull (1, 2)));
3897
3898 // Destroy the nctree.
3899 API void nctree_destroy(struct nctree* n);
3900
3901 // Menus. Horizontal menu bars are supported, on the top and/or bottom rows.
3902 // If the menu bar is longer than the screen, it will be only partially
3903 // visible. Menus may be either visible or invisible by default. In the event of
3904 // a plane resize, menus will be automatically moved/resized. Elements can be
3905 // dynamically enabled or disabled at all levels (menu, section, and item),
3906 struct ncmenu_item {
3907 const char* desc; // utf-8 menu item, NULL for horizontal separator
3908 ncinput shortcut; // shortcut, all should be distinct
3909 };
3910
3911 struct ncmenu_section {
3912 const char* name; // utf-8 c string
3913 int itemcount;
3914 struct ncmenu_item* items;
3915 ncinput shortcut; // shortcut, will be underlined if present in name
3916 };
3917
3918 #define NCMENU_OPTION_BOTTOM 0x0001ull // bottom row (as opposed to top row)
3919 #define NCMENU_OPTION_HIDING 0x0002ull // hide the menu when not unrolled
3920
3921 typedef struct ncmenu_options {
3922 struct ncmenu_section* sections; // array of 'sectioncount' menu_sections
3923 int sectioncount; // must be positive
3924 uint64_t headerchannels; // styling for header
3925 uint64_t sectionchannels; // styling for sections
3926 uint64_t flags; // flag word of NCMENU_OPTION_*
3927 } ncmenu_options;
3928
3929 // Create a menu with the specified options, bound to the specified plane.
3930 API ALLOC struct ncmenu* ncmenu_create(struct ncplane* n, const ncmenu_options* opts)
3931 __attribute__ ((nonnull (1)));
3932
3933 // Unroll the specified menu section, making the menu visible if it was
3934 // invisible, and rolling up any menu section that is already unrolled.
3935 API int ncmenu_unroll(struct ncmenu* n, int sectionidx);
3936
3937 // Roll up any unrolled menu section, and hide the menu if using hiding.
3938 API int ncmenu_rollup(struct ncmenu* n) __attribute__ ((nonnull (1)));
3939
3940 // Unroll the previous/next section (relative to current unrolled). If no
3941 // section is unrolled, the first section will be unrolled.
3942 API int ncmenu_nextsection(struct ncmenu* n) __attribute__ ((nonnull (1)));
3943 API int ncmenu_prevsection(struct ncmenu* n) __attribute__ ((nonnull (1)));
3944
3945 // Move to the previous/next item within the currently unrolled section. If no
3946 // section is unrolled, the first section will be unrolled.
3947 API int ncmenu_nextitem(struct ncmenu* n) __attribute__ ((nonnull (1)));
3948 API int ncmenu_previtem(struct ncmenu* n) __attribute__ ((nonnull (1)));
3949
3950 // Disable or enable a menu item. Returns 0 if the item was found.
3951 API int ncmenu_item_set_status(struct ncmenu* n, const char* section,
3952 const char* item, bool enabled);
3953
3954 // Return the selected item description, or NULL if no section is unrolled. If
3955 // 'ni' is not NULL, and the selected item has a shortcut, 'ni' will be filled
3956 // in with that shortcut--this can allow faster matching.
3957 API const char* ncmenu_selected(const struct ncmenu* n, ncinput* ni);
3958
3959 // Return the item description corresponding to the mouse click 'click'. The
3960 // item must be on an actively unrolled section, and the click must be in the
3961 // area of a valid item. If 'ni' is not NULL, and the selected item has a
3962 // shortcut, 'ni' will be filled in with the shortcut.
3963 API const char* ncmenu_mouse_selected(const struct ncmenu* n,
3964 const ncinput* click, ncinput* ni);
3965
3966 // Return the ncplane backing this ncmenu.
3967 API struct ncplane* ncmenu_plane(struct ncmenu* n);
3968
3969 // Offer the input to the ncmenu. If it's relevant, this function returns true,
3970 // and the input ought not be processed further. If it's irrelevant to the
3971 // menu, false is returned. Relevant inputs include:
3972 // * mouse movement over a hidden menu
3973 // * a mouse click on a menu section (the section is unrolled)
3974 // * a mouse click outside of an unrolled menu (the menu is rolled up)
3975 // * left or right on an unrolled menu (navigates among sections)
3976 // * up or down on an unrolled menu (navigates among items)
3977 // * escape on an unrolled menu (the menu is rolled up)
3978 API bool ncmenu_offer_input(struct ncmenu* n, const ncinput* nc)
3979 __attribute__ ((nonnull (1, 2)));
3980
3981 // Destroy a menu created with ncmenu_create().
3982 API void ncmenu_destroy(struct ncmenu* n);
3983
3984 // Progress bars. They proceed linearly in any of four directions. The entirety
3985 // of the plane will be used -- any border should be provided by the caller on
3986 // another plane. The plane will not be erased; text preloaded into the plane
3987 // will be consumed by the progress indicator. The bar is redrawn for each
3988 // provided progress report (a double between 0 and 1), and can regress with
3989 // lower values. The procession will take place along the longer dimension (at
3990 // the time of each redraw), with the horizontal length scaled by 2 for
3991 // purposes of comparison. I.e. for a plane of 20 rows and 50 columns, the
3992 // progress will be to the right (50 > 40) or left with OPTION_RETROGRADE.
3993
3994 #define NCPROGBAR_OPTION_RETROGRADE 0x0001u // proceed left/down
3995
3996 typedef struct ncprogbar_options {
3997 uint32_t ulchannel; // upper-left channel. in the context of a progress bar,
3998 uint32_t urchannel; // "up" is the direction we are progressing towards, and
3999 uint32_t blchannel; // "bottom" is the direction of origin. for monochromatic
4000 uint32_t brchannel; // bar, all four channels ought be the same.
4001 uint64_t flags;
4002 } ncprogbar_options;
4003
4004 // Takes ownership of the ncplane 'n', which will be destroyed by
4005 // ncprogbar_destroy(). The progress bar is initially at 0%.
4006 API ALLOC struct ncprogbar* ncprogbar_create(struct ncplane* n, const ncprogbar_options* opts)
4007 __attribute__ ((nonnull (1)));
4008
4009 // Return a reference to the ncprogbar's underlying ncplane.
4010 API struct ncplane* ncprogbar_plane(struct ncprogbar* n)
4011 __attribute__ ((nonnull (1)));
4012
4013 // Set the progress bar's completion, a double 0 <= 'p' <= 1.
4014 API int ncprogbar_set_progress(struct ncprogbar* n, double p)
4015 __attribute__ ((nonnull (1)));
4016
4017 // Get the progress bar's completion, a double on [0, 1].
4018 API double ncprogbar_progress(const struct ncprogbar* n)
4019 __attribute__ ((nonnull (1)));
4020
4021 // Destroy the progress bar and its underlying ncplane.
4022 API void ncprogbar_destroy(struct ncprogbar* n);
4023
4024 // Tabbed widgets. The tab list is displayed at the top or at the bottom of the
4025 // plane, and only one tab is visible at a time.
4026
4027 // Display the tab list at the bottom instead of at the top of the plane
4028 #define NCTABBED_OPTION_BOTTOM 0x0001ull
4029
4030 typedef struct nctabbed_options {
4031 uint64_t selchan; // channel for the selected tab header
4032 uint64_t hdrchan; // channel for unselected tab headers
4033 uint64_t sepchan; // channel for the tab separator
4034 const char* separator; // separator string (copied by nctabbed_create())
4035 uint64_t flags; // bitmask of NCTABBED_OPTION_*
4036 } nctabbed_options;
4037
4038 // Tab content drawing callback. Takes the tab it was associated to, the ncplane
4039 // on which tab content is to be drawn, and the user pointer of the tab.
4040 // It is called during nctabbed_redraw().
4041 typedef void (*tabcb)(struct nctab* t, struct ncplane* ncp, void* curry);
4042
4043 // Creates a new nctabbed widget, associated with the given ncplane 'n', and with
4044 // additional options given in 'opts'. When 'opts' is NULL, it acts as if it were
4045 // called with an all-zero opts. The widget takes ownership of 'n', and destroys
4046 // it when the widget is destroyed. Returns the newly created widget. Returns
4047 // NULL on failure, also destroying 'n'.
4048 API ALLOC struct nctabbed* nctabbed_create(struct ncplane* n, const nctabbed_options* opts)
4049 __attribute ((nonnull (1)));
4050
4051 // Destroy an nctabbed widget. All memory belonging to 'nt' is deallocated,
4052 // including all tabs and their names. The plane associated with 'nt' is also
4053 // destroyed. Calling this with NULL does nothing.
4054 API void nctabbed_destroy(struct nctabbed* nt);
4055
4056 // Redraw the widget. This calls the tab callback of the currently selected tab
4057 // to draw tab contents, and draws tab headers. The tab content plane is not
4058 // modified by this function, apart from resizing the plane is necessary.
4059 API void nctabbed_redraw(struct nctabbed* nt)
4060 __attribute__ ((nonnull (1)));
4061
4062 // Make sure the tab header of the currently selected tab is at least partially
4063 // visible. (by rotating tabs until at least one column is displayed)
4064 // Does nothing if there are no tabs.
4065 API void nctabbed_ensure_selected_header_visible(struct nctabbed* nt)
4066 __attribute__ ((nonnull (1)));
4067
4068 // Returns the currently selected tab, or NULL if there are no tabs.
4069 API struct nctab* nctabbed_selected(struct nctabbed* nt)
4070 __attribute__ ((nonnull (1)));
4071
4072 // Returns the leftmost tab, or NULL if there are no tabs.
4073 API struct nctab* nctabbed_leftmost(struct nctabbed* nt)
4074 __attribute__ ((nonnull (1)));
4075
4076 // Returns the number of tabs in the widget.
4077 API int nctabbed_tabcount(struct nctabbed* nt)
4078 __attribute__ ((nonnull (1)));
4079
4080 // Returns the plane associated to 'nt'.
4081 API struct ncplane* nctabbed_plane(struct nctabbed* nt)
4082 __attribute__ ((nonnull (1)));
4083
4084 // Returns the tab content plane.
4085 API struct ncplane* nctabbed_content_plane(struct nctabbed* nt)
4086 __attribute__ ((nonnull (1)));
4087
4088 // Returns the tab callback.
4089 API tabcb nctab_cb(struct nctab* t)
4090 __attribute__ ((nonnull (1)));
4091
4092 // Returns the tab name. This is not a copy and it should not be stored.
4093 API const char* nctab_name(struct nctab* t)
4094 __attribute__ ((nonnull (1)));
4095
4096 // Returns the width (in columns) of the tab's name.
4097 API int nctab_name_width(struct nctab* t)
4098 __attribute__ ((nonnull (1)));
4099
4100 // Returns the tab's user pointer.
4101 API void* nctab_userptr(struct nctab* t)
4102 __attribute__ ((nonnull (1)));
4103
4104 // Returns the tab to the right of 't'. This does not change which tab is selected.
4105 API struct nctab* nctab_next(struct nctab* t)
4106 __attribute__ ((nonnull (1)));
4107
4108 // Returns the tab to the left of 't'. This does not change which tab is selected.
4109 API struct nctab* nctab_prev(struct nctab* t)
4110 __attribute__ ((nonnull (1)));
4111
4112 // Add a new tab to 'nt' with the given tab callback, name, and user pointer.
4113 // If both 'before' and 'after' are NULL, the tab is inserted after the selected
4114 // tab. Otherwise, it gets put after 'after' (if not NULL) and before 'before'
4115 // (if not NULL). If both 'after' and 'before' are given, they must be two
4116 // neighboring tabs (the tab list is circular, so the last tab is immediately
4117 // before the leftmost tab), otherwise the function returns NULL. If 'name' is
4118 // NULL or a string containing illegal characters, the function returns NULL.
4119 // On all other failures the function also returns NULL. If it returns NULL,
4120 // none of the arguments are modified, and the widget state is not altered.
4121 API ALLOC struct nctab* nctabbed_add(struct nctabbed* nt, struct nctab* after,
4122 struct nctab* before, tabcb tcb,
4123 const char* name, void* opaque)
4124 __attribute__ ((nonnull (1, 5)));
4125
4126 // Remove a tab 't' from 'nt'. Its neighboring tabs become neighbors to each
4127 // other. If 't' if the selected tab, the tab after 't' becomes selected.
4128 // Likewise if 't' is the leftmost tab, the tab after 't' becomes leftmost.
4129 // If 't' is the only tab, there will no more be a selected or leftmost tab,
4130 // until a new tab is added. Returns -1 if 't' is NULL, and 0 otherwise.
4131 API int nctabbed_del(struct nctabbed* nt, struct nctab* t)
4132 __attribute__ ((nonnull (1)));
4133
4134 // Move 't' after 'after' (if not NULL) and before 'before' (if not NULL).
4135 // If both 'after' and 'before' are NULL, the function returns -1, otherwise
4136 // it returns 0.
4137 API int nctab_move(struct nctabbed* nt, struct nctab* t, struct nctab* after,
4138 struct nctab* before)
4139 __attribute__ ((nonnull (1, 2)));
4140
4141 // Move 't' to the right by one tab, looping around to become leftmost if needed.
4142 API void nctab_move_right(struct nctabbed* nt, struct nctab* t)
4143 __attribute__ ((nonnull (1, 2)));
4144
4145 // Move 't' to the right by one tab, looping around to become the last tab if needed.
4146 API void nctab_move_left(struct nctabbed* nt, struct nctab* t)
4147 __attribute__ ((nonnull (1, 2)));
4148
4149 // Rotate the tabs of 'nt' right by 'amt' tabs, or '-amt' tabs left if 'amt' is
4150 // negative. Tabs are rotated only by changing the leftmost tab; the selected tab
4151 // stays the same. If there are no tabs, nothing happens.
4152 API void nctabbed_rotate(struct nctabbed* nt, int amt)
4153 __attribute__ ((nonnull (1)));
4154
4155 // Select the tab after the currently selected tab, and return the newly selected
4156 // tab. Returns NULL if there are no tabs.
4157 API struct nctab* nctabbed_next(struct nctabbed* nt)
4158 __attribute__ ((nonnull (1)));
4159
4160 // Select the tab before the currently selected tab, and return the newly selected
4161 // tab. Returns NULL if there are no tabs.
4162 API struct nctab* nctabbed_prev(struct nctabbed* nt)
4163 __attribute__ ((nonnull (1)));
4164
4165 // Change the selected tab to be 't'. Returns the previously selected tab.
4166 API struct nctab* nctabbed_select(struct nctabbed* nt, struct nctab* t)
4167 __attribute__ ((nonnull (1, 2)));
4168
4169 // Write the channels for tab headers, the selected tab header, and the separator
4170 // to '*hdrchan', '*selchan', and '*sepchan' respectively.
4171 API void nctabbed_channels(struct nctabbed* nt, uint64_t* RESTRICT hdrchan,
4172 uint64_t* RESTRICT selchan, uint64_t* RESTRICT sepchan)
4173 __attribute__ ((nonnull (1)));
4174
4175 static inline uint64_t
nctabbed_hdrchan(struct nctabbed * nt)4176 nctabbed_hdrchan(struct nctabbed* nt){
4177 uint64_t ch;
4178 nctabbed_channels(nt, &ch, NULL, NULL);
4179 return ch;
4180 }
4181
4182 static inline uint64_t
nctabbed_selchan(struct nctabbed * nt)4183 nctabbed_selchan(struct nctabbed* nt){
4184 uint64_t ch;
4185 nctabbed_channels(nt, NULL, &ch, NULL);
4186 return ch;
4187 }
4188
4189 static inline uint64_t
nctabbed_sepchan(struct nctabbed * nt)4190 nctabbed_sepchan(struct nctabbed* nt){
4191 uint64_t ch;
4192 nctabbed_channels(nt, NULL, NULL, &ch);
4193 return ch;
4194 }
4195
4196 // Returns the tab separator. This is not a copy and it should not be stored.
4197 // This can be NULL, if the separator was set to NULL in ncatbbed_create() or
4198 // nctabbed_set_separator().
4199 API const char* nctabbed_separator(struct nctabbed* nt)
4200 __attribute__ ((nonnull (1)));
4201
4202 // Returns the tab separator width, or zero if there is no separator.
4203 API int nctabbed_separator_width(struct nctabbed* nt)
4204 __attribute__ ((nonnull (1)));
4205
4206 // Set the tab headers channel for 'nt'.
4207 API void nctabbed_set_hdrchan(struct nctabbed* nt, uint64_t chan)
4208 __attribute__ ((nonnull (1)));
4209
4210 // Set the selected tab header channel for 'nt'.
4211 API void nctabbed_set_selchan(struct nctabbed* nt, uint64_t chan)
4212 __attribute__ ((nonnull (1)));
4213
4214 // Set the tab separator channel for 'nt'.
4215 API void nctabbed_set_sepchan(struct nctabbed* nt, uint64_t chan)
4216 __attribute__ ((nonnull (1)));
4217
4218 // Set the tab callback function for 't'. Returns the previous tab callback.
4219 API tabcb nctab_set_cb(struct nctab* t, tabcb newcb)
4220 __attribute__ ((nonnull (1)));
4221
4222 // Change the name of 't'. Returns -1 if 'newname' is NULL, and 0 otherwise.
4223 API int nctab_set_name(struct nctab* t, const char* newname)
4224 __attribute__ ((nonnull (1, 2)));
4225
4226 // Set the user pointer of 't'. Returns the previous user pointer.
4227 API void* nctab_set_userptr(struct nctab* t, void* newopaque)
4228 __attribute__ ((nonnull (1)));
4229
4230 // Change the tab separator for 'nt'. Returns -1 if 'separator' is not NULL and
4231 // is not a valid string, and 0 otherwise.
4232 API int nctabbed_set_separator(struct nctabbed* nt, const char* separator)
4233 __attribute__ ((nonnull (1, 2)));
4234
4235 // Plots. Given a rectilinear area, an ncplot can graph samples along some axis.
4236 // There is some underlying independent variable--this could be e.g. measurement
4237 // sequence number, or measurement time. Samples are tagged with this variable, which
4238 // should never fall, but may grow non-monotonically. The desired range in terms
4239 // of the underlying independent variable is provided at creation time. The
4240 // desired domain can be specified, or can be autosolved. Granularity of the
4241 // dependent variable depends on glyph selection.
4242 //
4243 // For instance, perhaps we're sampling load as a time series. We want to
4244 // display an hour's worth of samples in 40 columns and 5 rows. We define the
4245 // x-axis to be the independent variable, time. We'll stamp at second
4246 // granularity. In this case, there are 60 * 60 == 3600 total elements in the
4247 // range. Each column will thus cover a 90s span. Using vertical blocks (the
4248 // most granular glyph), we have 8 * 5 == 40 levels of domain. If we report the
4249 // following samples, starting at 0, using autosolving, we will observe:
4250 //
4251 // 60 -- 1% |domain: 1--1, 0: 20 levels
4252 // 120 -- 50% |domain: 1--50, 0: 0 levels, 1: 40 levels
4253 // 180 -- 50% |domain: 1--50, 0: 0 levels, 1: 40 levels, 2: 40 levels
4254 // 240 -- 100% |domain: 1--75, 0: 1, 1: 27, 2: 40
4255 // 271 -- 100% |domain: 1--100, 0: 0, 1: 20, 2: 30, 3: 40
4256 // 300 -- 25% |domain: 1--75, 0: 0, 1: 27, 2: 40, 3: 33
4257 //
4258 // At the end, we have data in 4 90s spans: [0--89], [90--179], [180--269], and
4259 // [270--359]. The first two spans have one sample each, while the second two
4260 // have two samples each. Samples within a span are averaged (FIXME we could
4261 // probably do better), so the results are 0, 50, 75, and 62.5. Scaling each of
4262 // these out of 90 and multiplying by 40 gets our resulting levels. The final
4263 // domain is 75 rather than 100 due to the averaging of 100+25/2->62.5 in the
4264 // third span, at which point the maximum span value is once again 75.
4265 //
4266 // The 20 levels at first is a special case. When the domain is only 1 unit,
4267 // and autoscaling is in play, assign 50%.
4268 //
4269 // This options structure works for both the ncuplot (uint64_t) and ncdplot
4270 // (double) types.
4271 #define NCPLOT_OPTION_LABELTICKSD 0x0001u // show labels for dependent axis
4272 #define NCPLOT_OPTION_EXPONENTIALD 0x0002u // exponential dependent axis
4273 #define NCPLOT_OPTION_VERTICALI 0x0004u // independent axis is vertical
4274 #define NCPLOT_OPTION_NODEGRADE 0x0008u // fail rather than degrade blitter
4275 #define NCPLOT_OPTION_DETECTMAXONLY 0x0010u // use domain detection only for max
4276 #define NCPLOT_OPTION_PRINTSAMPLE 0x0020u // print the most recent sample
4277
4278 typedef struct ncplot_options {
4279 // channels for the maximum and minimum levels. linear or exponential
4280 // interpolation will be applied across the domain between these two.
4281 uint64_t maxchannels;
4282 uint64_t minchannels;
4283 // styling used for the legend, if NCPLOT_OPTION_LABELTICKSD is set
4284 uint16_t legendstyle;
4285 // if you don't care, pass NCBLIT_DEFAULT and get NCBLIT_8x1 (assuming
4286 // UTF8) or NCBLIT_1x1 (in an ASCII environment)
4287 ncblitter_e gridtype; // number of "pixels" per row x column
4288 // independent variable can either be a contiguous range, or a finite set
4289 // of keys. for a time range, say the previous hour sampled with second
4290 // resolution, the independent variable would be the range [0..3600): 3600.
4291 // if rangex is 0, it is dynamically set to the number of columns.
4292 int rangex;
4293 const char* title; // optional, printed by the labels
4294 uint64_t flags; // bitfield over NCPLOT_OPTION_*
4295 } ncplot_options;
4296
4297 // Use the provided plane 'n' for plotting according to the options 'opts'. The
4298 // plot will make free use of the entirety of the plane. For domain
4299 // autodiscovery, set miny == maxy == 0. ncuplot holds uint64_ts, while
4300 // ncdplot holds doubles.
4301 API ALLOC struct ncuplot* ncuplot_create(struct ncplane* n, const ncplot_options* opts,
4302 uint64_t miny, uint64_t maxy)
4303 __attribute__ ((nonnull (1)));
4304
4305 API ALLOC struct ncdplot* ncdplot_create(struct ncplane* n, const ncplot_options* opts,
4306 double miny, double maxy)
4307 __attribute__ ((nonnull (1)));
4308
4309 // Return a reference to the ncplot's underlying ncplane.
4310 API struct ncplane* ncuplot_plane(struct ncuplot* n)
4311 __attribute__ ((nonnull (1)));
4312
4313 API struct ncplane* ncdplot_plane(struct ncdplot* n)
4314 __attribute__ ((nonnull (1)));
4315
4316 // Add to or set the value corresponding to this x. If x is beyond the current
4317 // x window, the x window is advanced to include x, and values passing beyond
4318 // the window are lost. The first call will place the initial window. The plot
4319 // will be redrawn, but notcurses_render() is not called.
4320 API int ncuplot_add_sample(struct ncuplot* n, uint64_t x, uint64_t y)
4321 __attribute__ ((nonnull (1)));
4322 API int ncdplot_add_sample(struct ncdplot* n, uint64_t x, double y)
4323 __attribute__ ((nonnull (1)));
4324 API int ncuplot_set_sample(struct ncuplot* n, uint64_t x, uint64_t y)
4325 __attribute__ ((nonnull (1)));
4326 API int ncdplot_set_sample(struct ncdplot* n, uint64_t x, double y)
4327 __attribute__ ((nonnull (1)));
4328
4329 API int ncuplot_sample(const struct ncuplot* n, uint64_t x, uint64_t* y)
4330 __attribute__ ((nonnull (1)));
4331 API int ncdplot_sample(const struct ncdplot* n, uint64_t x, double* y)
4332 __attribute__ ((nonnull (1)));
4333
4334 API void ncuplot_destroy(struct ncuplot* n);
4335 API void ncdplot_destroy(struct ncdplot* n);
4336
4337 typedef int(*ncfdplane_callback)(struct ncfdplane* n, const void* buf, size_t s, void* curry);
4338 typedef int(*ncfdplane_done_cb)(struct ncfdplane* n, int fderrno, void* curry);
4339
4340 // read from an fd until EOF (or beyond, if follow is set), invoking the user's
4341 // callback each time. runs in its own context. on EOF or error, the finalizer
4342 // callback will be invoked, and the user ought destroy the ncfdplane. the
4343 // data is *not* guaranteed to be nul-terminated, and may contain arbitrary
4344 // zeroes.
4345 typedef struct ncfdplane_options {
4346 void* curry; // parameter provided to callbacks
4347 bool follow; // keep reading after hitting end? (think tail -f)
4348 uint64_t flags; // bitfield over NCOPTION_FDPLANE_*
4349 } ncfdplane_options;
4350
4351 // Create an ncfdplane around the fd 'fd'. Consider this function to take
4352 // ownership of the file descriptor, which will be closed in ncfdplane_destroy().
4353 API ALLOC struct ncfdplane* ncfdplane_create(struct ncplane* n, const ncfdplane_options* opts,
4354 int fd, ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn)
4355 __attribute__ ((nonnull (1)));
4356
4357 API struct ncplane* ncfdplane_plane(struct ncfdplane* n)
4358 __attribute__ ((nonnull (1)));
4359
4360 API int ncfdplane_destroy(struct ncfdplane* n);
4361
4362 typedef struct ncsubproc_options {
4363 void* curry;
4364 uint64_t restart_period; // restart this many seconds after an exit (watch)
4365 uint64_t flags; // bitfield over NCOPTION_SUBPROC_*
4366 } ncsubproc_options;
4367
4368 // see exec(2). p-types use $PATH. e-type passes environment vars.
4369 API ALLOC struct ncsubproc* ncsubproc_createv(struct ncplane* n, const ncsubproc_options* opts,
4370 const char* bin, const char* const arg[],
4371 ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn)
4372 __attribute__ ((nonnull (1)));
4373
4374 API ALLOC struct ncsubproc* ncsubproc_createvp(struct ncplane* n, const ncsubproc_options* opts,
4375 const char* bin, const char* const arg[],
4376 ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn)
4377 __attribute__ ((nonnull (1)));
4378
4379 API ALLOC struct ncsubproc* ncsubproc_createvpe(struct ncplane* n, const ncsubproc_options* opts,
4380 const char* bin, const char* const arg[],
4381 const char* const env[],
4382 ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn)
4383 __attribute__ ((nonnull (1)));
4384
4385 API struct ncplane* ncsubproc_plane(struct ncsubproc* n)
4386 __attribute__ ((nonnull (1)));
4387
4388 API int ncsubproc_destroy(struct ncsubproc* n);
4389
4390 // Draw a QR code at the current position on the plane. If there is insufficient
4391 // room to draw the code here, or there is any other error, non-zero will be
4392 // returned. Otherwise, the QR code "version" (size) is returned. The QR code
4393 // is (version * 4 + 17) columns wide, and ⌈version * 4 + 17⌉ rows tall (the
4394 // properly-scaled values are written back to '*ymax' and '*xmax').
4395 API int ncplane_qrcode(struct ncplane* n, unsigned* ymax, unsigned* xmax,
4396 const void* data, size_t len)
4397 __attribute__ ((nonnull (1, 4)));
4398
4399 // Enable horizontal scrolling. Virtual lines can then grow arbitrarily long.
4400 #define NCREADER_OPTION_HORSCROLL 0x0001ull
4401 // Enable vertical scrolling. You can then use arbitrarily many virtual lines.
4402 #define NCREADER_OPTION_VERSCROLL 0x0002ull
4403 // Disable all editing shortcuts. By default, emacs-style keys are available.
4404 #define NCREADER_OPTION_NOCMDKEYS 0x0004ull
4405 // Make the terminal cursor visible across the lifetime of the ncreader, and
4406 // have the ncreader manage the cursor's placement.
4407 #define NCREADER_OPTION_CURSOR 0x0008ull
4408
4409 typedef struct ncreader_options {
4410 uint64_t tchannels; // channels used for input
4411 uint32_t tattrword; // attributes used for input
4412 uint64_t flags; // bitfield of NCREADER_OPTION_*
4413 } ncreader_options;
4414
4415 // ncreaders provide freeform input in a (possibly multiline) region, supporting
4416 // optional readline keybindings. takes ownership of 'n', destroying it on any
4417 // error (ncreader_destroy() otherwise destroys the ncplane).
4418 API ALLOC struct ncreader* ncreader_create(struct ncplane* n, const ncreader_options* opts)
4419 __attribute__ ((nonnull (1)));
4420
4421 // empty the ncreader of any user input, and home the cursor.
4422 API int ncreader_clear(struct ncreader* n)
4423 __attribute__ ((nonnull (1)));
4424
4425 API struct ncplane* ncreader_plane(struct ncreader* n)
4426 __attribute__ ((nonnull (1)));
4427
4428 // Offer the input to the ncreader. If it's relevant, this function returns
4429 // true, and the input ought not be processed further. Almost all inputs
4430 // are relevant to an ncreader, save synthesized ones.
4431 API bool ncreader_offer_input(struct ncreader* n, const ncinput* ni)
4432 __attribute__ ((nonnull (1, 2)));
4433
4434 // Atttempt to move in the specified direction. Returns 0 if a move was
4435 // successfully executed, -1 otherwise. Scrolling is taken into account.
4436 API int ncreader_move_left(struct ncreader* n)
4437 __attribute__ ((nonnull (1)));
4438 API int ncreader_move_right(struct ncreader* n)
4439 __attribute__ ((nonnull (1)));
4440 API int ncreader_move_up(struct ncreader* n)
4441 __attribute__ ((nonnull (1)));
4442 API int ncreader_move_down(struct ncreader* n)
4443 __attribute__ ((nonnull (1)));
4444
4445 // Destructively write the provided EGC to the current cursor location. Move
4446 // the cursor as necessary, scrolling if applicable.
4447 API int ncreader_write_egc(struct ncreader* n, const char* egc)
4448 __attribute__ ((nonnull (1, 2)));
4449
4450 // return a heap-allocated copy of the current (UTF-8) contents.
4451 API char* ncreader_contents(const struct ncreader* n)
4452 __attribute__ ((nonnull (1)));
4453
4454 // destroy the reader and its bound plane. if 'contents' is not NULL, the
4455 // UTF-8 input will be heap-duplicated and written to 'contents'.
4456 API void ncreader_destroy(struct ncreader* n, char** contents);
4457
4458 // Returns a heap-allocated copy of the user name under which we are running.
4459 API ALLOC char* notcurses_accountname(void);
4460
4461 // Returns a heap-allocated copy of the local host name.
4462 API ALLOC char* notcurses_hostname(void);
4463
4464 // Returns a heap-allocated copy of human-readable OS name and version.
4465 API ALLOC char* notcurses_osversion(void);
4466
4467 // Dump selected Notcurses state to the supplied 'debugfp'. Output is freeform,
4468 // newline-delimited, and subject to change. It includes geometry of all
4469 // planes, from all piles. No line has more than 80 columns' worth of output.
4470 API void notcurses_debug(const struct notcurses* nc, FILE* debugfp)
4471 __attribute__ ((nonnull (1, 2)));
4472
4473 #undef API
4474 #undef ALLOC
4475
4476 #ifdef __cplusplus
4477 } // extern "C"
4478 #endif
4479
4480 #endif
4481