ncplane_resize(), slider demo (#64) (#74)

* sliding: bounding box around puzzle
* slider: make moves, deleting planes #61
* implement z-index move functions
* demo: allow demos to be chosen via command-line option
* allow default bg/fg to be explicitly chosen
* ncplane_resize() unit test #64
* useful links
* slider: use random colors
* use find_above() in ncplace_destroy()
* ncplane_resize() work #64
pull/81/head
Nick Black 5 years ago committed by GitHub
parent 374403fdeb
commit 7f9ac490b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -398,3 +398,15 @@ to implement".
tracing solutions exist, such as `bpftrace`.
* There is no timeout functionality for input (`timeout()`, `halfdelay()`, etc.).
Roll your own with any of the four thousand ways to do it.
## Useful links
* [BiDi in Terminal Emulators](https://terminal-wg.pages.freedesktop.org/bidi/)
* [The Xterm FAQ](https://invisible-island.net/xterm/xterm.faq.html)
* [The NCURSES FAQ](https://invisible-island.net/ncurses/ncurses.faq.html)
* [ECMA-35 Character Code Structure and Extension Techniques](https://www.ecma-international.org/publications/standards/Ecma-035.htm) (ISO/IEC 2022)
* [ECMA-43 8-bit Coded Character Set Structure and Rules](https://www.ecma-international.org/publications/standards/Ecma-043.htm)
* [ECMA-48 Control Functions for Coded Character Sets](https://www.ecma-international.org/publications/standards/Ecma-048.htm) (ISO/IEC 6429)
* [Unicode 12.1 Full Emoji List](https://unicode.org/emoji/charts/full-emoji-list.html)
* [Unicode Standard Annex #29 Text Segmenation](http://www.unicode.org/reports/tr29)
* [Unicode Standard Annex #15 Normalization Forms](https://unicode.org/reports/tr15/)

@ -9,6 +9,9 @@
#ifdef __cplusplus
extern "C" {
#define RESTRICT
#else
#define RESTRICT restrict
#endif
#define API __attribute__((visibility("default")))
@ -124,31 +127,52 @@ API int notcurses_resize(struct notcurses* n);
API struct ncplane* notcurses_stdplane(struct notcurses* nc);
API const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
// Create a new plane at the specified offset (relative to the standard plane)
// Create a new ncplane at the specified offset (relative to the standard plane)
// and the specified size. The number of rows and columns must both be positive.
// This plane is initially at the top of the z-buffer, as if ncplane_move_top()
// had been called on it. The void* 'opaque' can be retrieved (and reset) later.
API struct ncplane* notcurses_newplane(struct notcurses* nc, int rows, int cols,
int yoff, int xoff, void* opaque);
// Resize the specified ncplane. The four parameters 'keepy', 'keepx',
// 'keepleny', and 'keeplenx' define a subset of the ncplane to keep,
// unchanged. This may be a section of size 0, though none of these four
// parameters may be negative. 'keepx' and 'keepy' are relative to the ncplane.
// They must specify a coordinate within the ncplane's totality. 'yoff' and
// 'xoff' are relative to 'keepy' and 'keepx', and place the upper-left corner
// of the resized ncplane. Finally, 'ylen' and 'xlen' are the dimensions of the
// ncplane after resizing. 'ylen' must be greater than or equal to 'keepleny',
// and 'xlen' must be greater than or equal to 'keeplenx'. It is an error to
// attempt to resize the standard plane. If either of 'keepy' or 'keepx' is
// non-zero, both must be non-zero.
//
// Essentially, the kept material does not move. It serves to anchor the
// resized plane. If there is no kept material, the plane can move freely:
// it is possible to implement ncplane_move() in terms of ncplane_resize().
API int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny,
int keeplenx, int yoff, int xoff, int ylen, int xlen);
// Destroy the specified ncplane. None of its contents will be visible after
// the next call to notcurses_render(). It is an error to attempt to destroy
// the standard plane.
API int ncplane_destroy(struct notcurses* nc, struct ncplane* ncp);
API int ncplane_destroy(struct ncplane* ncp);
// Move this plane relative to the standard plane.
API int ncplane_move_yx(struct ncplane* n, int y, int x);
// Move this plane relative to the standard plane. It is an error to attempt to
// move the standard plane.
API void ncplane_move_yx(struct ncplane* n, int y, int x);
// Get the origin of this plane relative to the standard plane.
API void ncplane_yx(const struct ncplane* n, int* y, int* x);
API void ncplane_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
// Splice ncplane 'n' out of the z-buffer, and reinsert it above 'above'.
API void ncplane_move_above(struct ncplane* n, struct ncplane* above);
// Splice ncplane 'n' out of the z-buffer, and reinsert it below 'below'.
API void ncplane_move_below(struct ncplane* n, struct ncplane* below);
// Splice ncplane 'n' out of the z-buffer, and reinsert it at the top or bottom.
API void ncplane_move_top(struct ncplane* n);
API void ncplane_move_bottom(struct ncplane* n);
API int ncplane_move_top(struct ncplane* n);
API int ncplane_move_bottom(struct ncplane* n);
// Splice ncplane 'n' out of the z-buffer, and reinsert it below 'below'.
API int ncplane_move_below(struct ncplane* RESTRICT n, struct ncplane* RESTRICT below);
// Splice ncplane 'n' out of the z-buffer, and reinsert it above 'above'.
API int ncplane_move_above(struct ncplane* RESTRICT n, struct ncplane* RESTRICT above);
// Retrieve the topmost cell at this location on the screen, returning it in
// 'c'. If there is more than a byte of gcluster, it will be returned as a heap
@ -163,12 +187,14 @@ API void* ncplane_userptr(struct ncplane* n);
API const void* ncplane_userptr_const(const struct ncplane* n);
// Returns the dimensions of this ncplane.
API void ncplane_dimyx(const struct ncplane* n, int* rows, int* cols);
API void ncplane_dim_yx(const struct ncplane* n, int* RESTRICT rows,
int* RESTRICT cols);
// Return our current idea of the terminal dimensions in rows and cols.
static inline void
notcurses_term_dimyx(const struct notcurses* n, int* rows, int* cols){
ncplane_dimyx(notcurses_stdplane_const(n), rows, cols);
notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows,
int* RESTRICT cols){
ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
}
// Move the cursor to the specified position (the cursor needn't be visible).
@ -177,7 +203,8 @@ notcurses_term_dimyx(const struct notcurses* n, int* rows, int* cols){
API int ncplane_cursor_move_yx(struct ncplane* n, int y, int x);
// Get the current position of the cursor within n. y and/or x may be NULL.
API void ncplane_cursor_yx(const struct ncplane* n, int* y, int* x);
API void ncplane_cursor_yx(const struct ncplane* n, int* RESTRICT y,
int* RESTRICT x);
// Replace the cell underneath the cursor with the provided cell 'c', and
// advance the cursor by the width of the cell (but not past the end of the
@ -244,6 +271,10 @@ API void ncplane_erase(struct ncplane* n);
API int ncplane_fg_rgb8(struct ncplane* n, int r, int g, int b);
API int ncplane_bg_rgb8(struct ncplane* n, int r, int g, int b);
// use the default color for the foreground/background
API void ncplane_fg_default(struct ncplane* n);
API void ncplane_bg_default(struct ncplane* n);
// Set the specified style bits for the ncplane 'n', whether they're actively
// supported or not.
API void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
@ -359,22 +390,36 @@ cell_rgb_blue(uint32_t rgb){
#define CELL_BGDEFAULT_MASK 0x0000000040000000ull
#define CELL_BG_MASK 0x0000000000ffffffull
static inline void
cell_rgb_set_fg(uint64_t* channels, unsigned r, unsigned g, unsigned b){
static inline int
cell_rgb_set_fg(uint64_t* channels, int r, int g, int b){
if(r >= 256 || g >= 256 || b >= 256){
return -1;
}
if(r < 0 || g < 0 || b < 0){
return -1;
}
uint64_t rgb = (r & 0xffull) << 48u;
rgb |= (g & 0xffull) << 40u;
rgb |= (b & 0xffull) << 32u;
rgb |= CELL_FGDEFAULT_MASK;
*channels = (*channels & ~(CELL_FGDEFAULT_MASK | CELL_FG_MASK)) | rgb;
return 0;
}
static inline void
cell_rgb_set_bg(uint64_t* channels, unsigned r, unsigned g, unsigned b){
static inline int
cell_rgb_set_bg(uint64_t* channels, int r, int g, int b){
if(r >= 256 || g >= 256 || b >= 256){
return -1;
}
if(r < 0 || g < 0 || b < 0){
return -1;
}
uint64_t rgb = (r & 0xffull) << 16u;
rgb |= (g & 0xffull) << 8u;
rgb |= (b & 0xffull);
rgb |= CELL_BGDEFAULT_MASK;
*channels = (*channels & ~(CELL_BGDEFAULT_MASK | CELL_BG_MASK)) | rgb;
return 0;
}
static inline void
@ -407,12 +452,24 @@ cell_inherits_style(const cell* c){
return (c->channels & CELL_INHERITSTYLE_MASK);
}
// use the default color for the foreground
static inline void
cell_fg_default(cell* c){
c->channels |= CELL_FGDEFAULT_MASK;
}
// is the cell using the terminal's default foreground color for its foreground?
static inline bool
cell_fg_default_p(const cell* c){
return !(c->channels & CELL_FGDEFAULT_MASK);
}
// use the default color for the background
static inline void
cell_bg_default(cell* c){
c->channels |= CELL_BGDEFAULT_MASK;
}
// is the cell using the terminal's default background color for its background?
static inline bool
cell_bg_default_p(const cell* c){

@ -4,7 +4,7 @@
int box_demo(struct notcurses* nc){
int ylen, xlen;
notcurses_term_dimyx(nc, &ylen, &xlen);
notcurses_term_dim_yx(nc, &ylen, &xlen);
struct ncplane* n = notcurses_stdplane(nc);
ncplane_erase(n);
cell ul, ll, lr, ur, hl, vl;

@ -16,87 +16,30 @@ struct timespec demodelay = {
static void
usage(const char* exe, int status){
FILE* out = status == EXIT_SUCCESS ? stdout : stderr;
fprintf(out, "usage: %s [ -h ] [ -k ] [ -d ns ]\n", exe);
fprintf(out, " h: this message\n");
fprintf(out, " k: keep screen; do not switch to alternate\n");
fprintf(out, " d: delay in nanoseconds between demos\n");
fprintf(out, "usage: %s [ -h ] [ -k ] [ -d ns ] [ demos ]\n", exe);
fprintf(out, " -h: this message\n");
fprintf(out, " -k: keep screen; do not switch to alternate\n");
fprintf(out, " -d: delay in nanoseconds between demos\n");
fprintf(out, "all demos are run if no specification is provided\n");
fprintf(out, " i: run intro\n");
fprintf(out, " s: run shuffle\n");
fprintf(out, " u: run uniblock\n");
fprintf(out, " m: run maxcolor\n");
fprintf(out, " b: run box\n");
fprintf(out, " g: run grid\n");
fprintf(out, " w: run widecolors\n");
exit(status);
}
static int
ext_demos(struct notcurses* nc){
if(sliding_puzzle_demo(nc)){
return -1;
}
if(unicodeblocks_demo(nc)){
return -1;
}
if(maxcolor_demo(nc)){
return -1;
}
if(box_demo(nc)){
return -1;
}
if(grid_demo(nc)){
return -1;
}
if(widecolor_demo(nc)){
return -1;
}
return 0;
}
static int
handle_opts(int argc, char** argv, notcurses_options* opts){
int c;
memset(opts, 0, sizeof(*opts));
opts->outfp = stdout;
while((c = getopt(argc, argv, "hkd:")) != EOF){
switch(c){
case 'h':
usage(*argv, EXIT_SUCCESS);
break;
case 'k':
opts->inhibit_alternate_screen = true;
break;
case 'd':{
char* eptr;
unsigned long ns = strtoul(optarg, &eptr, 0);
if(*eptr){
usage(*argv, EXIT_FAILURE);
}
demodelay.tv_sec = ns / 1000000000;
demodelay.tv_nsec = ns % 1000000000;
break;
}default:
usage(*argv, EXIT_FAILURE);
}
}
return 0;
}
// just fucking around...for now
int main(int argc, char** argv){
struct notcurses* nc;
notcurses_options nopts;
intro(struct notcurses* nc){
struct ncplane* ncp;
if(!setlocale(LC_ALL, "")){
fprintf(stderr, "Couldn't set locale based on user preferences\n");
return EXIT_FAILURE;
}
if(handle_opts(argc, argv, &nopts)){
return EXIT_FAILURE;
}
if((nc = notcurses_init(&nopts)) == NULL){
return EXIT_FAILURE;
}
if((ncp = notcurses_stdplane(nc)) == NULL){
fprintf(stderr, "Couldn't get standard plane\n");
goto err;
return -1;
}
nanosleep(&demodelay, NULL);
ncplane_erase(ncp);
int x, y, rows, cols;
ncplane_dimyx(ncp, &rows, &cols);
ncplane_dim_yx(ncp, &rows, &cols);
cell c;
cell_init(&c);
const char* cstr = "Δ";
@ -107,10 +50,10 @@ int main(int argc, char** argv){
cell_set_bg(&c, 0, y * ys , 0);
for(x = 5 ; x < cols - 6 ; ++x){
if(ncplane_cursor_move_yx(ncp, y, x)){
goto err;
return -1;
}
if(ncplane_putc(ncp, &c) != (int)strlen(cstr)){
goto err;
return -1;
}
}
}
@ -122,7 +65,7 @@ int main(int argc, char** argv){
cell vl = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER;
if(ncplane_rounded_box_cells(ncp, &ul, &ur, &ll, &lr, &hl, &vl)){
goto err;
return -1;
}
cell_set_fg(&ul, 90, 0, 90);
cell_set_fg(&ur, 90, 0, 90);
@ -137,49 +80,131 @@ int main(int argc, char** argv){
cell_set_bg(&vl, 0, 0, 180);
cell_set_bg(&hl, 0, 0, 180);
if(ncplane_cursor_move_yx(ncp, 4, 4)){
goto err;
return -1;
}
if(ncplane_box(ncp, &ul, &ur, &ll, &lr, &hl, &vl, rows - 6, cols - 6)){
goto err;
return -1;
}
const char s1[] = " Die Welt ist alles, was der Fall ist. ";
const char str[] = " Wovon man nicht sprechen kann, darüber muss man schweigen. ";
if(ncplane_fg_rgb8(ncp, 192, 192, 192)){
goto err;
return -1;
}
if(ncplane_bg_rgb8(ncp, 0, 40, 0)){
goto err;
return -1;
}
if(ncplane_cursor_move_yx(ncp, rows / 2 - 2, (cols - strlen(s1) + 4) / 2)){
goto err;
return -1;
}
if(ncplane_putstr(ncp, s1) != (int)strlen(s1)){
goto err;
return -1;
}
if(ncplane_cursor_move_yx(ncp, rows / 2, (cols - strlen(str) + 4) / 2)){
goto err;
return -1;
}
ncplane_styles_on(ncp, CELL_STYLE_ITALIC);
if(ncplane_putstr(ncp, str) != (int)strlen(str)){
goto err;
return -1;
}
ncplane_styles_off(ncp, CELL_STYLE_ITALIC);
const wchar_t wstr[] = L"▏▁ ▂ ▃ ▄ ▅ ▆ ▇ █ █ ▇ ▆ ▅ ▄ ▃ ▂ ▁▕";
char mbstr[128];
if(wcstombs(mbstr, wstr, sizeof(mbstr)) <= 0){
goto err;
return -1;
}
if(ncplane_cursor_move_yx(ncp, rows / 2 - 5, (cols - wcslen(wstr) + 4) / 2)){
goto err;
return -1;
}
if(ncplane_putstr(ncp, mbstr) != (int)strlen(mbstr)){
goto err;
return -1;
}
if(notcurses_render(nc)){
return -1;
}
nanosleep(&demodelay, NULL);
return 0;
}
static int
ext_demos(struct notcurses* nc, const char* demos){
while(*demos){
int ret = 0;
switch(*demos){
case 'i': ret = intro(nc); break;
case 's': ret = sliding_puzzle_demo(nc); break;
case 'u': ret = unicodeblocks_demo(nc); break;
case 'm': ret = maxcolor_demo(nc); break;
case 'b': ret = box_demo(nc); break;
case 'g': ret = grid_demo(nc); break;
case 'w': ret = widecolor_demo(nc); break;
}
if(ret){
return ret;
}
++demos;
}
return 0;
}
// returns the demos to be run as a string. on error, returns NULL. on no
// specification, also returns NULL, heh. determine this by argv[optind];
// if it's NULL, there were valid options, but no spec.
static const char*
handle_opts(int argc, char** argv, notcurses_options* opts){
int c;
memset(opts, 0, sizeof(*opts));
opts->outfp = stdout;
while((c = getopt(argc, argv, "hkd:")) != EOF){
switch(c){
case 'h':
usage(*argv, EXIT_SUCCESS);
break;
case 'k':
opts->inhibit_alternate_screen = true;
break;
case 'd':{
char* eptr;
unsigned long ns = strtoul(optarg, &eptr, 0);
if(*eptr){
usage(*argv, EXIT_FAILURE);
}
demodelay.tv_sec = ns / 1000000000;
demodelay.tv_nsec = ns % 1000000000;
break;
}default:
usage(*argv, EXIT_FAILURE);
}
}
const char* demos = argv[optind];
return demos;
}
// just fucking around...for now
int main(int argc, char** argv){
srandom(time(NULL)); // a classic blunder
struct notcurses* nc;
notcurses_options nopts;
struct ncplane* ncp;
if(!setlocale(LC_ALL, "")){
fprintf(stderr, "Couldn't set locale based on user preferences\n");
return EXIT_FAILURE;
}
const char* demos;
if((demos = handle_opts(argc, argv, &nopts)) == NULL){
if(argv[optind] != NULL){
usage(*argv, EXIT_FAILURE);
}
demos = "isumbgw";
}
if((nc = notcurses_init(&nopts)) == NULL){
return EXIT_FAILURE;
}
if((ncp = notcurses_stdplane(nc)) == NULL){
fprintf(stderr, "Couldn't get standard plane\n");
goto err;
}
nanosleep(&demodelay, NULL);
if(ext_demos(nc)){
if(ext_demos(nc, demos)){
goto err;
}
if(notcurses_stop(nc)){

@ -75,7 +75,7 @@ static int
gridswitch_demo(struct notcurses* nc, struct ncplane *n){
ncplane_erase(n);
int maxx, maxy;
notcurses_term_dimyx(nc, &maxy, &maxx);
notcurses_term_dim_yx(nc, &maxy, &maxx);
int rs = 256 / maxx;
int gs = 256 / (maxx + maxy);
int bs = 256 / maxy;
@ -140,7 +140,7 @@ static int
gridinv_demo(struct notcurses* nc, struct ncplane *n){
ncplane_erase(n);
int maxx, maxy;
notcurses_term_dimyx(nc, &maxy, &maxx);
notcurses_term_dim_yx(nc, &maxy, &maxx);
int rs = 256 / maxx;
int gs = 256 / (maxx + maxy);
int bs = 256 / maxy;
@ -204,7 +204,7 @@ gridinv_demo(struct notcurses* nc, struct ncplane *n){
// red across, blue down, green from UL to LR
int grid_demo(struct notcurses* nc){
int maxx, maxy;
notcurses_term_dimyx(nc, &maxy, &maxx);
notcurses_term_dim_yx(nc, &maxy, &maxx);
int rs = 256 / maxx;
int gs = 256 / (maxx + maxy);
int bs = 256 / maxy;

@ -30,7 +30,7 @@ grow_rgb(uint32_t* rgb){
// and that we can write to every coordinate.
int maxcolor_demo(struct notcurses* nc){
int maxx, maxy;
notcurses_term_dimyx(nc, &maxy, &maxx);
notcurses_term_dim_yx(nc, &maxy, &maxx);
struct ncplane* n = notcurses_stdplane(nc);
ncplane_fg_rgb8(n, 255, 255, 255);
cell ul = CELL_TRIVIAL_INITIALIZER;

@ -4,14 +4,66 @@
#include "demo.h"
// FIXME do the bigger dimension on the screen's bigger dimension
#define CHUNKS_VERT 8
#define CHUNKS_HORZ 16
#define CHUNKS_VERT 6
#define CHUNKS_HORZ 12
#define MOVES 45
#define GIG 1000000000
// we take (MOVES / 5) * demodelay to play MOVES moves
static int
play(struct notcurses* nc, struct ncplane** chunks){
const int chunkcount = CHUNKS_VERT * CHUNKS_HORZ;
uint64_t movens = (MOVES / 5) * (demodelay.tv_sec * GIG + demodelay.tv_nsec);
struct timespec movetime = {
.tv_sec = movens / MOVES / GIG,
.tv_nsec = movens / MOVES % GIG,
};
// struct ncplane* n = notcurses_stdplane(nc);
int hole = random() % chunkcount;
int holex, holey;
ncplane_yx(chunks[hole], &holey, &holex);
ncplane_destroy(chunks[hole]);
chunks[hole] = NULL;
int m;
int lastdir = -1;
for(m = 0 ; m < MOVES ; ++m){
int mover = chunkcount;
int direction;
do{
direction = random() % 4;
switch(direction){
case 3: // up
if(lastdir != 1 && hole >= CHUNKS_HORZ){ mover = hole - CHUNKS_HORZ; } break;
case 2: // right
if(lastdir != 0 && hole % CHUNKS_HORZ < CHUNKS_HORZ - 1){ mover = hole + 1; } break;
case 1: // down
if(lastdir != 3 && hole < chunkcount - CHUNKS_HORZ){ mover = hole + CHUNKS_HORZ; } break;
case 0: // left
if(lastdir != 2 && hole % CHUNKS_HORZ){ mover = hole - 1; } break;
}
}while(mover == chunkcount);
lastdir = direction;
int newholex, newholey;
ncplane_yx(chunks[mover], &newholey, &newholex);
ncplane_move_yx(chunks[mover], holey, holex);
holey = newholey;
holex = newholex;
chunks[hole] = chunks[mover];
chunks[mover] = NULL;
hole = mover;
if(notcurses_render(nc)){
return -1;
}
nanosleep(&movetime, NULL);
}
return 0;
}
static int
fill_chunk(struct ncplane* n, int idx){
char buf[4];
int maxy, maxx;
ncplane_dimyx(n, &maxy, &maxx);
ncplane_dim_yx(n, &maxy, &maxx);
snprintf(buf, sizeof(buf), "%03d", idx);
cell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
cell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
@ -19,15 +71,7 @@ fill_chunk(struct ncplane* n, int idx){
if(ncplane_double_box_cells(n, &ul, &ur, &ll, &lr, &hl, &vl)){
return -1;
}
int r = 255, g = 255, b = 255;
switch(idx % 6){
case 5: r -= (idx % 64) * 4; break;
case 4: g -= (idx % 64) * 4; break;
case 3: b -= (idx % 64) * 4; break;
case 2: r -= (idx % 64) * 4; b -= (idx % 64) * 4; break;
case 1: r -= (idx % 64) * 4; g -= (idx % 64) * 4; break;
case 0: b -= (idx % 64) * 4; g -= (idx % 64) * 4; break;
}
int r = random() % 256, g = random() % 256, b = random() % 256;
cell_set_fg(&ul, r, g, b);
cell_set_fg(&ur, r, g, b);
cell_set_fg(&ll, r, g, b);
@ -55,6 +99,36 @@ fill_chunk(struct ncplane* n, int idx){
return 0;
}
static int
draw_bounding_box(struct ncplane* n, int yoff, int xoff, int chunky, int chunkx){
int ret = -1;
cell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
cell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER, vl = CELL_TRIVIAL_INITIALIZER;
if(ncplane_rounded_box_cells(n, &ul, &ur, &ll, &lr, &hl, &vl)){
return -1;
}
cell_set_fg(&ul, 180, 80, 180);
cell_set_fg(&ur, 180, 80, 180);
cell_set_fg(&ll, 180, 80, 180);
cell_set_fg(&lr, 180, 80, 180);
cell_set_fg(&hl, 180, 80, 180);
cell_set_fg(&vl, 180, 80, 180);
ncplane_cursor_move_yx(n, yoff, xoff);
if(!ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl,
CHUNKS_VERT * chunky + yoff + 1,
CHUNKS_HORZ * chunkx + xoff + 1)){
ret = 0;
}
cell_release(n, &ul);
cell_release(n, &ur);
cell_release(n, &ll);
cell_release(n, &lr);
cell_release(n, &hl);
cell_release(n, &vl);
return ret;
}
// break whatever's on the screen into panels and shift them around like a
// sliding puzzle. FIXME once we have copying, anyway. until then, just use
// background colors.
@ -62,17 +136,21 @@ int sliding_puzzle_demo(struct notcurses* nc){
int ret = -1, z;
int maxx, maxy;
int chunky, chunkx;
notcurses_term_dimyx(nc, &maxy, &maxx);
notcurses_term_dim_yx(nc, &maxy, &maxx);
// want at least 2x2 for each sliding chunk
if(maxy < CHUNKS_VERT * 2 || maxx < CHUNKS_HORZ * 2){
fprintf(stderr, "Terminal too small, need at least %dx%d\n",
CHUNKS_HORZ, CHUNKS_VERT);
return -1;
}
// we want an 8x8 grid of chunks. the leftover space will be unused
chunky = maxy / CHUNKS_VERT;
chunkx = maxx / CHUNKS_HORZ;
int chunkcount = CHUNKS_VERT * CHUNKS_HORZ;
// we want an 8x8 grid of chunks with a border. the leftover space will be unused
chunky = (maxy - 2) / CHUNKS_VERT;
chunkx = (maxx - 2) / CHUNKS_HORZ;
int wastey = ((maxy - 2) % CHUNKS_VERT) / 2;
int wastex = ((maxx - 2) % CHUNKS_HORZ) / 2;
struct ncplane* n = notcurses_stdplane(nc);
ncplane_erase(n);
const int chunkcount = CHUNKS_VERT * CHUNKS_HORZ;
struct ncplane** chunks = malloc(sizeof(*chunks) * chunkcount);
if(chunks == NULL){
return -1;
@ -83,22 +161,28 @@ int sliding_puzzle_demo(struct notcurses* nc){
for(cx = 0 ; cx < CHUNKS_HORZ ; ++cx){
const int idx = cy * CHUNKS_HORZ + cx;
chunks[idx] =
notcurses_newplane(nc, chunky, chunkx, cy * chunky, cx * chunkx, NULL);
notcurses_newplane(nc, chunky, chunkx, cy * chunky + wastey + 1,
cx * chunkx + wastex + 1, NULL);
if(chunks[idx] == NULL){
goto done;
}
fill_chunk(chunks[idx], idx);
}
}
if(draw_bounding_box(n, wastey, wastex, chunky, chunkx)){
return -1;
}
if(notcurses_render(nc)){
goto done;
}
nanosleep(&demodelay, NULL);
if(play(nc, chunks)){
goto done;
}
ret = 0;
done:
for(z = 0 ; z < chunkcount ; ++z){
ncplane_destroy(nc, chunks[z]);
ncplane_destroy(chunks[z]);
}
free(chunks);
return ret;

@ -13,7 +13,7 @@
int unicodeblocks_demo(struct notcurses* nc){
struct ncplane* n = notcurses_stdplane(nc);
int maxx, maxy;
notcurses_term_dimyx(nc, &maxy, &maxx);
notcurses_term_dim_yx(nc, &maxy, &maxx);
// some blocks are good for the printing, some less so. some are only
// marginally covered by mainstream fonts, some not at all. we explicitly
// list the ones we want.

@ -7,6 +7,7 @@
static int
message(struct ncplane* n, int maxy, int maxx, int num, int total){
ncplane_bg_default(n);
cell ul, ur, ll, lr, vl, hl;
cell_init(&ul);
cell_init(&ur);
@ -19,9 +20,8 @@ message(struct ncplane* n, int maxy, int maxx, int num, int total){
}
ncplane_cursor_move_yx(n, 3, 1);
ncplane_fg_rgb8(n, 255, 255, 255);
ncplane_bg_rgb8(n, 0, 20, 0);
ncplane_styles_on(n, CELL_STYLE_BOLD);
if(ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, 5, 54)){
if(ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, 5, 56)){
return -1;
}
cell_load(n, &ll, "");
@ -41,13 +41,12 @@ message(struct ncplane* n, int maxy, int maxx, int num, int total){
ncplane_hline(n, &hl, 13);
cell_load(n, &ur, "");
ncplane_putc(n, &ur);
ncplane_bg_rgb8(n, 0, 0, 0);
ncplane_cursor_move_yx(n, 2, 5);
ncplane_printf(n, " %dx%d (%d/%d) ", maxx, maxy, num, total);
ncplane_cursor_move_yx(n, 4, 2);
ncplane_styles_off(n, CELL_STYLE_BOLD);
ncplane_fg_rgb8(n, 200, 20, 200);
ncplane_putstr(n, " 🔥wide chars, multiple colors, resize awareness…🔥 ");
ncplane_putstr(n, " 🔥wide chars, multiple colors, resize awareness…🔥 ");
return 0;
}
@ -261,7 +260,7 @@ int widecolor_demo(struct notcurses* nc){
const int step = steps[i];
//do{
int y, x, maxy, maxx;
ncplane_dimyx(n, &maxy, &maxx);
ncplane_dim_yx(n, &maxy, &maxx);
int rgb = start;
if(ncplane_cursor_move_yx(n, 0, 0)){
return -1;

@ -106,7 +106,7 @@ ncvisual* ncplane_visual_open(struct ncplane* nc, const char* filename){
fprintf(stderr, "Couldn't create %s (%s)\n", filename, strerror(errno));
return NULL;
}
ncplane_dimyx(nc, &ncv->dstheight, &ncv->dstwidth);
ncplane_dim_yx(nc, &ncv->dstheight, &ncv->dstwidth);
int ret = avformat_open_input(&ncv->fmtctx, filename, NULL, NULL);
if(ret < 0){
fprintf(stderr, "Couldn't open %s (%s)\n", filename, av_err2str(ret));

@ -43,6 +43,7 @@ typedef struct ncplane {
uint64_t channels; // works the same way as cells
uint32_t attrword; // same deal as in a cell
void* userptr; // slot for the user to stick some opaque pointer
struct notcurses* nc; // notcurses object of which we are a part
} ncplane;
typedef struct ncstats {
@ -200,7 +201,7 @@ const void* ncplane_userptr_const(const ncplane* n){
return n->userptr;
}
void ncplane_dimyx(const ncplane* n, int* rows, int* cols){
void ncplane_dim_yx(const ncplane* n, int* rows, int* cols){
if(rows){
*rows = n->leny;
}
@ -296,6 +297,7 @@ ncplane_create(notcurses* nc, int rows, int cols, int yoff, int xoff){
egcpool_init(&p->pool);
p->z = nc->top;
nc->top = p;
p->nc = nc;
return p;
}
@ -315,6 +317,7 @@ create_initial_ncplane(notcurses* nc){
// array of *rows * *cols cells (may be NULL if *rows == *cols == 0). Gets the
// new size, and copies what can be copied from the old stdscr. Assumes that
// the screen is always anchored in the same place.
// FIXME rewrite this in terms of ncpanel_resize(n->stdscr)
int notcurses_resize(notcurses* n){
int oldrows = n->stdscr->leny;
int oldcols = n->stdscr->lenx;
@ -372,21 +375,113 @@ ncplane* notcurses_newplane(notcurses* nc, int rows, int cols,
return n;
}
int ncplane_destroy(notcurses* nc, ncplane* ncp){
int ncplane_resize(ncplane* n, int keepy, int keepx, int keepleny,
int keeplenx, int yoff, int xoff, int ylen, int xlen){
if(n == n->nc->stdscr){
return -1;
}
if(keepy < 0 || keepx < 0){ // can't retain negative size
return -1;
}
if(ylen <= 0 || xlen <= 0){ // can't resize to trivial or negative size
return -1;
}
if((!keepy && keepx) || (keepy && !keepx)){ // both must be 0
return -1;
}
if(ylen < keepleny || xlen < keeplenx){ // can't be smaller than our keep
return -1;
}
// we're good to resize. we'll need alloc up a new framebuffer, and copy in
// those elements we're retaining, zeroing out the rest. alternatively, if
// we've shrunk, we will be filling the new structure.
int keptarea = keepy * keepx;
int newarea = ylen * xlen;
cell* fb = malloc(sizeof(*fb) * newarea);
if(fb == NULL){
return -1;
}
// update the cursor, if it would otherwise be off-plane
if(n->y >= ylen){
n->y = ylen - 1;
}
if(n->x >= xlen){
n->x = xlen - 1;
}
cell* preserved = n->fb;
n->fb = fb;
n->absy = n->absy + keepy - yoff;
n->absx = n->absx + keepx - xoff;
// if we're keeping nothing, dump the old egcspool. otherwise, we go ahead
// and keep it. perhaps we ought compact it?
if(keptarea == 0){ // keep nothing, resize/move only
memset(fb, 0, sizeof(*fb) * newarea);
egcpool_dump(&n->pool);
n->lenx = xlen;
n->leny = ylen;
free(preserved);
return 0;
}
// we currently have maxy rows of maxx cells each. we will be keeping rows
// keepy..keepy + keepleny - 1 and columns keepx..keepx + keeplenx - 1. they
// will end up at keepy + yoff..keepy + keepleny - 1 + yoff and
// keepx + xoff..keepx + keeplenx - 1 + xoff. everything else is zerod out.
int itery;
// we'll prepare each cell in our new framebuffer with either zeroes or a copy
// from the old one.
int sourceline = keepy;
for(itery = 0 ; itery < ylen ; ++itery){
int copyoff = itery * xlen; // our target at any given time
// if we have nothing copied to this line, zero it out in one go
if(itery < keepy + yoff || itery > keepy + keepleny - 1 + yoff){
memset(fb + copyoff, 0, sizeof(*fb) * xlen);
continue;
}
// we do have something to copy, and zero, one, or two regions to zero out
int copied = 0;
if(xoff < 0){
memset(fb + copyoff, 0, sizeof(*fb) * -xoff);
copyoff += -xoff;
copied += -xoff;
}
const int sourceidx = fbcellidx(n, sourceline, keepx);
memcpy(fb + copyoff, preserved + sourceidx, sizeof(*fb) * keepx);
copyoff += keepx;
copied += keepx;
if(xlen > copied){
memset(fb + copyoff, 0, sizeof(*fb) * (xlen - copied));
}
++sourceline;
}
free(preserved);
return 0;
}
static ncplane**
find_above_ncplane(ncplane* n){
notcurses* nc = n->nc;
ncplane** above = &nc->top;
while(*above){
if(*above == n){
return above;
}
above = &(*above)->z;
}
return NULL;
}
int ncplane_destroy(ncplane* ncp){
if(ncp == NULL){
return 0;
}
if(nc->stdscr == ncp){
if(ncp->nc->stdscr == ncp){
return -1;
}
ncplane** above;
// pull it out of the list
for(above = &nc->top ; *above ; above = &(*above)->z){
if(*above == ncp){
*above = ncp->z;
free_plane(ncp);
return 0;
}
ncplane** above = find_above_ncplane(ncp);
if(*above){
*above = ncp->z; // splice it out of the list
free_plane(ncp);
return 0;
}
// couldn't find it in our stack. don't try to free this interloper.
return -1;
@ -570,26 +665,20 @@ int notcurses_stop(notcurses* nc){
return ret;
}
void ncplane_fg_default(struct ncplane* n){
n->channels |= CELL_FGDEFAULT_MASK;
}
void ncplane_bg_default(struct ncplane* n){
n->channels |= CELL_BGDEFAULT_MASK;
}
int ncplane_bg_rgb8(ncplane* n, int r, int g, int b){
if(r >= 256 || g >= 256 || b >= 256){
return -1;
}
if(r < 0 || g < 0 || b < 0){
return -1;
}
cell_rgb_set_bg(&n->channels, r, g, b);
return 0;
return cell_rgb_set_bg(&n->channels, r, g, b);
}
int ncplane_fg_rgb8(ncplane* n, int r, int g, int b){
if(r >= 256 || g >= 256 || b >= 256){
return -1;
}
if(r < 0 || g < 0 || b < 0){
return -1;
}
cell_rgb_set_fg(&n->channels, r, g, b);
return 0;
return cell_rgb_set_fg(&n->channels, r, g, b);
}
// 3 for foreground, 4 for background, ugh FIXME
@ -804,6 +893,60 @@ visible_cell(const notcurses* nc, int y, int x, const ncplane** retp){
return NULL;
}
// 'n' ends up above 'above'
int ncplane_move_above(ncplane* restrict n, ncplane* restrict above){
ncplane** an = find_above_ncplane(n);
if(an == NULL){
return -1;
}
ncplane** aa = find_above_ncplane(above);
if(aa == NULL){
return -1;
}
*an = n->z; // splice n out
n->z = above; // attach above below n
*aa = n; // spline n in above
return 0;
}
// 'n' ends up below 'below'
int ncplane_move_below(ncplane* restrict n, ncplane* restrict below){
ncplane** an = find_above_ncplane(n);
if(an == NULL){
return -1;
}
*an = n->z; // splice n out
n->z = below->z; // reattach subbelow list to n
below->z = n; // splice n in below
return 0;
}
int ncplane_move_top(ncplane* n){
ncplane** an = find_above_ncplane(n);
if(an == NULL){
return -1;
}
*an = n->z; // splice n out
n->z = n->nc->top;
n->nc->top = n;
return 0;
}
int ncplane_move_bottom(ncplane* n){
ncplane** an = find_above_ncplane(n);
if(an == NULL){
return -1;
}
*an = n->z; // splice n out
an = &n->nc->top;
while(*an){
an = &(*an)->z;
}
*an = n;
n->z = NULL;
return 0;
}
// FIXME this needs to keep an invalidation bitmap, rather than blitting the
// world every time
int notcurses_render(notcurses* nc){
@ -821,6 +964,8 @@ int notcurses_render(notcurses* nc){
term_emit(nc->clear, out, false);
for(y = 0 ; y < nc->stdscr->leny ; ++y){
// FIXME previous line could have ended halfway through multicol. what happens?
// FIXME also must explicitly move to next line if we're to deal with
// surprise enlargenings, otherwise we just print forward
for(x = 0 ; x < nc->stdscr->lenx ; ++x){
unsigned r, g, b, br, bg, bb;
const ncplane* p;
@ -1078,7 +1223,7 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
if(xstop < xoff + 1){
return -1;
}
ncplane_dimyx(n, &ymax, &xmax);
ncplane_dim_yx(n, &ymax, &xmax);
if(xstop >= xmax || ystop >= ymax){
return -1;
}
@ -1126,6 +1271,16 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
return 0;
}
void ncplane_move_yx(ncplane* n, int y, int x){
n->absy = y;
n->absx = x;
}
void ncplane_yx(const ncplane* n, int* y, int* x){
*y = n->absy;
*x = n->absx;
}
void ncplane_erase(ncplane* n){
memset(n->fb, 0, sizeof(*n->fb) * n->lenx * n->leny);
egcpool_dump(&n->pool);

@ -38,9 +38,9 @@ TEST_F(NcplaneTest, StdPlanePosition) {
// Dimensions of the standard plane ought be the same as those of the context
TEST_F(NcplaneTest, StdPlaneDimensions) {
int cols, rows;
notcurses_term_dimyx(nc_, &rows, &cols);
notcurses_term_dim_yx(nc_, &rows, &cols);
int ncols, nrows;
ncplane_dimyx(n_, &nrows, &ncols);
ncplane_dim_yx(n_, &nrows, &ncols);
EXPECT_EQ(rows, nrows);
EXPECT_EQ(cols, ncols);
}
@ -48,7 +48,7 @@ TEST_F(NcplaneTest, StdPlaneDimensions) {
// Verify that we can move to all four coordinates of the standard plane
TEST_F(NcplaneTest, MoveStdPlaneDimensions) {
int cols, rows;
notcurses_term_dimyx(nc_, &rows, &cols);
notcurses_term_dim_yx(nc_, &rows, &cols);
EXPECT_EQ(0, ncplane_cursor_move_yx(n_, 0, 0));
int x, y;
ncplane_cursor_yx(n_, &y, &x);
@ -71,7 +71,7 @@ TEST_F(NcplaneTest, MoveStdPlaneDimensions) {
// Verify that we can move to all four coordinates of the standard plane
TEST_F(NcplaneTest, MoveBeyondPlaneFails) {
int cols, rows;
notcurses_term_dimyx(nc_, &rows, &cols);
notcurses_term_dim_yx(nc_, &rows, &cols);
EXPECT_NE(0, ncplane_cursor_move_yx(n_, -1, 0));
EXPECT_NE(0, ncplane_cursor_move_yx(n_, -1, -1));
EXPECT_NE(0, ncplane_cursor_move_yx(n_, 0, -1));
@ -128,7 +128,7 @@ TEST_F(NcplaneTest, EmitStr) {
TEST_F(NcplaneTest, HorizontalLines) {
int x, y;
ncplane_dimyx(n_, &y, &x);
ncplane_dim_yx(n_, &y, &x);
ASSERT_LT(0, y);
ASSERT_LT(0, x);
cell c{};
@ -147,7 +147,7 @@ TEST_F(NcplaneTest, HorizontalLines) {
TEST_F(NcplaneTest, VerticalLines) {
int x, y;
ncplane_dimyx(n_, &y, &x);
ncplane_dim_yx(n_, &y, &x);
ASSERT_LT(0, y);
ASSERT_LT(0, x);
cell c{};
@ -167,7 +167,7 @@ TEST_F(NcplaneTest, VerticalLines) {
// reject attempts to draw boxes beyond the boundaries of the ncplane
TEST_F(NcplaneTest, BadlyPlacedBoxen) {
int x, y;
ncplane_dimyx(n_, &y, &x);
ncplane_dim_yx(n_, &y, &x);
ASSERT_LT(2, y);
ASSERT_LT(2, x);
cell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
@ -188,7 +188,7 @@ TEST_F(NcplaneTest, BadlyPlacedBoxen) {
TEST_F(NcplaneTest, PerimeterBox) {
int x, y;
ncplane_dimyx(n_, &y, &x);
ncplane_dim_yx(n_, &y, &x);
ASSERT_LT(2, y);
ASSERT_LT(2, x);
cell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
@ -205,7 +205,7 @@ TEST_F(NcplaneTest, PerimeterBox) {
TEST_F(NcplaneTest, PerimeterBoxSized) {
int x, y;
ncplane_dimyx(n_, &y, &x);
ncplane_dim_yx(n_, &y, &x);
ASSERT_LT(2, y);
ASSERT_LT(2, x);
cell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
@ -293,7 +293,7 @@ TEST_F(NcplaneTest, UserPtr) {
EXPECT_EQ(nullptr, ncplane_userptr(n_));
int x, y;
void* sentinel = &x;
notcurses_term_dimyx(nc_, &y, &x);
notcurses_term_dim_yx(nc_, &y, &x);
struct ncplane* ncp = notcurses_newplane(nc_, y, x, 0, 0, sentinel);
ASSERT_NE(ncp, nullptr);
EXPECT_EQ(&x, ncplane_userptr(ncp));
@ -302,23 +302,92 @@ TEST_F(NcplaneTest, UserPtr) {
sentinel = &y;
EXPECT_EQ(nullptr, ncplane_set_userptr(ncp, sentinel));
EXPECT_EQ(&y, ncplane_userptr(ncp));
EXPECT_EQ(0, ncplane_destroy(nc_, ncp));
EXPECT_EQ(0, ncplane_destroy(ncp));
}
// create a new plane, the same size as the terminal, and verify that it
// occupies the same dimensions as the standard plane.
TEST_F(NcplaneTest, NewPlaneSameSize) {
int x, y;
notcurses_term_dimyx(nc_, &y, &x);
notcurses_term_dim_yx(nc_, &y, &x);
struct ncplane* ncp = notcurses_newplane(nc_, y, x, 0, 0, nullptr);
ASSERT_NE(nullptr, ncp);
int px, py;
ncplane_dimyx(ncp, &py, &px);
ncplane_dim_yx(ncp, &py, &px);
EXPECT_EQ(y, py);
EXPECT_EQ(x, px);
int sx, sy;
ncplane_dimyx(n_, &sy, &sx);
ncplane_dim_yx(n_, &sy, &sx);
EXPECT_EQ(sy, py);
EXPECT_EQ(sx, px);
EXPECT_EQ(0, ncplane_destroy(nc_, ncp));
EXPECT_EQ(0, ncplane_destroy(ncp));
}
TEST_F(NcplaneTest, ShrinkPlane) {
int maxx, maxy;
int x = 0, y = 0;
notcurses_term_dim_yx(nc_, &maxy, &maxx);
struct ncplane* newp = notcurses_newplane(nc_, maxy, maxx, y, x, nullptr);
ASSERT_NE(nullptr, newp);
while(y > 4 && x > 4){
maxx -= 2;
maxy -= 2;
++x;
++y;
ASSERT_EQ(0, ncplane_resize(newp, 1, 1, maxy, maxx, 1, 1, maxy, maxx));
// FIXME check dims, pos
}
while(y > 4){
maxy -= 2;
++y;
ASSERT_EQ(0, ncplane_resize(newp, 1, 0, maxy, maxx, 1, 0, maxy, maxx));
// FIXME check dims, pos
}
while(x > 4){
maxx -= 2;
++x;
ASSERT_EQ(0, ncplane_resize(newp, 0, 1, maxy, maxx, 0, 1, maxy, maxx));
// FIXME check dims, pos
}
ASSERT_EQ(0, ncplane_resize(newp, 0, 0, 0, 0, 0, 0, 2, 2));
// FIXME check dims, pos
ASSERT_EQ(0, ncplane_destroy(newp));
}
TEST_F(NcplaneTest, GrowPlane) {
int maxx = 2, maxy = 2;
int x = 0, y = 0;
int dimy, dimx;
notcurses_term_dim_yx(nc_, &dimy, &dimx);
x = dimx / 2 - 1;
y = dimy / 2 - 1;
struct ncplane* newp = notcurses_newplane(nc_, maxy, maxx, y, x, nullptr);
ASSERT_NE(nullptr, newp);
while(dimx - maxx > 4 && dimy - maxy > 4){
maxx += 2;
maxy += 2;
--x;
--y;
// ASSERT_EQ(0, ncplane_resize(newp, 1, 1, maxy, maxx, 1, 1, maxy, maxx));
// FIXME check dims, pos
}
while(y < dimy){
++maxy;
if(y){
++y;
}
// ASSERT_EQ(0, ncplane_resize(newp, 1, 0, maxy, maxx, 1, 0, maxy, maxx));
// FIXME check dims, pos
}
while(x < dimx){
++maxx;
if(x){
++x;
}
// ASSERT_EQ(0, ncplane_resize(newp, 0, 1, maxy, maxx, 0, 1, maxy, maxx));
// FIXME check dims, pos
}
ASSERT_EQ(0, ncplane_resize(newp, 0, 0, 0, 0, 0, 0, dimy, dimx));
// FIXME check dims, pos
ASSERT_EQ(0, ncplane_destroy(newp));
}

@ -37,7 +37,7 @@ TEST_F(NotcursesTest, BasicLifetime) {
TEST_F(NotcursesTest, TermDimensions) {
int x, y;
notcurses_term_dimyx(nc_, &y, &x);
notcurses_term_dim_yx(nc_, &y, &x);
auto stry = getenv("LINES");
if(stry){
auto envy = std::stoi(stry, nullptr);
@ -52,10 +52,10 @@ TEST_F(NotcursesTest, TermDimensions) {
TEST_F(NotcursesTest, ResizeSameSize) {
int x, y;
notcurses_term_dimyx(nc_, &y, &x);
notcurses_term_dim_yx(nc_, &y, &x);
EXPECT_EQ(0, notcurses_resize(nc_));
int newx, newy;
notcurses_term_dimyx(nc_, &newy, &newx);
notcurses_term_dim_yx(nc_, &newy, &newx);
EXPECT_EQ(newx, x);
EXPECT_EQ(newy, y);
}
@ -70,13 +70,13 @@ TEST_F(NotcursesTest, CursesStyles) {
TEST_F(NotcursesTest, RejectDestroyStdPlane) {
ncplane* ncp = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, ncp);
ASSERT_NE(0, ncplane_destroy(nc_, ncp));
ASSERT_NE(0, ncplane_destroy(ncp));
}
// create planes partitioning the entirety of the screen, one at each coordinate
TEST_F(NotcursesTest, TileScreenWithPlanes) {
int maxx, maxy;
notcurses_term_dimyx(nc_, &maxy, &maxx);
notcurses_term_dim_yx(nc_, &maxy, &maxx);
auto total = maxx * maxy;
struct ncplane** planes = new struct ncplane*[total];
int* planesecrets = new int[total];
@ -94,7 +94,7 @@ TEST_F(NotcursesTest, TileScreenWithPlanes) {
auto userptr = ncplane_userptr(planes[idx]);
ASSERT_NE(nullptr, userptr);
EXPECT_EQ(userptr, &planesecrets[idx]);
ASSERT_EQ(0, ncplane_destroy(nc_, planes[idx]));
ASSERT_EQ(0, ncplane_destroy(planes[idx]));
}
}
delete[] planesecrets;

Loading…
Cancel
Save