mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 09:09:03 -04:00
O(1) z-axis moves #623
Replace the singly-linked z-axis with a doubly-linked list, and reimplement all z-axis moves as O(1) functions. Eliminate ncplane_move_{above/below}_unsafe(), as there are no longer unsafe moves.
This commit is contained in:
parent
a288c2e654
commit
37a4114f42
5
NEWS.md
5
NEWS.md
@ -1,6 +1,11 @@
|
||||
This document attempts to list user-visible changes and any major internal
|
||||
rearrangements of Notcurses.
|
||||
|
||||
* 1.4.2.4 (2020-05-20)
|
||||
* Removed `ncplane_move_above_unsafe()` and `ncplane_move_below_unsafe()`;
|
||||
all z-axis moves are now safe. Z-axis moves are all now O(1), rather
|
||||
than the previous O(N).
|
||||
|
||||
* 1.4.2.3 (2020-05-17)
|
||||
* Added `notcurses_canutf8()`, to verify use of UTF-8 encoding.
|
||||
* Fixed bug in `ncvisual_from_plane()` when invoked on the standard plane.
|
||||
|
9
USAGE.md
9
USAGE.md
@ -549,7 +549,6 @@ struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);
|
||||
|
||||
// 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.
|
||||
struct ncplane* ncplane_dup(struct ncplane* n, void* opaque);
|
||||
|
||||
// Merge the ncplane 'src' down onto the ncplane 'dst'. This is most rigorously
|
||||
@ -709,13 +708,17 @@ int ncplane_base(struct ncplane* ncp, cell* c);
|
||||
|
||||
```c
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it at the top or bottom.
|
||||
int ncplane_move_top(struct ncplane* n);
|
||||
int ncplane_move_bottom(struct ncplane* n);
|
||||
void ncplane_move_top(struct ncplane* n);
|
||||
void ncplane_move_bottom(struct ncplane* n);
|
||||
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it below 'below'.
|
||||
// Returns non-zero if 'n' is already in the desired location. 'n' and
|
||||
// 'below' must not be the same plane.
|
||||
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'.
|
||||
// Returns non-zero if 'n' is already in the desired location. 'n' and
|
||||
// 'above' must not be the same plane.
|
||||
int ncplane_move_above(struct ncplane* restrict n, struct ncplane* restrict above);
|
||||
|
||||
// Return the ncplane below this one, or NULL if this is at the stack's bottom.
|
||||
|
@ -36,9 +36,9 @@ notcurses_plane - operations on ncplanes
|
||||
|
||||
**int ncplane_move_bottom(struct ncplane* n);**
|
||||
|
||||
**int ncplane_move_above(struct ncplane* n, struct ncplane* above);**
|
||||
**int ncplane_move_above(struct ncplane* restrict n, struct ncplane* restrict above);**
|
||||
|
||||
**int ncplane_move_below(struct ncplane* n, struct ncplane* below);**
|
||||
**int ncplane_move_below(struct ncplane* restrict n, struct ncplane* restrict below);**
|
||||
|
||||
**struct ncplane* ncplane_below(struct ncplane* n);**
|
||||
|
||||
|
@ -271,14 +271,14 @@ namespace ncpp
|
||||
return error_guard (ncplane_move_yx (plane, y, x), -1);
|
||||
}
|
||||
|
||||
bool move_top () const NOEXCEPT_MAYBE
|
||||
void move_top () noexcept
|
||||
{
|
||||
return error_guard (ncplane_move_top (plane), -1);
|
||||
ncplane_move_top (plane);
|
||||
}
|
||||
|
||||
bool move_bottom () const NOEXCEPT_MAYBE
|
||||
void move_bottom () noexcept
|
||||
{
|
||||
return error_guard (ncplane_move_bottom (plane), -1);
|
||||
ncplane_move_bottom (plane);
|
||||
}
|
||||
|
||||
bool move_below (Plane &below) const NOEXCEPT_MAYBE
|
||||
@ -294,19 +294,6 @@ namespace ncpp
|
||||
return move_below (*below);
|
||||
}
|
||||
|
||||
bool move_below_unsafe (Plane &below) const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncplane_move_below_unsafe (plane, below.plane), -1);
|
||||
}
|
||||
|
||||
bool move_below_unsafe (Plane *below) const
|
||||
{
|
||||
if (below == nullptr)
|
||||
throw invalid_argument ("'below' must be a valid pointer");
|
||||
|
||||
return move_below_unsafe (*below);
|
||||
}
|
||||
|
||||
bool move_above (Plane &above) const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncplane_move_above (plane, above.plane), -1);
|
||||
@ -320,19 +307,6 @@ namespace ncpp
|
||||
return move_above (*above);
|
||||
}
|
||||
|
||||
bool move_above_unsafe (Plane &above) const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncplane_move_above_unsafe (plane, above.plane), -1);
|
||||
}
|
||||
|
||||
bool move_above_unsafe (Plane *above) const
|
||||
{
|
||||
if (above == nullptr)
|
||||
throw invalid_argument ("'above' must be a valid pointer");
|
||||
|
||||
return move_above (*above);
|
||||
}
|
||||
|
||||
bool mergedown (Plane &dst) const
|
||||
{
|
||||
return mergedown (&dst);
|
||||
|
@ -1124,32 +1124,20 @@ API int ncplane_move_yx(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 at the top or bottom.
|
||||
API int ncplane_move_top(struct ncplane* n);
|
||||
API int ncplane_move_bottom(struct ncplane* n);
|
||||
API void ncplane_move_top(struct ncplane* n);
|
||||
API void 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,
|
||||
const struct ncplane* RESTRICT above);
|
||||
|
||||
static inline int
|
||||
ncplane_move_above(struct ncplane* n, struct ncplane* above){
|
||||
if(n == above){
|
||||
return -1;
|
||||
}
|
||||
return ncplane_move_above_unsafe(n, above);
|
||||
}
|
||||
// Returns non-zero if 'n' is already in the desired location. 'n' and
|
||||
// 'above' must not be the same plane.
|
||||
API int ncplane_move_above(struct ncplane* RESTRICT n,
|
||||
struct ncplane* RESTRICT above);
|
||||
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it below 'below'.
|
||||
API int ncplane_move_below_unsafe(struct ncplane* RESTRICT n,
|
||||
const struct ncplane* RESTRICT below);
|
||||
|
||||
static inline int
|
||||
ncplane_move_below(struct ncplane* n, struct ncplane* below){
|
||||
if(n == below){
|
||||
return -1;
|
||||
}
|
||||
return ncplane_move_below_unsafe(n, below);
|
||||
}
|
||||
// Returns non-zero if 'n' is already in the desired location. 'n' and
|
||||
// 'below' must not be the same plane.
|
||||
API int ncplane_move_below(struct ncplane* RESTRICT n,
|
||||
struct ncplane* RESTRICT below);
|
||||
|
||||
// Return the plane below this one, or NULL if this is at the bottom.
|
||||
API struct ncplane* ncplane_below(struct ncplane* n);
|
||||
|
@ -134,10 +134,10 @@ int ncplane_move_yx(struct ncplane* n, int y, int x);
|
||||
void ncplane_yx(struct ncplane* n, int* y, int* x);
|
||||
void ncplane_dim_yx(const struct ncplane* n, int* rows, int* cols);
|
||||
int ncplane_putc_yx(struct ncplane* n, int y, int x, const cell* c);
|
||||
int ncplane_move_top(struct ncplane* n);
|
||||
int ncplane_move_bottom(struct ncplane* n);
|
||||
int ncplane_move_below(struct ncplane* n, struct ncplane* below);
|
||||
int ncplane_move_above(struct ncplane* n, struct ncplane* above);
|
||||
void ncplane_move_top(struct ncplane* n);
|
||||
void ncplane_move_bottom(struct ncplane* n);
|
||||
int ncplane_move_below(struct ncplane* restrict n, struct ncplane* restrict below);
|
||||
int ncplane_move_above(struct ncplane* restrict n, struct ncplane* restrict above);
|
||||
struct ncplane* ncplane_below(struct ncplane* n);
|
||||
char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff, uint32_t* attrword, uint64_t* channels);
|
||||
char* ncplane_at_cursor(struct ncplane* n, uint32_t* attrword, uint64_t* channels);
|
||||
|
@ -214,7 +214,7 @@ int main(void){
|
||||
if(!nc.mouse_enable()){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto n = nc.get_stdplane(&dimy, &dimx);
|
||||
std::unique_ptr<Plane*> n = std::make_unique<Plane*>(nc.get_stdplane(&dimy, &dimx));
|
||||
ncpp::Plane pplane{PLOTHEIGHT, dimx, dimy - PLOTHEIGHT, 0, nullptr};
|
||||
struct ncplot_options popts{};
|
||||
// FIXME would be nice to switch over to exponential at some level
|
||||
@ -227,14 +227,14 @@ int main(void){
|
||||
if(!plot){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
n->set_fg_rgb(0x00, 0x00, 0x00);
|
||||
n->set_bg_rgb(0xbb, 0x64, 0xbb);
|
||||
n->styles_on(CellStyle::Underline);
|
||||
if(n->putstr(0, NCAlign::Center, "mash keys, yo. give that mouse some waggle! ctrl+d exits.") <= 0){
|
||||
(*n)->set_fg_rgb(0x00, 0x00, 0x00);
|
||||
(*n)->set_bg_rgb(0xbb, 0x64, 0xbb);
|
||||
(*n)->styles_on(CellStyle::Underline);
|
||||
if((*n)->putstr(0, NCAlign::Center, "mash keys, yo. give that mouse some waggle! ctrl+d exits.") <= 0){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
n->styles_set(CellStyle::None);
|
||||
n->set_bg_default();
|
||||
(*n)->styles_set(CellStyle::None);
|
||||
(*n)->set_bg_default();
|
||||
if(!nc.render()){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@ -262,35 +262,35 @@ int main(void){
|
||||
}
|
||||
mtx.unlock();
|
||||
}
|
||||
if(!n->cursor_move(y, 0)){
|
||||
if(!(*n)->cursor_move(y, 0)){
|
||||
break;
|
||||
}
|
||||
n->set_fg_rgb(0xd0, 0xd0, 0xd0);
|
||||
n->printf("%c%c%c ", ni.alt ? 'A' : 'a', ni.ctrl ? 'C' : 'c',
|
||||
(*n)->set_fg_rgb(0xd0, 0xd0, 0xd0);
|
||||
(*n)->printf("%c%c%c ", ni.alt ? 'A' : 'a', ni.ctrl ? 'C' : 'c',
|
||||
ni.shift ? 'S' : 's');
|
||||
if(r < 0x80){
|
||||
n->set_fg_rgb(128, 250, 64);
|
||||
if(n->printf("ASCII: [0x%02x (%03d)] '%lc'", r, r,
|
||||
(wchar_t)(iswprint(r) ? r : printutf8(r))) < 0){
|
||||
(*n)->set_fg_rgb(128, 250, 64);
|
||||
if((*n)->printf("ASCII: [0x%02x (%03d)] '%lc'", r, r,
|
||||
(wchar_t)(iswprint(r) ? r : printutf8(r))) < 0){
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
if(nckey_supppuab_p(r)){
|
||||
n->set_fg_rgb(250, 64, 128);
|
||||
if(n->printf("Special: [0x%02x (%02d)] '%s'", r, r, nckeystr(r)) < 0){
|
||||
(*n)->set_fg_rgb(250, 64, 128);
|
||||
if((*n)->printf("Special: [0x%02x (%02d)] '%s'", r, r, nckeystr(r)) < 0){
|
||||
break;
|
||||
}
|
||||
if(NCKey::IsMouse(r)){
|
||||
if(n->printf(-1, NCAlign::Right, " x: %d y: %d", ni.x, ni.y) < 0){
|
||||
if((*n)->printf(-1, NCAlign::Right, " x: %d y: %d", ni.x, ni.y) < 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
n->set_fg_rgb(64, 128, 250);
|
||||
n->printf("Unicode: [0x%08x] '%lc'", r, (wchar_t)r);
|
||||
(*n)->set_fg_rgb(64, 128, 250);
|
||||
(*n)->printf("Unicode: [0x%08x] '%lc'", r, (wchar_t)r);
|
||||
}
|
||||
}
|
||||
if(!dim_rows(n)){
|
||||
if(!dim_rows(*n)){
|
||||
break;
|
||||
}
|
||||
const uint64_t sec = (timenow_to_ns() - start) / NANOSECS_IN_SEC;
|
||||
|
@ -2,14 +2,22 @@
|
||||
|
||||
void notcurses_debug(notcurses* nc, FILE* debugfp){
|
||||
const ncplane* n = nc->top;
|
||||
const ncplane* prev = NULL;
|
||||
int planeidx = 0;
|
||||
fprintf(debugfp, "*************************** notcurses debug state *****************************\n");
|
||||
while(n){
|
||||
fprintf(debugfp, "%04d off y: %3d x: %3d geom y: %3d x: %3d curs y: %3d x: %3d %s %p\n",
|
||||
planeidx, n->absy, n->absx, n->leny, n->lenx, n->y, n->x,
|
||||
n == notcurses_stdplane_const(nc) ? "std" : " ", n);
|
||||
n = n->z;
|
||||
fprintf(debugfp, "%04d off y: %3d x: %3d geom y: %3d x: %3d curs y: %3d x: %3d %s %p\n",
|
||||
planeidx, n->absy, n->absx, n->leny, n->lenx, n->y, n->x,
|
||||
n == notcurses_stdplane_const(nc) ? "std" : " ", n);
|
||||
if(n->above != prev){
|
||||
fprintf(stderr, " WARNING: expected ->above %p, got %p\n", prev, n->above);
|
||||
}
|
||||
prev = n;
|
||||
n = n->below;
|
||||
++planeidx;
|
||||
}
|
||||
if(nc->bottom != prev){
|
||||
fprintf(stderr, " WARNING: expected ->bottom %p, got %p\n", prev, nc->bottom);
|
||||
}
|
||||
fprintf(debugfp, "*******************************************************************************\n");
|
||||
}
|
||||
|
@ -65,7 +65,8 @@ typedef struct ncplane {
|
||||
int x, y; // current cursor location within this plane
|
||||
int absx, absy; // origin of the plane relative to the screen
|
||||
int lenx, leny; // size of the plane, [0..len{x,y}) is addressable
|
||||
struct ncplane* z; // plane below us
|
||||
struct ncplane* above;// plane above us, NULL if we're on top
|
||||
struct ncplane* below;// plane below us, NULL if we're on bottom
|
||||
struct ncplane* bnext;// next in the bound list of plane to which we are bound
|
||||
struct ncplane* blist;// head of our own bound list, if any
|
||||
struct ncplane* bound;// plane to which we are bound, if any
|
||||
@ -267,7 +268,8 @@ typedef struct ncdirect {
|
||||
} ncdirect;
|
||||
|
||||
typedef struct notcurses {
|
||||
ncplane* top; // the contents of our topmost plane (initially entire screen)
|
||||
ncplane* top; // topmost plane, never NULL
|
||||
ncplane* bottom;// bottommost plane, never NULL
|
||||
ncplane* stdscr;// aliases some plane from the z-buffer, covers screen
|
||||
|
||||
// the style state of the terminal is carried across render runs
|
||||
|
@ -291,7 +291,12 @@ ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
|
||||
cell_init(&p->basecell);
|
||||
p->blist = NULL;
|
||||
p->userptr = opaque;
|
||||
p->z = nc->top;
|
||||
p->above = NULL;
|
||||
if( (p->below = nc->top) ){ // always happens save initial plane
|
||||
nc->top->above = p;
|
||||
}else{
|
||||
nc->bottom = p;
|
||||
}
|
||||
nc->top = p;
|
||||
p->nc = nc;
|
||||
nc->stats.fbbytes += fbsize;
|
||||
@ -368,7 +373,6 @@ ncplane* ncplane_dup(const ncplane* n, void* opaque){
|
||||
ncplane_cursor_move_yx(newn, n->y, n->x);
|
||||
newn->attrword = attr;
|
||||
newn->channels = chan;
|
||||
ncplane_move_above_unsafe(newn, n);
|
||||
memmove(newn->fb, n->fb, sizeof(*n->fb) * dimx * dimy);
|
||||
// we dupd the egcpool, so just dup the goffset
|
||||
newn->basecell = n->basecell;
|
||||
@ -481,21 +485,6 @@ fprintf(stderr, "Can't resize standard plane\n");
|
||||
yoff, xoff, ylen, xlen);
|
||||
}
|
||||
|
||||
// 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(const 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;
|
||||
@ -503,11 +492,16 @@ int ncplane_destroy(ncplane* ncp){
|
||||
if(ncp->nc->stdscr == ncp){
|
||||
return -1;
|
||||
}
|
||||
ncplane** above = find_above_ncplane(ncp);
|
||||
if(above == NULL){
|
||||
return -1;
|
||||
if(ncp->above){
|
||||
ncp->above->below = ncp->below;
|
||||
}else{
|
||||
ncp->nc->top = ncp->below;
|
||||
}
|
||||
if(ncp->below){
|
||||
ncp->below->above = ncp->above;
|
||||
}else{
|
||||
ncp->nc->bottom = ncp->above;
|
||||
}
|
||||
*above = ncp->z; // splice it out of the list
|
||||
free_plane(ncp);
|
||||
return 0;
|
||||
}
|
||||
@ -806,11 +800,13 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
|
||||
goto err;
|
||||
}
|
||||
int dimy, dimx;
|
||||
update_term_dimensions(ret->ttyfd, &dimy, &dimx);
|
||||
if(update_term_dimensions(ret->ttyfd, &dimy, &dimx)){
|
||||
goto err;
|
||||
}
|
||||
char* shortname_term = termname();
|
||||
char* longname_term = longname();
|
||||
if(!opts->suppress_banner){
|
||||
fprintf(stderr, "Term: %dx%d %s (%s)\n", dimx, dimy,
|
||||
fprintf(stderr, "Term: %dx%d %s (%s)\n", dimy, dimx,
|
||||
shortname_term ? shortname_term : "?",
|
||||
longname_term ? longname_term : "?");
|
||||
}
|
||||
@ -826,7 +822,7 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
|
||||
term_verify_seq(&ret->tcache.smcup, "smcup");
|
||||
term_verify_seq(&ret->tcache.rmcup, "rmcup");
|
||||
}
|
||||
ret->top = ret->stdscr = NULL;
|
||||
ret->bottom = ret->top = ret->stdscr = NULL;
|
||||
if(ncvisual_init(ffmpeg_log_level(opts->loglevel))){
|
||||
goto err;
|
||||
}
|
||||
@ -867,11 +863,8 @@ err:
|
||||
void notcurses_drop_planes(notcurses* nc){
|
||||
ncplane* p = nc->top;
|
||||
while(p){
|
||||
ncplane* tmp = p->z;
|
||||
if(nc->stdscr == p){
|
||||
nc->top = p;
|
||||
p->z = NULL;
|
||||
}else{
|
||||
ncplane* tmp = p->below;
|
||||
if(nc->stdscr != p){
|
||||
free_plane(p);
|
||||
}
|
||||
p = tmp;
|
||||
@ -883,9 +876,9 @@ int notcurses_stop(notcurses* nc){
|
||||
if(nc){
|
||||
ret |= notcurses_stop_minimal(nc);
|
||||
while(nc->top){
|
||||
ncplane* p = nc->top;
|
||||
nc->top = p->z;
|
||||
free_plane(p);
|
||||
ncplane* p = nc->top->below;
|
||||
free_plane(nc->top);
|
||||
nc->top = p;
|
||||
}
|
||||
if(nc->rstate.mstreamfp){
|
||||
fclose(nc->rstate.mstreamfp);
|
||||
@ -1047,76 +1040,88 @@ const char* cell_extended_gcluster(const ncplane* n, const cell* c){
|
||||
}
|
||||
|
||||
// 'n' ends up above 'above'
|
||||
int ncplane_move_above_unsafe(ncplane* restrict n, const ncplane* restrict above){
|
||||
if(n->z == above){
|
||||
return 0;
|
||||
}
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
int ncplane_move_above(ncplane* restrict n, ncplane* restrict above){
|
||||
if(n == above){
|
||||
return -1;
|
||||
}
|
||||
ncplane** aa = find_above_ncplane(above);
|
||||
if(aa == NULL){
|
||||
return -1;
|
||||
if(n->below != above){
|
||||
// splice out 'n'
|
||||
if(n->below){
|
||||
n->below->above = n->above;
|
||||
}else{
|
||||
n->nc->bottom = n->above;
|
||||
}
|
||||
if(n->above){
|
||||
n->above->below = n->below;
|
||||
}else{
|
||||
n->nc->top = n->below;
|
||||
}
|
||||
if(above->above){
|
||||
above->above->below = n;
|
||||
}else{
|
||||
n->nc->top = n;
|
||||
}
|
||||
above->above = n;
|
||||
n->below = above;
|
||||
}
|
||||
ncplane* deconst_above = *aa;
|
||||
*an = n->z; // splice n out
|
||||
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, const ncplane* restrict below){
|
||||
if(below->z == n){
|
||||
return 0;
|
||||
int ncplane_move_below(ncplane* restrict n, ncplane* restrict below){
|
||||
if(n == below){
|
||||
return -1;
|
||||
}
|
||||
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(n->above != below){
|
||||
if(n->below){
|
||||
n->below->above = n->above;
|
||||
}else{
|
||||
n->nc->bottom = n->above;
|
||||
}
|
||||
if(n->above){
|
||||
n->above->below = n->below;
|
||||
}else{
|
||||
n->nc->top = n->below;
|
||||
}
|
||||
if(below->below){
|
||||
below->below->above = n;
|
||||
}else{
|
||||
n->nc->bottom = n;
|
||||
}
|
||||
below->below = n;
|
||||
n->above = below;
|
||||
}
|
||||
if(an == NULL){
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
int ncplane_move_top(ncplane* n){
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
if(an == NULL){
|
||||
return -1;
|
||||
void ncplane_move_top(ncplane* n){
|
||||
if(n->above){
|
||||
if( (n->above->below = n->below) ){
|
||||
n->below->above = n->above;
|
||||
}else{
|
||||
n->nc->bottom = n->above;
|
||||
}
|
||||
n->above = NULL;
|
||||
if( (n->below = n->nc->top) ){
|
||||
n->below->above = n;
|
||||
}
|
||||
n->nc->top = n;
|
||||
}
|
||||
*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;
|
||||
void ncplane_move_bottom(ncplane* n){
|
||||
if(n->below){
|
||||
if( (n->below->above = n->above) ){
|
||||
n->above->below = n->below;
|
||||
}else{
|
||||
n->nc->top = n->below;
|
||||
}
|
||||
n->below = NULL;
|
||||
if( (n->above = n->nc->bottom) ){
|
||||
n->above->below = n;
|
||||
}
|
||||
n->nc->bottom = n;
|
||||
}
|
||||
*an = n->z; // splice n out
|
||||
an = &n->nc->top;
|
||||
while(*an){
|
||||
an = &(*an)->z;
|
||||
}
|
||||
*an = n;
|
||||
n->z = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ncplane_cursor_yx(const ncplane* n, int* y, int* x){
|
||||
@ -1694,7 +1699,7 @@ ncplane* notcurses_top(notcurses* n){
|
||||
}
|
||||
|
||||
ncplane* ncplane_below(ncplane* n){
|
||||
return n->z;
|
||||
return n->below;
|
||||
}
|
||||
|
||||
// FIXME this clears the screen for some reason! what's up?
|
||||
|
@ -1084,7 +1084,7 @@ notcurses_render_internal(notcurses* nc, struct crender* rvec){
|
||||
free(fb);
|
||||
return -1;
|
||||
}
|
||||
p = p->z;
|
||||
p = p->below;
|
||||
}
|
||||
postpaint(fb, nc->lastframe, dimy, dimx, rvec, &nc->pool);
|
||||
free(fb);
|
||||
|
@ -20,6 +20,7 @@ auto main() -> int {
|
||||
opts.physrows = dimy / 8;
|
||||
opts.physcols = dimx / 2;
|
||||
opts.egc = strdup("░");
|
||||
// FIXME c++ is crashing
|
||||
//ncpp::Reader nr(nc, 0, 0, &opts);
|
||||
auto nr = ncreader_create(*n, 2, 2, &opts);
|
||||
if(nr == nullptr){
|
||||
|
@ -21,11 +21,11 @@ TEST_CASE("ZAxis") {
|
||||
|
||||
// if you want to move the plane which is already top+bottom to either, go ahead
|
||||
SUBCASE("StdPlaneOnanism") {
|
||||
CHECK(0 == ncplane_move_top(n_));
|
||||
ncplane_move_top(n_);
|
||||
struct ncplane* top = notcurses_top(nc_);
|
||||
CHECK(n_ == top);
|
||||
CHECK(!ncplane_below(top));
|
||||
CHECK(0 == ncplane_move_bottom(n_));
|
||||
ncplane_move_bottom(n_);
|
||||
CHECK(!ncplane_below(n_));
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ TEST_CASE("ZAxis") {
|
||||
CHECK(np == top);
|
||||
CHECK(n_ == ncplane_below(top));
|
||||
CHECK(!ncplane_below(n_));
|
||||
CHECK(!ncplane_move_top(np));
|
||||
ncplane_move_top(np);
|
||||
// verify it
|
||||
top = notcurses_top(nc_);
|
||||
CHECK(np == top);
|
||||
@ -73,7 +73,7 @@ TEST_CASE("ZAxis") {
|
||||
CHECK(np == top);
|
||||
CHECK(n_ == ncplane_below(top));
|
||||
CHECK(!ncplane_below(n_));
|
||||
CHECK(!ncplane_move_bottom(np));
|
||||
ncplane_move_bottom(np);
|
||||
top = notcurses_top(nc_);
|
||||
CHECK(n_ == top);
|
||||
CHECK(np == ncplane_below(top));
|
||||
|
Loading…
x
Reference in New Issue
Block a user