diff --git a/NEWS.md b/NEWS.md index 4c4346ede..70072d276 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,13 @@ rearrangements of Notcurses. * 1.4.2 (not yet released) * Added `notcurses_canutf8()`, to verify use of UTF-8 encoding. + * Fixed bug in `ncvisual_from_plane()` when invoked on the standard plane. + * `ncvisual_from_plane()` now accepts the same four geometric parameters + as other plane selectors. To reproduce the old behavior, for `ncv`, call + it as `ncvisual_from_plane(ncv, 0, 0, -1, -1)`. + * `ncvisual_from_plane()`, `ncplane_move_below_unsafe()`, `ncplane_dup()`, + and `ncplane_move_above_unsafe()` now accept `const` arguments where they + did not before. * 1.4.1 (2020-05-11) * No user-visible changes (fixed two unit tests). diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 6835cdac5..ed166c0e2 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -990,7 +990,7 @@ API struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparen // Duplicate an existing ncplane. The new plane will have the same geometry, // will duplicate all content, and will start with the same rendering state. // The new plane will be immediately above the old one on the z axis. -API struct ncplane* ncplane_dup(struct ncplane* n, void* opaque); +API struct ncplane* ncplane_dup(const struct ncplane* n, void* opaque); // provided a coordinate relative to the origin of 'src', map it to the same // absolute coordinate relative to thte origin of 'dst'. either or both of 'y' @@ -1126,7 +1126,7 @@ API int ncplane_move_bottom(struct ncplane* n); // Splice ncplane 'n' out of the z-buffer, and reinsert it above 'above'. API int ncplane_move_above_unsafe(struct ncplane* RESTRICT n, - struct ncplane* RESTRICT above); + const struct ncplane* RESTRICT above); static inline int ncplane_move_above(struct ncplane* n, struct ncplane* above){ @@ -1138,7 +1138,7 @@ ncplane_move_above(struct ncplane* n, struct ncplane* above){ // Splice ncplane 'n' out of the z-buffer, and reinsert it below 'below'. API int ncplane_move_below_unsafe(struct ncplane* RESTRICT n, - struct ncplane* RESTRICT below); + const struct ncplane* RESTRICT below); static inline int ncplane_move_below(struct ncplane* n, struct ncplane* below){ @@ -2802,7 +2802,8 @@ API int ncplane_qrcode(struct ncplane* n, int maxversion, const void* data, size // in a NULL being returned. This function exists so that planes can be // subjected to ncvisual transformations. If possible, it's usually better // to create the ncvisual from memory using ncvisual_from_rgba(). -API struct ncvisual* ncvisual_from_plane(struct ncplane* n); +API struct ncvisual* ncvisual_from_plane(const struct ncplane* n, + int begy, int begx, int leny, int lenx); #define NCREADER_OPTION_HORSCROLL 0x0001 #define NCREADER_OPTION_VERSCROLL 0x0002 diff --git a/src/demo/normal.c b/src/demo/normal.c index 6915ef82b..ed1f60585 100644 --- a/src/demo/normal.c +++ b/src/demo/normal.c @@ -36,6 +36,7 @@ offset(uint32_t* rgba, int y, int x, int dx){ int normal_demo(struct notcurses* nc){ int dy, dx; struct ncplane* n = notcurses_stddim_yx(nc, &dy, &dx); + ncplane_erase(n); dy *= VSCALE; // double-block trick means both 2x resolution and even linecount yay uint32_t* rgba = malloc(sizeof(*rgba) * dy * dx); if(!rgba){ @@ -66,5 +67,20 @@ int normal_demo(struct notcurses* nc){ DEMO_RENDER(nc); } free(rgba); + struct ncvisual* ncv = ncvisual_from_plane(n, 0, 0, -1, -1); + if(!ncv){ + return -1; + } + // FIXME use smaller rotations once supported + for(int i = 1 ; i < 4 ; ++i){ + if(ncvisual_rotate(ncv, M_PI / 2)){ + return -1; + } + if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ + return -1; + } + DEMO_RENDER(nc); + } + ncvisual_destroy(ncv); return 0; } diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index a18ac4e21..4fc11fdb3 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -367,7 +367,7 @@ inline int ncplane_cursor_move_yx(ncplane* n, int y, int x){ return 0; } -ncplane* ncplane_dup(ncplane* n, void* opaque){ +ncplane* ncplane_dup(const ncplane* n, void* opaque){ int dimy = n->leny; int dimx = n->lenx; int aty = n->absy; @@ -383,8 +383,8 @@ ncplane* ncplane_dup(ncplane* n, void* opaque){ return NULL; }else{ ncplane_cursor_move_yx(newn, y, x); - n->attrword = attr; - n->channels = chan; + newn->attrword = attr; + newn->channels = chan; ncplane_move_above_unsafe(newn, n); memmove(newn->fb, n->fb, sizeof(*n->fb) * dimx * dimy); } @@ -499,7 +499,7 @@ int ncplane_resize(ncplane* n, int keepy, int keepx, int keepleny, // find the pointer on the z-index referencing the specified plane. writing to // this pointer will remove the plane (and everything below it) from the stack. static ncplane** -find_above_ncplane(ncplane* n){ +find_above_ncplane(const ncplane* n){ notcurses* nc = n->nc; ncplane** above = &nc->top; while(*above){ @@ -1189,7 +1189,7 @@ const char* cell_extended_gcluster(const ncplane* n, const cell* c){ } // 'n' ends up above 'above' -int ncplane_move_above_unsafe(ncplane* restrict n, ncplane* restrict above){ +int ncplane_move_above_unsafe(ncplane* restrict n, const ncplane* restrict above){ if(n->z == above){ return 0; } @@ -1201,24 +1201,37 @@ int ncplane_move_above_unsafe(ncplane* restrict n, ncplane* restrict above){ if(aa == NULL){ return -1; } + ncplane* deconst_above = *aa; *an = n->z; // splice n out - n->z = above; // attach above below n + n->z = deconst_above; // attach above below n *aa = n; // spline n in above return 0; } // 'n' ends up below 'below' -int ncplane_move_below_unsafe(ncplane* restrict n, ncplane* restrict below){ +int ncplane_move_below_unsafe(ncplane* restrict n, const ncplane* restrict below){ if(below->z == n){ return 0; } - ncplane** an = find_above_ncplane(n); + ncplane* deconst_below = NULL; + ncplane** an = &n->nc->top; + // go down, looking for n and below. if we find below, mark it. if we + // find n, break from the loop. + while(*an){ + if(*an == below){ + deconst_below = *an; + }else if(*an == n){ + *an = n->z; // splice n out + } + } 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 + while(deconst_below != below){ + deconst_below = deconst_below->z; + } + n->z = deconst_below->z; // reattach subbelow list to n + deconst_below->z = n; // splice n in below return 0; } @@ -2054,7 +2067,7 @@ uint32_t* ncplane_rgba(const ncplane* nc, int begy, int begx, int leny, int lenx // FIXME how do we deal with transparency? uint32_t frgba = (fr << 24u) + (fg << 16u) + (fb << 8u) + 0xff; uint32_t brgba = (br << 24u) + (bg << 16u) + (bb << 8u) + 0xff; - if(strcmp(c, " ") == 0){ + if((strcmp(c, " ") == 0) || (strcmp(c, "") == 0)){ *top = *bot = brgba; }else if(strcmp(c, "▄") == 0){ *top = frgba; diff --git a/src/lib/visual.cpp b/src/lib/visual.cpp index 850754ca5..1cf362a1c 100644 --- a/src/lib/visual.cpp +++ b/src/lib/visual.cpp @@ -105,8 +105,9 @@ auto ncvisual_create(float timescale) -> ncvisual* { return ret; } -auto ncvisual_from_plane(ncplane* n) -> ncvisual* { - uint32_t* rgba = ncplane_rgba(n, 0, 0, -1, -1); +auto ncvisual_from_plane(const ncplane* n, int begy, int begx, int leny, int lenx) + -> ncvisual* { + uint32_t* rgba = ncplane_rgba(n, begx, begy, leny, lenx); if(rgba == nullptr){ return nullptr; } @@ -118,8 +119,8 @@ auto ncvisual_from_plane(ncplane* n) -> ncvisual* { return nullptr; } ncplane_destroy(ncv->ncp); - ncv->ncp = n; - ncv->ncobj = nullptr; + ncv->ncp = ncplane_dup(n, nullptr); + ncv->ncobj = n->nc; return ncv; }