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