merge in doc changes

pull/274/head
nick black 5 years ago
commit d9b721971a
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -115,12 +115,13 @@ foreach(f ${POCSRCS})
endforeach()
# Documentation
file(GLOB MANSOURCE1 CONFIGURE_DEPENDS doc/man/man1/*.md)
file(GLOB MANSOURCE3 CONFIGURE_DEPENDS doc/man/man3/*.md)
FIND_PROGRAM(PANDOC pandoc)
iF(NOT PANDOC)
message(WARNING "pandoc not found, won't generate documentation")
else()
foreach(m ${MANSOURCE3})
foreach(m ${MANSOURCE3} ${MANSOURCE1})
get_filename_component(me ${m} NAME_WLE)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${me}
@ -133,8 +134,9 @@ foreach(m ${MANSOURCE3})
ALL
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${me}
)
set(MANPAGES3 ${MANPAGES3} ${CMAKE_CURRENT_BINARY_DIR}/${me})
file(GLOB ANALHTML doc/analytics-header.html)
set(MANPAGES3 ${MANPAGES3} ${CMAKE_CURRENT_BINARY_DIR}/${me})
set(MANPAGES1 ${MANPAGES1} ${CMAKE_CURRENT_BINARY_DIR}/${me})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${me}.html
DEPENDS ${m} ${ANALHTML}

@ -123,6 +123,10 @@ hides important output).
To watch the bitchin' demo, run `./notcurses-demo -p ../data`. More details can
be found on the `notcurses-demo(1)` man page.
<p align="center">
<img width="640" height="112" src="doc/widechars.png" alt="notcurses 1.0.2 wide banner"/>
</p>
## Use
A full API reference [is available](https://nick-black.com/notcurses/). Manual
@ -1126,6 +1130,10 @@ ncplane_bg_rgb(const struct ncplane* n, unsigned* r, unsigned* g, unsigned*
int ncplane_set_fg_rgb(struct ncplane* n, int r, int g, int b);
int ncplane_set_bg_rgb(struct ncplane* n, int r, int g, int b);
// Same, but clipped to [0..255].
void ncplane_set_bg_rgb_clipped(struct ncplane* n, int r, int g, int b);
void ncplane_set_fg_rgb_clipped(struct ncplane* n, int r, int g, int b);
// Same, but with rgb assembled into a channel (i.e. lower 24 bits).
int ncplane_set_fg(struct ncplane* n, unsigned channel);
int ncplane_set_bg(struct ncplane* n, unsigned channel);
@ -1460,6 +1468,18 @@ cell_set_fg_rgb(cell* cl, int r, int g, int b){
return channels_set_fg_rgb(&cl->channels, r, g, b);
}
// Same, but clipped to [0..255].
static inline void
cell_set_fg_rgb_clipped(cell* cl, int r, int g, int b){
channels_set_fg_rgb_clipped(&cl->channels, r, g, b);
}
// Same, but with an assembled 32-bit channel.
static inline int
cell_set_fg(cell* c, uint32_t channel){
return channels_set_fg(&c->channels, channel);
}
// Set the r, g, and b cell for the background component of this 64-bit
// 'cell' variable, and mark it as not using the default color.
static inline int
@ -1467,12 +1487,13 @@ cell_set_bg_rgb(cell* cl, int r, int g, int b){
return channels_set_bg_rgb(&cl->channels, r, g, b);
}
// Same, but with an assembled 32-bit channel.
static inline int
cell_set_fg(cell* c, uint32_t channel){
return channels_set_fg(&c->channels, channel);
// Same, but clipped to [0..255].
static inline void
cell_set_bg_rgb_clipped(cell* cl, int r, int g, int b){
channels_set_bg_rgb_clipped(&cl->channels, r, g, b);
}
// Same, but with an assembled 32-bit channel.
static inline int
cell_set_bg(cell* c, uint32_t channel){
return channels_set_bg(&c->channels, channel);

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@ -1,75 +0,0 @@
.TH notcurses-demo 1 "v1.0.2"
.SH NAME
notcurses-demo \- Show off some notcurses features
.SH SYNOPSIS
.B notcurses-demo
[ \fB\-p \fIpath \fR]
[ \fB\-d \fIdelaymult \fR]
[ \fB\-k \fR]
[ \fB\-c \fR]
[ \fB\-h / \fB\-\-help \fR]
.IR demospec
.SH OPTIONS
.TP
.BR \-p \fIpath\fR
Look in the specified path for data files.
.TP
.BR \-d \fIdelaymult\fR
Apply a (floating-point) multiplier to the standard delay of 1s.
.TP
.BR \-H
Launch a HUD with running timers for each demo. This HUD can be moved or
closed with the mouse.
.TP
.BR \-k
Inhibit use of the alternate screen. Necessary if you want the output left
on your terminal after the program exits.
.TP
.BR \-c
Do not attempt to seed the PRNG. This is useful when benchmarking.
.TP
.BR \-h ", " \-\-help
Print a usage message, and exit with success.
.TP
.BR \-V ", " \-\-version
Print the program name and version, and exit with success.
.TP
.IR demospec
Select which demos to run, and what order to run them in. The default is "ixetcgswubvlpo". See below for a list of demos.
.SH DESCRIPTION
.B notcurses-demo
contains a set of text-based demonstrations of capabilities from the notcurses library. The demonstrations include:
.P
(i)ntro—a setting of tone
.P
(x)ray—stimulate a logo with energy
.P
(e)agle—zoom in on a background from Ninja Gaiden
.P
(t)rans—an exploration of various transparencies
.P
(c)hunli—the day Bison graced her village, it was Tuesday
.P
(l)uigi-a dashing plumber of Apennine persuasion
.P
(u)niblocks—a series of blocks detailing Unicode pages
.P
(b)oxes—pulsating boxes with a transparent center
.P
(g)rid—a gradient of color lain atop a great grid
.P
(s)liders—a missing-piece puzzle made up of colorful blocks
.P
(w)hiteworm—a great Nothing slowly robs the world of color
.P
(v)iew—images and a video are rendered as text
.P
(p)anelreels—demonstration of the panelreel high-level widget
.P
(o)utro—a message of hope from the library's author
.P
At any time, press 'q' to quit. The demo is best run in at least a 80x45 terminal.
.SH NOTES
Proper display requires a terminal advertising the RGB terminfo(5) capability (necessary for specification of arbitrary 24bpp colors), and a monospaced font with good Unicode support.
.SH SEE ALSO
notcurses(3notcurses), ncurses(3ncurses), terminfo(5)

@ -0,0 +1,66 @@
% notcurses-demo(1)
% nick black <nickblack@linux.com>
% v1.0.2
# NAME
notcurses-demo - Show off some notcurses features
# SYNOPSIS
**notcurses-demo** [**-h|--help**] [**-p path**] [**-d delaymult**] [**-l loglevel**] [**-kHVc**] demospec
# DESCRIPTION
**notcurses-demo** demonstrates the capabilities of the notcurses library. It
can be run in any terminal emulator or console with a correct terminfo(5)
database, but is at is best in a "DirectColor" 24bpp RGB environment. If
**notcurses-demo** seems to generate garbage, something is likely configured in
a way that is going to prevent notcurses from working.
The demonstrations include:
* (i)ntro—a setting of tone
* (x)ray—stimulate a logo with energy
* (e)agle—they took some time off my life, back in the day
* (t)rans—an exploration of various transparencies
* (c)hunli—the strongest woman in the world
* (g)rid—a gradient of color lain atop a great grid
* (s)liders—a missing-piece puzzle made up of colorful blocks
* (w)itherworm—a great Nothing slowly robs the world of color
* (u)niblocks—a series of blocks detailing Unicode pages
* (b)oxes—pulsating boxes with a transparent center
* (v)iew—images and a video are rendered as text
* (l)uigi-a dashing Apennine plumber in a world of fire
* (p)anelreels—demonstration of the panelreel high-level widget
* (o)utro—a message of hope from the library's author
At any time, press 'q' to quit. The demo is best run in at least a 80x45 terminal.
# OPTIONS
**-p path**: Look in the specified **path** for data files.
**-d delaymult**: Apply a rational multiplier to the standard delay of 1s.
**-H**: Launch a HUD with running timers for each demo. This HUD can be moved or closed with the mouse.
**-k**: Inhibit use of the alternate screen. Necessary if you want the output left on your terminal after the program exits.
**-c**: Do not attempt to seed the PRNG. This is useful when benchmarking.
**-h**: Print a usage message, and exit with success.
**-V**: Print the program name and version, and exit with success.
demospec: Select which demos to run, and what order to run them in. The default is **ixetcgswubvlpo**. See above for a list of demos.
# NOTES
Proper display requires:
* A terminal advertising the **rgb** terminfo(5) capability, or that the environment variable **COLORTERM** is defined to **24bit** (and that the terminal honors this variable),
* A monospaced font, and
* Good Unicode support in your libc, font, and terminal emulator.
# SEE ALSO
notcurses(3notcurses), ncurses(3ncurses), terminfo(5)

@ -106,6 +106,10 @@ typedef struct cell {
**int cell_set_bg_rgb(cell* cl, int r, int g, int b);**
**void cell_set_fg_rgb_clipped(cell* cl, int r, int g, int b);**
**void cell_set_bg_rgb_clipped(cell* cl, int r, int g, int b);**
**int cell_set_fg(cell* c, uint32_t channel);**
**int cell_set_bg(cell* c, uint32_t channel);**
@ -116,9 +120,34 @@ typedef struct cell {
# DESCRIPTION
Cells make up the framebuffer associated with each plane, with one cell per
addressable coordinate. You should not usually need to interact directly
with cells.
Each **cell** contains exactly one extended grapheme cluster. If the EGC happens
to be a single ASCII character, i.e. a single character with a value less than
128, it is encoded directly into the **cell**'s **gcluster** field, and no
additional storage is necessary. In this case, **cell_simple_p()** is **true**.
Otherwise, the EGC is stored as a UTF-8 string in some backing egcpool. Egcpools
are associated with **ncplane**s, so **cell**s must be considered associated
with **ncplane**s. Indeed, **ncplane_erase()** destroys the backing storage for
all a plane's cells, invalidating them. This association is formed at the time
of **cell_load()**, **cell_prime()**, or **cell_duplicate()**. All of these
functions first call **cell_release()**, as does **cell_load_simple()**. When
done using a **cell** entirely, call **cell_release()**. **ncplane_destroy()**
will free up the memory used by the **cell**, but the backing egcpool has a
maximum size of 16MiB, and failure to release **cell**s can eventually block new
output.
# RETURN VALUES
**cell_load()** and similar functions return the number of bytes loaded from the
EGC, or -1 on failure. They can fail due to either an invalid UTF-8 input, or the
backing egcpool reaching its maximum size.
**cell_set_fg_rgb()** and similar functions will return -1 if provided invalid
inputs, and 0 otherwise.
# SEE ALSO
**notcurses(3)**, **notcurses_channels(3)**, **notcurses_ncplane(3)**,

@ -54,42 +54,52 @@ notcurses_ncplane - operations on notcurses planes
**int ncplane_cursor_move_yx(struct ncplane* n, int y, int x);**
**void ncplane_cursor_yx(const struct ncplane* n, int* restrict y, int* restrict x);**
**void ncplane_cursor_yx(struct ncplane* n, int* restrict y, int* restrict x);**
**uint64_t ncplane_channels(const struct ncplane* n);**
**uint64_t ncplane_channels(struct ncplane* n);**
**uint32_t ncplane_attr(const struct ncplane* n);**
**uint32_t ncplane_attr(struct ncplane* n);**
**static inline unsigned ncplane_bchannel(const struct ncplane* nc);**
**static inline unsigned ncplane_bchannel(struct ncplane* nc);**
**static inline unsigned ncplane_fchannel(const struct ncplane* nc);**
**static inline unsigned ncplane_fchannel(struct ncplane* nc);**
**static inline unsigned ncplane_fg(const struct ncplane* nc);**
**static inline unsigned ncplane_fg(struct ncplane* nc);**
**static inline unsigned ncplane_bg(const struct ncplane* nc);**
**static inline unsigned ncplane_bg(struct ncplane* nc);**
**static inline unsigned ncplane_fg_alpha(const struct ncplane* nc);**
**static inline unsigned ncplane_fg_alpha(struct ncplane* nc);**
**static inline unsigned ncplane_bg_alpha(const struct ncplane* nc);**
**static inline unsigned ncplane_bg_alpha(struct ncplane* nc);**
**static inline unsigned ncplane_fg_rgb(const struct ncplane* n, unsigned* r, unsigned* g, unsigned* b);**
**static inline unsigned ncplane_fg_rgb(struct ncplane* n, unsigned* r, unsigned* g, unsigned* b);**
**static inline unsigned ncplane_bg_rgb(const struct ncplane* n, unsigned* r, unsigned* g, unsigned* b);**
**static inline unsigned ncplane_bg_rgb(struct ncplane* n, unsigned* r, unsigned* g, unsigned* b);**
**int ncplane_set_fg_rgb(struct ncplane* n, **int r, **int g, **int b);**
**int ncplane_set_bg_rgb(struct ncplane* n, **int r, **int g, **int b);**
**int ncplane_set_fg_rgb(struct ncplane* n, int r, int g, int b);**
**int ncplane_set_bg_rgb(struct ncplane* n, int r, int g, int b);**
**void ncplane_set_fg_rgb_clipped(struct ncplane* n, int r, int g, int b);**
**void ncplane_set_bg_rgb_clipped(struct ncplane* n, int r, int g, int b);**
**int ncplane_set_fg(struct ncplane* n, unsigned channel);**
**int ncplane_set_bg(struct ncplane* n, unsigned channel);**
**void ncplane_set_fg_default(struct ncplane* n);**
**void ncplane_set_bg_default(struct ncplane* n);**
**int ncplane_set_fg_alpha(struct ncplane* n, **int alpha);**
**int ncplane_set_bg_alpha(struct ncplane* n, **int alpha);**
**int ncplane_set_fg_alpha(struct ncplane* n, int alpha);**
**int ncplane_set_bg_alpha(struct ncplane* n, int alpha);**
**void ncplane_styles_set(struct ncplane* n, unsigned stylebits);**
**void ncplane_styles_on(struct ncplane* n, unsigned stylebits);**
**void ncplane_styles_off(struct ncplane* n, unsigned stylebits);**
**unsigned ncplane_styles(struct ncplane* n);**

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

@ -862,6 +862,35 @@ channel_set_rgb(unsigned* channel, int r, int g, int b){
return 0;
}
// Set the three 8-bit components of a 32-bit channel, and mark it as not using
// the default color. Retain the other bits unchanged. r, g, and b will be
// clipped to the range [0..255].
static inline void
channel_set_rgb_clipped(unsigned* channel, int r, int g, int b){
if(r >= 256){
r = 255;
}
if(g >= 256){
g = 255;
}
if(b >= 256){
b = 255;
}
if(r <= -1){
r = 0;
}
if(g <= -1){
g = 0;
}
if(b <= -1){
b = 0;
}
unsigned c = (r << 16u) | (g << 8u) | b;
c |= CELL_BGDEFAULT_MASK;
const uint64_t mask = CELL_BGDEFAULT_MASK | CELL_BG_MASK;
*channel = (*channel & ~mask) | c;
}
// Same, but provide an assembled, packed 24 bits of rgb.
static inline int
channel_set(unsigned* channel, unsigned rgb){
@ -972,6 +1001,14 @@ channels_set_fg_rgb(uint64_t* channels, int r, int g, int b){
return 0;
}
// Same, but clips to [0..255].
static inline void
channels_set_fg_rgb_clipped(uint64_t* channels, int r, int g, int b){
unsigned channel = channels_fchannel(*channels);
channel_set_rgb_clipped(&channel, r, g, b);
*channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
}
// Set the r, g, and b channels for the background component of this 64-bit
// 'channels' variable, and mark it as not using the default color.
static inline int
@ -984,6 +1021,14 @@ channels_set_bg_rgb(uint64_t* channels, int r, int g, int b){
return 0;
}
// Same, but clips to [0..255].
static inline void
channels_set_bg_rgb_clipped(uint64_t* channels, int r, int g, int b){
unsigned channel = channels_bchannel(*channels);
channel_set_rgb_clipped(&channel, r, g, b);
*channels = (*channels & 0xffffffff00000000llu) | channel;
}
// Same, but set an assembled 32 bit channel at once.
static inline int
channels_set_fg(uint64_t* channels, unsigned rgb){
@ -1069,14 +1114,22 @@ channels_set_bg_default(uint64_t* channels){
// it will not be used (unless 'blends' is 0).
static inline unsigned
channels_blend(unsigned c1, unsigned c2, unsigned blends){
unsigned rsum, gsum, bsum;
if(blends == 0){
return c2;
}
if(!channel_default_p(c2) && !channel_default_p(c1)){
int rsum = (channel_r(c1) * blends + channel_r(c2)) / (blends + 1);
int gsum = (channel_g(c1) * blends + channel_g(c2)) / (blends + 1);
int bsum = (channel_b(c1) * blends + channel_b(c2)) / (blends + 1);
// don't just return c2, or you set wide status and all kinds of crap
if(channel_default_p(c2)){
channel_set_default(&c1);
}else{
channel_rgb(c2, &rsum, &gsum, &bsum);
channel_set_rgb(&c1, rsum, gsum, bsum);
}
channel_set_alpha(&c1, channel_alpha(c2));
}else if(!channel_default_p(c2) && !channel_default_p(c1)){
rsum = (channel_r(c1) * blends + channel_r(c2)) / (blends + 1);
gsum = (channel_g(c1) * blends + channel_g(c2)) / (blends + 1);
bsum = (channel_b(c1) * blends + channel_b(c2)) / (blends + 1);
channel_set_rgb(&c1, rsum, gsum, bsum);
channel_set_alpha(&c1, channel_alpha(c2));
}
return c1;
}
@ -1158,6 +1211,18 @@ cell_set_fg_rgb(cell* cl, int r, int g, int b){
return channels_set_fg_rgb(&cl->channels, r, g, b);
}
// Same, but clipped to [0..255].
static inline void
cell_set_fg_rgb_clipped(cell* cl, int r, int g, int b){
channels_set_fg_rgb_clipped(&cl->channels, r, g, b);
}
// Same, but with an assembled 32-bit channel.
static inline int
cell_set_fg(cell* c, uint32_t channel){
return channels_set_fg(&c->channels, channel);
}
// Set the r, g, and b cell for the background component of this 64-bit
// 'cell' variable, and mark it as not using the default color.
static inline int
@ -1165,12 +1230,13 @@ cell_set_bg_rgb(cell* cl, int r, int g, int b){
return channels_set_bg_rgb(&cl->channels, r, g, b);
}
// Same, but with an assembled 32-bit channel.
static inline int
cell_set_fg(cell* c, uint32_t channel){
return channels_set_fg(&c->channels, channel);
// Same, but clipped to [0..255].
static inline void
cell_set_bg_rgb_clipped(cell* cl, int r, int g, int b){
channels_set_bg_rgb_clipped(&cl->channels, r, g, b);
}
// Same, but with an assembled 32-bit channel.
static inline int
cell_set_bg(cell* c, uint32_t channel){
return channels_set_bg(&c->channels, channel);
@ -1251,6 +1317,10 @@ ncplane_bg_rgb(const struct ncplane* n, unsigned* r, unsigned* g, unsigned* b){
API int ncplane_set_fg_rgb(struct ncplane* n, int r, int g, int b);
API int ncplane_set_bg_rgb(struct ncplane* n, int r, int g, int b);
// Same, but clipped to [0..255].
API void ncplane_set_bg_rgb_clipped(struct ncplane* n, int r, int g, int b);
API void ncplane_set_fg_rgb_clipped(struct ncplane* n, int r, int g, int b);
// Same, but with rgb assembled into a channel (i.e. lower 24 bits).
API int ncplane_set_fg(struct ncplane* n, unsigned channel);
API int ncplane_set_bg(struct ncplane* n, unsigned channel);

@ -8,19 +8,17 @@ typedef struct chunli {
struct ncplane* n;
} chunli;
// test of sprites from files
int chunli_demo(struct notcurses* nc){
cell b = CELL_TRIVIAL_INITIALIZER;
cell_set_fg_alpha(&b, CELL_ALPHA_TRANSPARENT);
cell_set_bg_alpha(&b, CELL_ALPHA_TRANSPARENT);
struct timespec iterdelay;
timespec_div(&demodelay, 10, &iterdelay);
int averr, dimy, dimx;
static int
chunli_draw(struct notcurses* nc, const char* ext, int count, const cell* b){
chunli chuns[CHUNS];
char file[PATH_MAX];
for(int i = 0 ; i < CHUNS ; ++i){
int dimx, dimy;
struct timespec iterdelay;
timespec_div(&demodelay, 10, &iterdelay);
for(int i = 0 ; i < count ; ++i){
int averr;
notcurses_resize(nc, &dimy, &dimx);
snprintf(file, sizeof(file), "chunli%d.bmp", i + 1);
snprintf(file, sizeof(file), "chunli%d.%s", i + 1, ext);
chuns[i].path = find_data(file);
chuns[i].ncv = ncvisual_open_plane(nc, chuns[i].path, &averr, 0, 0, NCSCALE_NONE);
if(chuns[i].ncv == NULL){
@ -33,7 +31,7 @@ int chunli_demo(struct notcurses* nc){
return -1;
}
chuns[i].n = ncvisual_plane(chuns[i].ncv);
ncplane_set_base(chuns[i].n, &b);
ncplane_set_base(chuns[i].n, b);
int thisx, thisy;
ncplane_dim_yx(chuns[i].n, &thisy, &thisx);
if(ncplane_move_yx(chuns[i].n, (dimy - thisy) / 2, (dimx - thisx) / 2)){
@ -47,6 +45,19 @@ int chunli_demo(struct notcurses* nc){
ncvisual_destroy(chuns[i].ncv);
free(chuns[i].path);
}
return 0;
}
// test of sprites from files
int chunli_demo(struct notcurses* nc){
struct timespec iterdelay;
timespec_div(&demodelay, 10, &iterdelay);
int averr, dimy, dimx;
cell b = CELL_TRIVIAL_INITIALIZER;
cell_set_fg_alpha(&b, CELL_ALPHA_TRANSPARENT);
cell_set_bg_alpha(&b, CELL_ALPHA_TRANSPARENT);
chunli_draw(nc, "bmp", CHUNS, &b);
chunli_draw(nc, "png", 7, &b);
char* victory = find_data("chunlivictory.png");
struct ncvisual* ncv = ncvisual_open_plane(nc, victory, &averr, 0, 0, NCSCALE_NONE);
if(ncv == NULL){

@ -67,7 +67,7 @@ struct timespec demodelay = {
static void
usage(const char* exe, int status){
FILE* out = status == EXIT_SUCCESS ? stdout : stderr;
fprintf(out, "usage: %s [ -hHVkc ] [ -l loglevel ] [ -d mult ] [ -f renderfile ] demospec\n", exe);
fprintf(out, "usage: %s [ -hHVkc ] [ -p path ] [ -l loglevel ] [ -d mult ] [ -f renderfile ] demospec\n", exe);
fprintf(out, " -h: this message\n");
fprintf(out, " -V: print program name and version\n");
fprintf(out, " -l: logging level (%d: silent..%d: manic)\n", NCLOGLEVEL_SILENT, NCLOGLEVEL_TRACE);
@ -76,6 +76,7 @@ usage(const char* exe, int status){
fprintf(out, " -d: delay multiplier (float)\n");
fprintf(out, " -f: render to file in addition to stdout\n");
fprintf(out, " -c: constant PRNG seed, useful for benchmarking\n");
fprintf(out, " -p: data file path\n");
fprintf(out, "if no specification is provided, run %s\n", DEFAULT_DEMO);
fprintf(out, " b: run box\n");
fprintf(out, " c: run chunli\n");
@ -270,8 +271,8 @@ ext_demos(struct notcurses* nc, const char* demos){
uint64_t nowns = timespec_to_ns(&now);
results[i].timens = nowns - prevns;
prevns = nowns;
results[i].result = ret;
if(ret){
results[i].failed = true;
break;
}
hud_completion_notify(&results[i]);
@ -285,11 +286,12 @@ ext_demos(struct notcurses* nc, const char* demos){
static const char*
handle_opts(int argc, char** argv, notcurses_options* opts, bool* use_hud){
strcpy(datadir, NOTCURSES_SHARE);
char renderfile[PATH_MAX] = "";
bool constant_seed = false;
int c;
*use_hud = false;
memset(opts, 0, sizeof(*opts));
while((c = getopt(argc, argv, "HVhckl:d:f:p:")) != EOF){
while((c = getopt(argc, argv, "HVhckl:r:d:f:p:")) != EOF){
switch(c){
case 'H':
*use_hud = true;
@ -330,12 +332,19 @@ handle_opts(int argc, char** argv, notcurses_options* opts, bool* use_hud){
case 'p':
strcpy(datadir, optarg);
break;
case 'r':
strcpy(renderfile, optarg);
break;
case 'd':{
float f;
if(sscanf(optarg, "%f", &f) != 1){
fprintf(stderr, "Couldn't get a float from %s\n", optarg);
usage(*argv, EXIT_FAILURE);
}
if(f <= 0){
fprintf(stderr, "Invalid multiplier: %f\n", f);
usage(*argv, EXIT_FAILURE);
}
uint64_t ns = f * GIG;
demodelay.tv_sec = ns / GIG;
demodelay.tv_nsec = ns % GIG;
@ -347,6 +356,13 @@ handle_opts(int argc, char** argv, notcurses_options* opts, bool* use_hud){
if(!constant_seed){
srand(time(NULL)); // a classic blunder lol
}
if(strlen(renderfile)){
opts->renderfp = fopen(renderfile, "wb");
if(opts->renderfp == NULL){
fprintf(stderr, "Error opening %s for write\n", renderfile);
usage(*argv, EXIT_FAILURE);
}
}
const char* demos = argv[optind];
return demos;
}
@ -410,6 +426,11 @@ int main(int argc, char** argv){
if(notcurses_stop(nc)){
return EXIT_FAILURE;
}
if(nopts.renderfp){
if(fclose(nopts.renderfp)){
fprintf(stderr, "Warning: error closing renderfile\n");
}
}
bool failed = false;
uint64_t totalbytes = 0;
long unsigned totalframes = 0;
@ -434,8 +455,10 @@ int main(int argc, char** argv){
results[i].timens ?
results[i].stats.render_ns * 100 / results[i].timens : 0,
GIG / avg,
results[i].failed ? "***FAILED" : results[i].stats.renders ? "" : "***NOT RUN");
if(results[i].failed){
results[i].result < 0 ? "***FAILED" :
results[i].result > 0 ? "***ABORTED" :
results[i].stats.renders ? "" : "***NOT RUN");
if(results[i].result < 0){
failed = true;
}
totalframes += results[i].stats.renders;
@ -462,7 +485,8 @@ err:
notcurses_term_dim_yx(nc, &dimy, &dimx);
notcurses_stop(nc);
if(dimy < MIN_SUPPORTED_ROWS || dimx < MIN_SUPPORTED_COLS){
fprintf(stderr, "At least an 80x25 terminal is required (current: %dx%d)\n", dimx, dimy);
fprintf(stderr, "At least an %dx%d terminal is required (current: %dx%d)\n",
MIN_SUPPORTED_COLS, MIN_SUPPORTED_ROWS, dimx, dimy);
}
return EXIT_FAILURE;
}

@ -126,7 +126,7 @@ typedef struct demoresult {
char selector;
struct ncstats stats;
uint64_t timens;
bool failed;
int result; // positive == aborted, negative == failed
} demoresult;
// let the HUD know that a demo has completed, reporting the stats

@ -19,8 +19,10 @@ char32_t demo_getc(const struct timespec* ts, ncinput* ni){
struct timespec now;
uint64_t ns;
struct timespec abstime;
// yes, i'd like CLOCK_MONOTONIC too, but pthread_cond_timedwait() is based off
// of crappy CLOCK_REALTIME :/
if(ts){
clock_gettime(CLOCK_MONOTONIC, &now);
clock_gettime(CLOCK_REALTIME, &now);
ns = timespec_to_ns(&now) + timespec_to_ns(ts);
ns_to_timespec(ns, &abstime);
}else{
@ -29,7 +31,7 @@ char32_t demo_getc(const struct timespec* ts, ncinput* ni){
}
pthread_mutex_lock(&lock);
while(!queue){
clock_gettime(CLOCK_MONOTONIC, &now);
clock_gettime(CLOCK_REALTIME, &now);
if(timespec_to_ns(&now) > timespec_to_ns(&abstime)){
pthread_mutex_unlock(&lock);
return 0;
@ -52,11 +54,14 @@ char32_t demo_getc(const struct timespec* ts, ncinput* ni){
static int
pass_along(const ncinput* ni){
pthread_mutex_lock(&lock);
nciqueue *nq = malloc(sizeof(*nq));
memcpy(&nq->ni, ni, sizeof(*ni));
nq->next = NULL;
*enqueue = nq;
enqueue = &nq->next;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond);
return 0;
}

@ -262,8 +262,9 @@ close_pipes(int* pipes){
return 0;
}
static struct panelreel*
panelreel_demo_core(struct notcurses* nc, int efdr, int efdw, tabletctx** tctxs){
static int
panelreel_demo_core(struct notcurses* nc, int efdr, int efdw){
tabletctx* tctxs = NULL;
bool done = false;
int x = 8, y = 4;
panelreel_options popts = {
@ -287,16 +288,16 @@ panelreel_demo_core(struct notcurses* nc, int efdr, int efdw, tabletctx** tctxs)
channels_set_fg_rgb(&popts.borderchan, 136, 23, 152);
channels_set_bg_rgb(&popts.borderchan, 0, 0, 0);
if(channels_set_fg_alpha(&popts.bgchannel, CELL_ALPHA_TRANSPARENT)){
return NULL;
return -1;
}
if(channels_set_bg_alpha(&popts.bgchannel, CELL_ALPHA_TRANSPARENT)){
return NULL;
return -1;
}
struct ncplane* w = notcurses_stdplane(nc);
struct panelreel* pr = panelreel_create(w, &popts, efdw);
if(pr == NULL){
fprintf(stderr, "Error creating panelreel\n");
return NULL;
return -1;
}
// Press a for a new panel above the current, c for a new one below the
// current, and b for a new block at arbitrary placement.
@ -317,10 +318,11 @@ panelreel_demo_core(struct notcurses* nc, int efdr, int efdw, tabletctx** tctxs)
while(id < dimy / 8u){
newtablet = new_tabletctx(pr, &id);
if(newtablet == NULL){
return NULL;
panelreel_destroy(pr);
return -1;
}
newtablet->next = *tctxs;
*tctxs = newtablet;
newtablet->next = tctxs;
tctxs = newtablet;
}
do{
ncplane_styles_set(w, 0);
@ -333,7 +335,6 @@ panelreel_demo_core(struct notcurses* nc, int efdr, int efdw, tabletctx** tctxs)
ncplane_set_fg_rgb(w, 0, 55, 218);
wchar_t rw;
if((rw = handle_input(nc, pr, efdr, &deadline)) <= 0){
done = true;
break;
}
// FIXME clrtoeol();
@ -351,13 +352,13 @@ panelreel_demo_core(struct notcurses* nc, int efdr, int efdw, tabletctx** tctxs)
case NCKEY_RIGHT: ++x; if(panelreel_move(pr, x, y)){ --x; } break;
case NCKEY_UP: panelreel_prev(pr); break;
case NCKEY_DOWN: panelreel_next(pr); break;
case NCKEY_DEL: kill_active_tablet(pr, tctxs); break;
case NCKEY_DEL: kill_active_tablet(pr, &tctxs); break;
default:
ncplane_printf_yx(w, 3, 2, "Unknown keycode (0x%x)\n", rw);
}
if(newtablet){
newtablet->next = *tctxs;
*tctxs = newtablet;
newtablet->next = tctxs;
tctxs = newtablet;
}
struct timespec cur;
clock_gettime(CLOCK_MONOTONIC, &cur);
@ -366,32 +367,27 @@ panelreel_demo_core(struct notcurses* nc, int efdr, int efdw, tabletctx** tctxs)
}
//panelreel_validate(w, pr); // do what, if not assert()ing? FIXME
}while(!done);
return pr;
while(tctxs){
kill_tablet(&tctxs);
}
if(panelreel_destroy(pr)){
fprintf(stderr, "Error destroying panelreel\n");
return -1;
}
return done ? 1 : 0;
}
int panelreel_demo(struct notcurses* nc){
tabletctx* tctxs = NULL;
int pipes[2];
// freebsd doesn't have eventfd :/
if(pipe2(pipes, O_CLOEXEC | O_NONBLOCK)){
fprintf(stderr, "Error creating pipe (%s)\n", strerror(errno));
return -1;
}
struct panelreel* pr;
if((pr = panelreel_demo_core(nc, pipes[0], pipes[1], &tctxs)) == NULL){
close_pipes(pipes);
return -1;
}
while(tctxs){
kill_tablet(&tctxs);
}
int ret = panelreel_demo_core(nc, pipes[0], pipes[1]);
close_pipes(pipes);
if(panelreel_destroy(pr)){
fprintf(stderr, "Error destroying panelreel\n");
return -1;
}
if(demo_render(nc)){
return -1;
}
return 0;
return ret;
}

@ -20,7 +20,10 @@ fade_block(struct notcurses* nc, struct ncplane* nn, const struct timespec* subd
}
static int
draw_block(struct ncplane* nn, uint32_t blockstart){
draw_block(struct ncplane* nn, uint32_t blockstart, bool rtl){
if(rtl){
return 0;
}
int dimx, dimy;
ncplane_dim_yx(nn, &dimy, &dimx);
cell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
@ -50,7 +53,7 @@ draw_block(struct ncplane* nn, uint32_t blockstart){
int z;
for(z = 0 ; z < CHUNKSIZE ; ++z){
wchar_t w[2] = { blockstart + chunk * CHUNKSIZE + z, L'\0' };
char utf8arr[MB_CUR_MAX * 2 + 1];
char utf8arr[MB_CUR_MAX * 3 + 1];
if(wcswidth(w, sizeof(w) / sizeof(*w)) >= 1 && iswgraph(w[0])){
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
@ -87,72 +90,73 @@ int unicodeblocks_demo(struct notcurses* nc){
// marginally covered by mainstream fonts, some not at all. we explicitly
// list the ones we want.
const struct {
bool rtl; // are there right-to-left chars?
const char* name;
uint32_t start;
} blocks[] = {
{ .name = "Basic Latin, Latin 1 Supplement, Latin Extended", .start = 0, },
{ .name = "IPA Extensions, Spacing Modifiers, Greek and Coptic", .start = 0x200, },
{ .name = "Cyrillic, Cyrillic Supplement, Armenian, Hebrew", .start = 0x400, },
{ .name = "Arabic, Syriac, Arabic Supplement", .start = 0x600, },
{ .name = "Samaritan, Mandaic, Devanagari, Bengali", .start = 0x800, },
{ .name = "Gurmukhi, Gujarati, Oriya, Tamil", .start = 0xa00, },
{ .name = "Telugu, Kannada, Malayalam, Sinhala", .start = 0xc00, },
{ .name = "Thai, Lao, Tibetan", .start = 0xe00, },
{ .name = "Myanmar, Georgian, Hangul Jamo", .start = 0x1000, },
{ .name = "Ethiopic, Ethiopic Supplement, Cherokee", .start = 0x1200, },
{ .name = "Canadian", .start = 0x1400, },
{ .name = "Runic, Tagalog, Hanunoo, Buhid, Tagbanwa, Khmer", .start = 0x1600, },
{ .name = "Mongolian, Canadian Extended, Limbu, Tai Le", .start = 0x1800, },
{ .name = "Buginese, Tai Tham, Balinese, Sundanese, Batak", .start = 0x1a00, },
{ .name = "Lepcha, Ol Chiki, Vedic Extensions, Phonetic Extensions", .start = 0x1c00, },
{ .name = "Latin Extended Additional, Greek Extended", .start = 0x1e00, },
{ .name = "General Punctuation, Letterlike Symbols, Arrows", .start = 0x2000, },
{ .name = "Mathematical Operators, Miscellaneous Technical", .start = 0x2200, },
{ .name = "Control Pictures, Box Drawing, Block Elements", .start = 0x2400, },
{ .name = "Miscellaneous Symbols, Dingbats", .start = 0x2600, },
{ .name = "Braille Patterns, Supplemental Arrows", .start = 0x2800, },
{ .name = "Supplemental Mathematical Operators", .start = 0x2a00, },
{ .name = "Glagolitic, Georgian Supplement, Tifinagh", .start = 0x2c00, },
{ .name = "Supplemental Punctuation, CJK Radicals", .start = 0x2e00, },
{ .name = "CJK Symbols and Punctuation", .start = 0x3000, },
{ .name = "Enclosed CJK Letters and Months", .start = 0x3200, },
{ .name = "CJK Unified Ideographs Extension A", .start = 0x3400, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3600, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3800, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3a00, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3c00, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3e00, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4000, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4200, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4400, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4600, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4800, },
{ .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4a00, },
{ .name = "CJK Unified Ideographs Extension A, Yijang Hexagram", .start = 0x4c00, },
{ .name = "CJK Unified Ideographs", .start = 0x4e00, },
{ .name = "Yi Syllables", .start = 0xa000, },
{ .name = "Yi Syllables", .start = 0xa200, },
{ .name = "Yi Syllables, Yi Radicals, Lisu, Vai", .start = 0xa400, },
{ .name = "Vai, Cyrillic Extended-B, Bamum, Tone Letters, Latin Extended-D", .start = 0xa600, },
{ .name = "Halfwidth and Fullwidth Forms", .start = 0xff00, },
{ .name = "Linear B Syllabary, Linear B Ideograms, Aegean Numbers, Phaistos Disc", .start = 0x10000, },
{ .name = "Lycian, Carian, Coptic Epact Numbers, Old Italic, Gothic, Old Permic", .start = 0x10200, },
{ .name = "Cuneiform", .start = 0x12000, },
{ .name = "Cuneiform (cont.)", .start = 0x12200, },
{ .name = "Byzantine Musical Symbols, Musical Symbols", .start = 0x1d000, },
{ .name = "Ancient Greek Musical Notation, Mayan Numerals, Tai Xuan Jing, Counting Rods", .start = 0x1d200, },
{ .name = "Mathematical Alphanumeric Symbols", .start = 0x1d400, },
{ .name = "Mathematical Alphanumeric Symbols (cont.)", .start = 0x1d600, },
{ .name = "Sutton SignWriting", .start = 0x1d800, },
{ .name = "Glagolitic Supplement, Nyiakeng Puachue Hmong", .start = 0x1e000, },
{ .name = "Ottoman Siyaq Numbers", .start = 0x1ed00, },
{ .name = "Arabic Mathematical Alphabetic Symbols", .start = 0x1ee00, },
{ .name = "Mahjong Tiles, Domino Tiles, Playing Cards", .start = 0x1f000, },
{ .name = "Enclosed Ideographic Supplement, Miscellaneous Symbols", .start = 0x1f200, },
{ .name = "Miscellaneous Symbols and Pictographs (cont.)", .start = 0x1f400, },
{ .name = "Emoticons, Ornamental Dingbats, Transport and Map Symbols", .start = 0x1f600, },
{ .name = "Supplemental Arrows-C, Supplemental Symbols", .start = 0x1f800, },
{ .name = "Chess Symbols, Symbols and Pictographs Extended-A", .start = 0x1fa00, },
{ .rtl = false, .name = "Basic Latin, Latin 1 Supplement, Latin Extended", .start = 0, },
{ .rtl = false, .name = "IPA Extensions, Spacing Modifiers, Greek and Coptic", .start = 0x200, },
{ .rtl = true, .name = "Cyrillic, Cyrillic Supplement, Armenian, Hebrew", .start = 0x400, },
{ .rtl = true, .name = "Arabic, Syriac, Arabic Supplement", .start = 0x600, },
{ .rtl = true, .name = "Samaritan, Mandaic, Devanagari, Bengali", .start = 0x800, },
{ .rtl = false, .name = "Gurmukhi, Gujarati, Oriya, Tamil", .start = 0xa00, },
{ .rtl = false, .name = "Telugu, Kannada, Malayalam, Sinhala", .start = 0xc00, },
{ .rtl = false, .name = "Thai, Lao, Tibetan", .start = 0xe00, },
{ .rtl = false, .name = "Myanmar, Georgian, Hangul Jamo", .start = 0x1000, },
{ .rtl = false, .name = "Ethiopic, Ethiopic Supplement, Cherokee", .start = 0x1200, },
{ .rtl = false, .name = "Canadian", .start = 0x1400, },
{ .rtl = false, .name = "Runic, Tagalog, Hanunoo, Buhid, Tagbanwa, Khmer", .start = 0x1600, },
{ .rtl = false, .name = "Mongolian, Canadian Extended, Limbu, Tai Le", .start = 0x1800, },
{ .rtl = false, .name = "Buginese, Tai Tham, Balinese, Sundanese, Batak", .start = 0x1a00, },
{ .rtl = false, .name = "Lepcha, Ol Chiki, Vedic Extensions, Phonetic Extensions", .start = 0x1c00, },
{ .rtl = false, .name = "Latin Extended Additional, Greek Extended", .start = 0x1e00, },
{ .rtl = false, .name = "General Punctuation, Letterlike Symbols, Arrows", .start = 0x2000, },
{ .rtl = false, .name = "Mathematical Operators, Miscellaneous Technical", .start = 0x2200, },
{ .rtl = false, .name = "Control Pictures, Box Drawing, Block Elements", .start = 0x2400, },
{ .rtl = false, .name = "Miscellaneous Symbols, Dingbats", .start = 0x2600, },
{ .rtl = false, .name = "Braille Patterns, Supplemental Arrows", .start = 0x2800, },
{ .rtl = false, .name = "Supplemental Mathematical Operators", .start = 0x2a00, },
{ .rtl = false, .name = "Glagolitic, Georgian Supplement, Tifinagh", .start = 0x2c00, },
{ .rtl = false, .name = "Supplemental Punctuation, CJK Radicals", .start = 0x2e00, },
{ .rtl = false, .name = "CJK Symbols and Punctuation", .start = 0x3000, },
{ .rtl = false, .name = "Enclosed CJK Letters and Months", .start = 0x3200, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A", .start = 0x3400, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3600, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3800, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3a00, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3c00, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x3e00, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4000, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4200, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4400, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4600, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4800, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A (cont.)", .start = 0x4a00, },
{ .rtl = false, .name = "CJK Unified Ideographs Extension A, Yijang Hexagram", .start = 0x4c00, },
{ .rtl = false, .name = "CJK Unified Ideographs", .start = 0x4e00, },
{ .rtl = false, .name = "Yi Syllables", .start = 0xa000, },
{ .rtl = false, .name = "Yi Syllables", .start = 0xa200, },
{ .rtl = false, .name = "Yi Syllables, Yi Radicals, Lisu, Vai", .start = 0xa400, },
{ .rtl = false, .name = "Vai, Cyrillic Extended-B, Bamum, Tone Letters, Latin Extended-D", .start = 0xa600, },
{ .rtl = false, .name = "Halfwidth and Fullwidth Forms", .start = 0xff00, },
{ .rtl = false, .name = "Linear B Syllabary, Linear B Ideograms, Aegean Numbers, Phaistos Disc", .start = 0x10000, },
{ .rtl = false, .name = "Lycian, Carian, Coptic Epact Numbers, Old Italic, Gothic, Old Permic", .start = 0x10200, },
{ .rtl = false, .name = "Cuneiform", .start = 0x12000, },
{ .rtl = false, .name = "Cuneiform (cont.)", .start = 0x12200, },
{ .rtl = false, .name = "Byzantine Musical Symbols, Musical Symbols", .start = 0x1d000, },
{ .rtl = false, .name = "Ancient Greek Musical Notation, Mayan Numerals, Tai Xuan Jing, Counting Rods", .start = 0x1d200, },
{ .rtl = false, .name = "Mathematical Alphanumeric Symbols", .start = 0x1d400, },
{ .rtl = false, .name = "Mathematical Alphanumeric Symbols (cont.)", .start = 0x1d600, },
{ .rtl = false, .name = "Sutton SignWriting", .start = 0x1d800, },
{ .rtl = false, .name = "Glagolitic Supplement, Nyiakeng Puachue Hmong", .start = 0x1e000, },
{ .rtl = false, .name = "Ottoman Siyaq Numbers", .start = 0x1ed00, },
{ .rtl = false, .name = "Arabic Mathematical Alphabetic Symbols", .start = 0x1ee00, },
{ .rtl = false, .name = "Mahjong Tiles, Domino Tiles, Playing Cards", .start = 0x1f000, },
{ .rtl = false, .name = "Enclosed Ideographic Supplement, Miscellaneous Symbols", .start = 0x1f200, },
{ .rtl = false, .name = "Miscellaneous Symbols and Pictographs (cont.)", .start = 0x1f400, },
{ .rtl = false, .name = "Emoticons, Ornamental Dingbats, Transport and Map Symbols", .start = 0x1f600, },
{ .rtl = false, .name = "Supplemental Arrows-C, Supplemental Symbols", .start = 0x1f800, },
{ .rtl = false, .name = "Chess Symbols, Symbols and Pictographs Extended-A", .start = 0x1fa00, },
};
size_t sindex;
// we don't want a full delay period for each one, urk...or do we?
@ -175,7 +179,7 @@ int unicodeblocks_demo(struct notcurses* nc){
if(hud){
ncplane_move_below_unsafe(nn, hud);
}
if(draw_block(nn, blockstart)){
if(draw_block(nn, blockstart, blocks[sindex].rtl)){
return -1;
}
ncplane_set_fg_rgb(n, 0x40, 0xc0, 0x40);

@ -5,11 +5,10 @@ static int
watch_for_keystroke(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused)),
void* curry __attribute__ ((unused))){
wchar_t w;
// we don't want a keypress, but should handle NCKEY_RESIZE
// we don't want a keypress, but allow the ncvisual to handle
// NCKEY_RESIZE for us
if((w = demo_getc_nblock(NULL)) != (wchar_t)-1){
if(w == NCKEY_RESIZE){
// FIXME resize that sumbitch
}else if(w){
if(w == 'q'){
return 1;
}
}
@ -30,12 +29,9 @@ view_video_demo(struct notcurses* nc){
return -1;
}
free(fm6);
if(ncvisual_stream(nc, ncv, &averr, watch_for_keystroke, NULL) < 0){
ncvisual_destroy(ncv);
return -1;
}
int ret = ncvisual_stream(nc, ncv, &averr, watch_for_keystroke, NULL);
ncvisual_destroy(ncv);
return 0;
return ret;
}
static struct ncplane*
@ -139,9 +135,7 @@ int view_demo(struct notcurses* nc){
if(ncpl == NULL){
return -1;
}
if(view_video_demo(nc)){
return -1;
}
int ret = view_video_demo(nc);
ncplane_destroy(ncpl);
return 0;
return ret;
}

@ -16,70 +16,28 @@ mathplane(struct notcurses* nc){
notcurses_term_dim_yx(nc, &dimy, &dimx);
const int HEIGHT = 9;
const int WIDTH = dimx;
struct ncplane* n = ncplane_new(nc, HEIGHT, WIDTH, dimy - HEIGHT - 1, dimx - WIDTH - 1, NULL);
struct ncplane* n = ncplane_new(nc, HEIGHT, WIDTH, dimy - HEIGHT - 1, dimx - WIDTH, NULL);
cell b = CELL_TRIVIAL_INITIALIZER;
cell_set_fg_rgb(&b, 0xff, 0xff, 0xff);
cell_set_fg_alpha(&b, CELL_ALPHA_BLEND);
cell_set_bg_alpha(&b, CELL_ALPHA_TRANSPARENT);
cell_set_fg_alpha(&b, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(n, &b);
cell_release(n, &b);
ncplane_set_fg_rgb(n, 0xff, 0xff, 0xff);
if(n){
/* FIXME issue #260
struct ncplane* stdn = notcurses_stdplane(nc);
ncplane_set_bg_alpha(n, CELL_ALPHA_TRANSPARENT);
int snatchy = dimy - HEIGHT - 1;
cell c = CELL_TRIVIAL_INITIALIZER;
ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);
// FIXME reenable the left parts of these strings, issue #260*/
//ncplane_printf_aligned(n, 0, NCALIGN_RIGHT, /*∮E⋅da=Q,n→∞,∑f(i)=∏g(i)*/"⎧⎡⎛┌─────┐⎞⎤⎫");
/*ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);
ncplane_printf_aligned(n, 0, NCALIGN_RIGHT, "∮E⋅da=Q,n→∞,∑f(i)=∏g(i)⎧⎡⎛┌─────┐⎞⎤⎫");
ncplane_printf_aligned(n, 1, NCALIGN_RIGHT, "⎪⎢⎜│a²+b³ ⎟⎥⎪");
ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);*/
//ncplane_printf_aligned(n, 2, NCALIGN_RIGHT, /*∀x∈:⌈x⌉=x⌋,α∧¬β=¬(¬α∨β)*/"⎪⎢⎜│───── ⎟⎥⎪");
/*ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);
ncplane_printf_aligned(n, 2, NCALIGN_RIGHT, "∀x∈:⌈x⌉=x⌋,α∧¬β=¬(¬α∨β)⎪⎢⎜│───── ⎟⎥⎪");
ncplane_printf_aligned(n, 3, NCALIGN_RIGHT, "⎪⎢⎜⎷ c₈ ⎟⎥⎪");
ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);*/
//ncplane_printf_aligned(n, 4, NCALIGN_RIGHT, /*ℕ⊆ℕ₀⊂ℤ⊂ℚ⊂ℝ⊂ℂ(z̄=(z)(z)⋅𝑖)*/"⎨⎢⎜ ⎟⎥⎬");
/*ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);
ncplane_printf_aligned(n, 4, NCALIGN_RIGHT, "ℕ⊆ℕ₀⊂ℤ⊂ℚ⊂ℝ⊂ℂ(z̄=(z)(z)⋅𝑖)⎨⎢⎜ ⎟⎥⎬");
ncplane_printf_aligned(n, 5, NCALIGN_RIGHT, "⎪⎢⎜ ∞ ⎟⎥⎪");
ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);*/
//ncplane_printf_aligned(n, 6, NCALIGN_RIGHT, /*⊥<a≠b≡c≤d≪⇒(⟦A⟧⇔⟪B⟫)*/"⎪⎢⎜ ⎲ ⎟⎥⎪");
/*ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);
ncplane_printf_aligned(n, 6, NCALIGN_RIGHT, "⊥<a≠b≡c≤d≪⇒(⟦A⟧⇔⟪B⟫)⎪⎢⎜ ⎲ ⎟⎥⎪");
ncplane_printf_aligned(n, 7, NCALIGN_RIGHT, "⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪");
ncplane_at_yx(stdn, snatchy++, 0, &c);
ncplane_set_fg(n, cell_fchannel(&c) & CELL_BG_MASK);*/
//ncplane_printf_aligned(n, 8, NCALIGN_RIGHT, /*2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200µm*/"⎩⎣⎝i=1 ⎠⎦⎭");
ncplane_printf_aligned(n, 8, NCALIGN_RIGHT, "2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200µm⎩⎣⎝i=1 ⎠⎦⎭");
}
return n;
}
// get the (up to) eight surrounding cells. they run clockwise, starting from
// the upper left: 012
// 7 3
// 654
// is the provided cell part of the wall (i.e. a box-drawing character)?
static bool
wall_p(const struct ncplane* n, const cell* c){
if(cell_simple_p(c)){ // any simple cell is fine to consume
return false;
}
const char* egc = cell_extended_gcluster(n, c);
wchar_t w;
if(mbtowc(&w, egc, strlen(egc)) > 0){
if(w >= 0x2500 && w <= 0x257f){ // no room in the inn, little worm!
return true;
}
}
return false;
}
// the closer the coordinate is (lower distance), the more we lighten the cell
static inline int
lighten(struct ncplane* n, cell* c, int distance, int y, int x){
@ -88,15 +46,10 @@ lighten(struct ncplane* n, cell* c, int distance, int y, int x){
}
unsigned r, g, b;
cell_fg_rgb(c, &r, &g, &b);
r += rand() % ((r + 16) / (4 * distance + 1) + 1);
g += rand() % ((g + 16) / (4 * distance + 1) + 1);
b += rand() % ((b + 16) / (4 * distance + 1) + 1);
if(r > 255) r = 255;
if(g > 255) g = 255;
if(b > 255) b = 255;
if(cell_set_fg_rgb(c, r, g, b)){
return -1;
}
r += rand() % (20 / (5 * distance + 1) + 1);
g += rand() % (20 / (5 * distance + 1) + 1);
b += rand() % (20 / (5 * distance + 1) + 1);
cell_set_fg_rgb_clipped(c, r, g, b);
return ncplane_putc_yx(n, y, x, c);
}
@ -120,6 +73,7 @@ surrounding_cells(struct ncplane* n, cell* cells, int y, int x){
static int
lightup_surrounding_cells(struct ncplane* n, const cell* cells, int y, int x){
cell c = CELL_TRIVIAL_INITIALIZER;
/*
cell_duplicate(n, &c, &cells[0]);
lighten(n, &c, 2, y - 1, x - 1);
cell_duplicate(n, &c, &cells[1]);
@ -144,6 +98,7 @@ lightup_surrounding_cells(struct ncplane* n, const cell* cells, int y, int x){
lighten(n, &c, 2, y, x - 2);
cell_duplicate(n, &c, &cells[11]);
lighten(n, &c, 2, y, x + 2);
*/
cell_duplicate(n, &c, &cells[12]);
lighten(n, &c, 0, y, x);
cell_release(n, &c);
@ -178,13 +133,13 @@ wormy_top(struct notcurses* nc, worm* s){
}
static int
wormy(struct notcurses* nc, worm* s, int dimy, int dimx){
struct ncplane* n = notcurses_stdplane(nc);
wormy(worm* s, int dimy, int dimx){
int oldy, oldx;
cell c = CELL_TRIVIAL_INITIALIZER;
oldy = s->y;
oldx = s->x;
do{ // force a move
oldy = s->y;
oldx = s->x;
s->y = oldy;
s->x = oldx;
// FIXME he ought be weighted to avoid light; he's a worm after all
int direction = random() % 4;
switch(direction){
@ -205,23 +160,14 @@ wormy(struct notcurses* nc, worm* s, int dimy, int dimx){
if(s->x >= dimx){
s->x = 0;
}
ncplane_at_yx(n, s->y, s->x, &c);
// don't allow the worm into the summary zone (test for walls)
if(wall_p(n, &c)){
s->x = oldx;
s->y = oldy;
}
}while((oldx == s->x && oldy == s->y) || (s->x == s->prevx && s->y == s->prevy));
s->prevy = oldy;
s->prevx = oldx;
cell_release(n, &c);
return 0;
}
// each worm wanders around aimlessly, prohibited from entering the summary
// section. it ought light up the cells around it; to do this, we keep an array
// of 13 cells with the original colors, which we tune up for the duration of
// our colocality (unless they're summary area walls).
// each worm wanders around aimlessly. it lights up the cells around it; to do
// this, we keep an array of 13 cells with the original colors, which we tune up.
static void *
worm_thread(void* vnc){
struct notcurses* nc = vnc;
@ -233,7 +179,6 @@ worm_thread(void* vnc){
for(int s = 0 ; s < wormcount ; ++s){
init_worm(&worms[s], dimy, dimx);
}
struct timespec iterdelay = { .tv_sec = 0, .tv_nsec = 100000000ul / 20, };
while(true){
pthread_testcancel();
for(int s = 0 ; s < wormcount ; ++s){
@ -245,11 +190,10 @@ worm_thread(void* vnc){
return NULL;
}
for(int s = 0 ; s < wormcount ; ++s){
if(wormy(nc, &worms[s], dimy, dimx)){
if(wormy(&worms[s], dimy, dimx)){
return NULL;
}
}
nanosleep(&iterdelay, NULL);
}
return NULL;
}
@ -446,7 +390,7 @@ int witherworm_demo(struct notcurses* nc){
"𝐸 = 𝑚𝑐²",
"Jag kan äta glas utan att skada mig",
"Jeg kan spise glas, det gør ikke ondt på mig",
" ㎔㎮ ",
"㎛㎜㎝㎞㎟㎠㎡㎢㎣㎤㎥㎦㎕㎖㎗㎘㏄㎰㎱㎲㎳㎍㎎㎏㎅㎆㏔㎇㎐㎑㎒㎓㎔㎮㎯",
"Æ ka æe glass uhen at det go mæ naue",
"က္ယ္ဝန္တော္၊က္ယ္ဝန္မ မ္ယက္စားနုိင္သည္။ ၎က္ရောင္ ထိခုိက္မ္ဟု မရ္ဟိပာ။",
"ကျွန်တော် ကျွန်မ မှန်စားနိုင်တယ်။ ၎င်းကြောင့် ထိခိုက်မှုမရှိပါ။ ",
@ -538,8 +482,8 @@ int witherworm_demo(struct notcurses* nc){
NULL
};
const char** s;
const int steps[] = { 0x10040, 0x100, 0x100, 0x10001, };
const int starts[] = { 0x10101, 0x004000, 0x000040, 0x400040, };
const int steps[] = { 0, 0x10040, 0x100, 0x100, 0x10001, };
const int starts[] = { 0, 0x10101, 0x004000, 0x000040, 0x400040, };
struct ncplane* n = notcurses_stdplane(nc);
size_t i;
@ -658,6 +602,9 @@ int witherworm_demo(struct notcurses* nc){
notcurses_resize(nc, &maxy, &maxx);
}
}while(key == NCKEY_RESIZE);
if(key == 'q'){
return 1;
}
}
return 0;
}

@ -13,12 +13,23 @@ static const char* leg[] = {
" 888P ",
};
static int
watch_for_keystroke(struct notcurses* nc){
wchar_t w;
if((w = demo_getc_nblock(NULL)) != (wchar_t)-1){
if(w == 'q'){
return 1;
}
}
return demo_render(nc);
}
static int
perframecb(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused)),
void* vnewplane){
static int startr = 0xaf;
static int startg = 0xff;
static int startb = 0xd4;
static int startr = 0x5f;
static int startg = 0xaf;
static int startb = 0x84;
static int frameno = 0;
int dimx, dimy, y;
struct ncplane* n = *(struct ncplane**)vnewplane;
@ -64,10 +75,9 @@ perframecb(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused)),
stroff = -x;
x = 0;
}
ncplane_set_bg_alpha(n, CELL_ALPHA_BLEND);
for(size_t l = 0 ; l < sizeof(leg) / sizeof(*leg) ; ++l, ++y){
if(ncplane_set_fg_rgb(n, r - 0xa * l, g - 0xa * l, b - 0xa * l)){
return -1;
}
ncplane_set_fg_rgb_clipped(n, r + 0x8 * l, g + 0x8 * l, b + 0x8 * l);
if(ncplane_set_bg_rgb(n, (l + 1) * 0x2, 0x20, (l + 1) * 0x2)){
return -1;
}
@ -83,8 +93,7 @@ perframecb(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused)),
b = t;
}while(x < dimx);
++frameno;
demo_render(nc);
return 0;
return watch_for_keystroke(nc);
}
int xray_demo(struct notcurses* nc){
@ -103,9 +112,9 @@ int xray_demo(struct notcurses* nc){
return -1;
}
struct ncplane* newpanel = NULL;
ncvisual_stream(nc, ncv, &averr, perframecb, &newpanel);
int ret = ncvisual_stream(nc, ncv, &averr, perframecb, &newpanel);
ncvisual_destroy(ncv);
ncplane_destroy(n);
ncplane_destroy(newpanel);
return 0;
return ret;
}

@ -97,6 +97,9 @@ int ncplane_fadein(ncplane* n, const struct timespec* ts, fadecb fader){
int maxbsteps = pp.maxbg > pp.maxbr ? (pp.maxbb > pp.maxbg ? pp.maxbb : pp.maxbg) :
(pp.maxbb > pp.maxbr ? pp.maxbb : pp.maxbr);
int maxsteps = maxfsteps > maxbsteps ? maxfsteps : maxbsteps;
if(maxsteps == 0){
maxsteps = 1;
}
uint64_t nanosecs_total = ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec;
uint64_t nanosecs_step = nanosecs_total / maxsteps;
struct timespec times;
@ -172,6 +175,9 @@ int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader){
int maxbsteps = pp.maxbg > pp.maxbr ? (pp.maxbb > pp.maxbg ? pp.maxbb : pp.maxbg) :
(pp.maxbb > pp.maxbr ? pp.maxbb : pp.maxbr);
int maxsteps = maxfsteps > maxbsteps ? maxfsteps : maxbsteps;
if(maxsteps == 0){
maxsteps = 1;
}
uint64_t nanosecs_total = ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec;
uint64_t nanosecs_step = nanosecs_total / maxsteps;
struct timespec times;

@ -309,6 +309,17 @@ ns_to_timespec(uint64_t ns, struct timespec* ts){
return ts;
}
static inline void
cell_debug(const ncplane* p, const cell* c){
if(cell_simple_p(c)){
fprintf(stderr, "gcluster: %u %c attr: 0x%08x chan: 0x%016lx\n",
c->gcluster, c->gcluster, c->attrword, c->channels);
}else{
fprintf(stderr, "gcluster: %u %s attr: 0x%08x chan: 0x%016lx\n",
c->gcluster, extended_gcluster(p, c), c->attrword, c->channels);
}
}
// no CLOCK_MONOTONIC_RAW on FreeBSD as of 12.0 :/
#ifndef CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC

@ -671,6 +671,11 @@ ffmpeg_log_level(ncloglevel_e level){
}
notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
notcurses_options defaultopts;
memset(&defaultopts, 0, sizeof(defaultopts));
if(!opts){
opts = &defaultopts;
}
const char* encoding = nl_langinfo(CODESET);
if(encoding == NULL || strcmp(encoding, "UTF-8")){
fprintf(stderr, "Encoding (\"%s\") wasn't UTF-8, refusing to start\n",
@ -848,7 +853,7 @@ int notcurses_stop(notcurses* nc){
char minbuf[BPREFIXSTRLEN + 1];
char maxbuf[BPREFIXSTRLEN + 1];
double avg = nc->stashstats.render_ns / (double)nc->stashstats.renders;
fprintf(stderr, "\n%ju render%s, %.03gs total (%.03gs min, %.03gs max, %.02gs avg %.1f fps)\n",
fprintf(stderr, "\n%ju render%s, %.03gs total (%.03gs min, %.03gs max, %.03gs avg %.1f fps)\n",
nc->stashstats.renders, nc->stashstats.renders == 1 ? "" : "s",
nc->stashstats.render_ns / 1000000000.0,
nc->stashstats.render_min_ns / 1000000000.0,
@ -858,7 +863,7 @@ int notcurses_stop(notcurses* nc){
bprefix(nc->stashstats.render_bytes, 1, totalbuf, 0),
bprefix(nc->stashstats.render_min_bytes, 1, minbuf, 0),
bprefix(nc->stashstats.render_max_bytes, 1, maxbuf, 0),
fprintf(stderr, "%sB total (%sB min, %sB max, %.02fKiB avg)\n",
fprintf(stderr, "%sB total (%sB min, %sB max, %.03gKiB avg)\n",
totalbuf, minbuf, maxbuf,
avg / 1024);
}
@ -897,17 +902,33 @@ uint32_t ncplane_attr(const ncplane* n){
}
void ncplane_set_fg_default(struct ncplane* n){
ncplane_lock(n);
channels_set_fg_default(&n->channels);
ncplane_unlock(n);
}
void ncplane_set_bg_default(struct ncplane* n){
ncplane_lock(n);
channels_set_bg_default(&n->channels);
ncplane_unlock(n);
}
void ncplane_set_bg_rgb_clipped(ncplane* n, int r, int g, int b){
ncplane_lock(n);
channels_set_bg_rgb_clipped(&n->channels, r, g, b);
ncplane_unlock(n);
}
int ncplane_set_bg_rgb(ncplane* n, int r, int g, int b){
return channels_set_bg_rgb(&n->channels, r, g, b);
}
void ncplane_set_fg_rgb_clipped(ncplane* n, int r, int g, int b){
ncplane_lock(n);
channels_set_fg_rgb_clipped(&n->channels, r, g, b);
ncplane_unlock(n);
}
int ncplane_set_fg_rgb(ncplane* n, int r, int g, int b){
return channels_set_fg_rgb(&n->channels, r, g, b);
}
@ -1029,6 +1050,9 @@ ncplane_cursor_move_yx_locked(ncplane* n, int y, int x){
}else{
n->y = y;
}
if(cursor_invalid_p(n)){
return -1;
}
return 0;
}
@ -1050,7 +1074,7 @@ void ncplane_cursor_yx(ncplane* n, int* y, int* x){
static inline bool
ncplane_cursor_stuck(const ncplane* n){
return (n->x == n->lenx && n->y == n->leny);
return (n->x >= n->lenx && n->y >= n->leny);
}
static inline void
@ -1248,25 +1272,32 @@ unsigned ncplane_styles(ncplane* n){
// i hate the big allocation and two copies here, but eh what you gonna do?
// well, for one, we don't need the huge allocation FIXME
char* ncplane_vprintf_prep(ncplane* n, const char* format, va_list ap){
static char*
ncplane_vprintf_prep(ncplane* n, const char* format, va_list ap){
const size_t size = n->lenx + 1; // healthy estimate, can embiggen below
char* buf = malloc(size);
if(buf == NULL){
return NULL;
}
va_list vacopy;
va_copy(vacopy, ap);
int ret = vsnprintf(buf, size, format, ap);
if(ret < 0){
free(buf);
va_end(vacopy);
return NULL;
}
if((size_t)ret >= size){
char* tmp = realloc(buf, ret + 1);
if(tmp == NULL){
free(buf);
va_end(vacopy);
return NULL;
}
buf = tmp;
vsprintf(buf, format, vacopy);
}
va_end(vacopy);
return buf;
}

@ -172,14 +172,20 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int* previousz){
if(vis->gcluster == 0){
vis = &p->basecell;
}
// if we have no character in this cell, we continune to look for a
// if we have no character in this cell, we continue to look for a
// character, but our foreground color will still be used unless it's
// been set to transparent. if that foreground color is transparent, we
// still use a character we find here, but its color will come entirely
// from cells underneath us.
if(c->gcluster == 0){
if(!glyphplane){
if( (c->gcluster = vis->gcluster) ){ // index copy only
glyphplane = p; // must return this ncplane for this glyph
glyphplane = p;
}
if(cell_double_wide_p(vis)){
cell_set_wide(c);
glyphplane = p;
}
if(glyphplane){
c->attrword = vis->attrword;
}
}
@ -212,7 +218,7 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int* previousz){
}
// if we have a background set, but no glyph selected, load a space so that
// the background will be printed
if(c->gcluster == 0){
if(!glyphplane){
cell_load_simple(NULL, c, ' ');
}
if(depth < *previousz){
@ -511,9 +517,11 @@ notcurses_render_internal(notcurses* nc){
if((x + 1 >= nc->stdscr->lenx && cell_double_wide_p(&c))){
continue; // needmove will be reset as we restart the line
}
//fprintf(stderr, "%d %d depth: %d %d\n", y, x, depth, inright);
bool damaged = false;
if(depth > 0){ // we are above the previous source plane
if(inright){ // wipe out the character to the left
// FIXME do this by keeping an offset for the memstream, and
// truncating it (via lseek()), methinks
cell* prev = &nc->lastframe[fbcellidx(nc->stdscr, y, x - 1)];
pool_release(&nc->pool, prev);
cell_init(prev);
@ -523,7 +531,12 @@ notcurses_render_internal(notcurses* nc){
term_emit("cup", tiparm(nc->cup, y, x - 1), out, false);
fputc(' ', out);
inright = false;
//if(cell_simple_p(&c)){
//fprintf(stderr, "WENT BACK NOW FOR %c\n", c.gcluster);
//}else{
//fprintf(stderr, "WENT BACK NOW FOR %s\n", extended_gcluster(p, &c));
//}
damaged = true;
}
}
// lastframe has already been sized to match the current size, so no need
@ -535,24 +548,26 @@ notcurses_render_internal(notcurses* nc){
inright = false;
continue;
}
// check the damage map
// check the damage map, unless we must repair damage done
if(cellcmp_and_dupfar(&nc->pool, oldcell, p, &c) == 0){
// no need to emit a cell; what we rendered appears to already be
// here. no updates are performed to elision state nor lastframe.
++nc->stats.cellelisions;
if(needmove < INT_MAX){
++needmove;
}
if(cell_double_wide_p(&c)){
if(!damaged){
// no need to emit a cell; what we rendered appears to already be
// here. no updates are performed to elision state nor lastframe.
++nc->stats.cellelisions;
if(needmove < INT_MAX){
++needmove;
}
++nc->stats.cellelisions;
inright = !inright;
}else{
inright = false;
if(cell_double_wide_p(&c)){
if(needmove < INT_MAX){
++needmove;
}
++nc->stats.cellelisions;
inright = !inright;
}else{
inright = false;
}
continue;
}
continue;
}
}
++nc->stats.cellemissions;

@ -0,0 +1,82 @@
#include <cstdlib>
#include <locale.h>
#include <unistd.h>
#include <notcurses.h>
int mathtext(struct notcurses* nc){
int dimx, dimy;
notcurses_term_dim_yx(nc, &dimy, &dimx);
const int HEIGHT = 9;
const int WIDTH = dimx;
struct ncplane* n = ncplane_new(nc, HEIGHT, WIDTH, dimy - HEIGHT - 1, dimx - WIDTH - 1, NULL);
if(n){
struct ncplane* stdn = notcurses_stdplane(nc);
ncplane_set_fg(n, 0xffffff);
ncplane_set_bg(n, 0x008000);
ncplane_printf_aligned(n, 0, NCALIGN_RIGHT, "∮E⋅da=Q,n→∞,∑f(i)=∏g(i)⎧⎡⎛┌─────┐⎞⎤⎫");
ncplane_printf_aligned(n, 1, NCALIGN_RIGHT, "⎪⎢⎜│a²+b³ ⎟⎥⎪");
ncplane_printf_aligned(n, 2, NCALIGN_RIGHT, "∀x∈:⌈x⌉=x⌋,α∧¬β=¬(¬α∨β)⎪⎢⎜│───── ⎟⎥⎪");
ncplane_printf_aligned(n, 3, NCALIGN_RIGHT, "⎪⎢⎜⎷ c₈ ⎟⎥⎪");
ncplane_printf_aligned(n, 4, NCALIGN_RIGHT, "ℕ⊆ℕ₀⊂ℤ⊂ℚ⊂ℝ⊂ℂ(z̄=(z)(z)⋅𝑖)⎨⎢⎜ ⎟⎥⎬");
ncplane_printf_aligned(n, 5, NCALIGN_RIGHT, "⎪⎢⎜ ∞ ⎟⎥⎪");
ncplane_printf_aligned(n, 6, NCALIGN_RIGHT, "⊥<a≠b≡c≤d≪⇒(⟦A⟧⇔⟪B⟫)⎪⎢⎜ ⎲ ⎟⎥⎪");
ncplane_printf_aligned(n, 7, NCALIGN_RIGHT, "⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪");
ncplane_printf_aligned(n, 8, NCALIGN_RIGHT, "2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200µm⎩⎣⎝i=1 ⎠⎦⎭");
}
return 0;
}
int main(void){
if(setlocale(LC_ALL, "") == nullptr){
return EXIT_FAILURE;
}
notcurses_options opts{};
opts.inhibit_alternate_screen = true;
struct notcurses* nc = notcurses_init(&opts, stdout);
if(nc == nullptr){
return EXIT_FAILURE;
}
const char c[] =
"Jegkanspiseglassutenåskademeg"
"Egkannetaglasskaðaleysur"
"Éggetetiðgleránþessaðmeiðamig"
"𝐸=𝑚𝑐²"
"Jagkanätaglasutanattskadamig"
"Jegkanspiseglasdetgørikkeondtpåmig"
"㎚㎛㎜㎝㎞㎟㎠㎡㎢㎣㎤㎥㎦㎕㎖㎗㎘㏄㎰㎱㎲㎳㎍㎎㎏㎅㎆㏔㎇㎐㎑㎒㎓㎔㎮㎯"
"Ækaæeglassuhenatdetgomænaue"
"က္ယ္ဝန္တော၊က္ယ္ဝန္မမ္ယက္စားနုိင္သည္။၎က္ရောင္ထိခုိက္မ္ဟုမရ္ဟိပာ။"
"ကျွန်တောကျွန်မမှန်စားနိုင်တယ်။၎င်းကြေင့်ထိခိုက်မှုမရှိပါ။"
"Tôicóthểănthủytinhmàkhônghạigì"
"些𣎏世咹水晶𦓡空𣎏害"
"ខ្ញុំអាចញុំកញ្ចក់បានដោយគ្មានបញ្ហា"
"ຂອ້ຍກິນແກ້ວໄດ້ໂດຍທີ່ມັນບໍ່ໄດ້ເຮັດໃຫ້ຂອ້ຍເຈັບ"
"ฉันกินกระจกได้แต่มันไม่ทำให้ฉันเจ็"
"Бишилидэйчаднанададхортойби"
"ᠪᠢᠰᠢᠯᠢᠢᠳᠡᠶᠦᠴᠢᠳᠠᠨᠠ᠂ᠨᠠᠳᠤᠷᠬᠣᠤᠷᠠᠳᠠᠢᠪᠢᠰ"
"मकाँचखानसक्छूरमलाईकेहिनीहुन्न्"
"ཤེལ་སྒོ་ཟ་ནས་ང་ན་གི་མ་རེད"
"我能吞下玻璃而不伤身体"
"我能吞下玻璃而不傷身體"
"Góaē-tàngchia̍hpo-lêmābētio̍h-siong"
"私はガラスを食べられますそれは私を傷つけません"
"나는유리를먹을수있어요.그래도아프지않아"
"Misavekakaeglasheminosavekatemmi"
"Hikiiaʻukeʻaiikeaniani;ʻaʻolenōlāaueʻeha"
"Ekoʻanaekaiitekarahimeaʻāʻaʻehauhau"
"ᐊᓕᒍᖅᓂᕆᔭᕌᖓᒃᑯᓱᕋᙱᑦᑐᓐᓇᖅᑐ";
struct ncplane* n = notcurses_stdplane(nc);
int y, dimy;
notcurses_term_dim_yx(nc, &dimy, nullptr);
do{
ncplane_putstr(n, c);
ncplane_cursor_yx(n, &y, nullptr);
}while(y < dimy);
if(mathtext(nc)){
notcurses_stop(nc);
return EXIT_FAILURE;
}
notcurses_render(nc);
notcurses_stop(nc);
return 0;
}

@ -143,16 +143,13 @@ TEST_CASE("ChannelBlendDefaultRight") {
uint32_t c1 = 0;
uint32_t c2 = 0;
channel_set_rgb(&c1, 0x80, 0x40, 0x20);
CHECK(!channel_default_p(c1));
CHECK(channel_default_p(c2));
uint32_t c = channels_blend(c1, c2, 0);
CHECK(channel_default_p(c));
unsigned r, g, b;
channel_rgb(c, &r, &g, &b);
CHECK(0 == r);
CHECK(0 == g);
CHECK(0 == b);
c = channels_blend(c1, c2, 1);
CHECK(!channel_default_p(c));
unsigned r, g, b;
channel_rgb(c, &r, &g, &b);
CHECK(0x80 == r);
CHECK(0x40 == g);

Loading…
Cancel
Save