ncplane_move_family_{below, above}() with unit tests #2232

This commit is contained in:
nick black 2021-10-04 05:16:58 -04:00
parent 2b9765e945
commit e613b81b82
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
3 changed files with 137 additions and 65 deletions

View File

@ -1629,6 +1629,22 @@ ncplane_descendant_p(const struct ncplane* n, const struct ncplane* ancestor){
return 1;
}
// 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. If 'above' is NULL, 'n' is moved
// to the bottom of its pile.
API int ncplane_move_above(struct ncplane* RESTRICT n,
struct ncplane* RESTRICT above)
__attribute__ ((nonnull (1)));
// 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. If 'below' is NULL, 'n' is moved to
// the top of its pile.
API int ncplane_move_below(struct ncplane* RESTRICT n,
struct ncplane* RESTRICT below)
__attribute__ ((nonnull (1)));
// Splice ncplane 'n' out of the z-buffer, and reinsert it at the top or
// bottom. FIXME these both become static inline wrappers around
// ncplane_move_below() and ncplane_move_above() in ABI3.
@ -1638,38 +1654,27 @@ API void ncplane_move_bottom(struct ncplane* n)
__attribute__ ((nonnull (1)));
// Splice ncplane 'n' and its bound planes out of the z-buffer, and reinsert
// them at the top or bottom. Relative order will be maintained between the
// them above or below 'targ'. Relative order will be maintained between the
// reinserted planes. For a plane E bound to C, with z-ordering A B C D E,
// moving the C family to the top results in C E A B D, while moving it to
// the bottom results in A B D C E.
API void ncplane_move_family_top(struct ncplane* n)
__attribute__ ((nonnull (1)));
API void ncplane_move_family_bottom(struct ncplane* n)
API void ncplane_move_family_above(struct ncplane* n, struct ncplane* targ)
__attribute__ ((nonnull (1)));
// 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. If 'above' is NULL, 'n' is moved
// to the bottom of its pile.
API int ncplane_move_above(struct ncplane* RESTRICT n,
struct ncplane* RESTRICT above)
__attribute__ ((nonnull (1, 2)));
API void ncplane_move_family_below(struct ncplane* n, struct ncplane* targ)
__attribute__ ((nonnull (1)));
// 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. If 'below' is NULL, 'n' is moved to
// the top of its pile.
API int ncplane_move_below(struct ncplane* RESTRICT n,
struct ncplane* RESTRICT below)
__attribute__ ((nonnull (1, 2)));
__attribute__ ((nonnull (1)))
static inline void
ncplane_move_family_top(struct ncplane* n){
ncplane_move_family_below(n, NULL);
}
API void ncplane_move_family_above(struct ncplane* RESTRICT n,
struct ncplane* RESTRICT above)
__attribute__ ((nonnull (1, 2)));
API void ncplane_move_family_below(struct ncplane* RESTRICT n,
struct ncplane* RESTRICT below)
__attribute__ ((nonnull (1, 2)));
__attribute__ ((nonnull (1)))
static inline void
ncplane_move_family_bottom(struct ncplane* n){
ncplane_move_family_above(n, NULL);
}
// Return the plane below this one, or NULL if this is at the bottom.
API struct ncplane* ncplane_below(struct ncplane* n)

View File

@ -1358,6 +1358,10 @@ int ncplane_move_above(ncplane* restrict n, ncplane* restrict above){
if(n == above){
return -1;
}
if(above == NULL){
ncplane_move_bottom(n);
return 0;
}
if(ncplane_pile(n) != ncplane_pile(above)){ // can't move among piles
return -1;
}
@ -1389,6 +1393,10 @@ int ncplane_move_below(ncplane* restrict n, ncplane* restrict below){
if(n == below){
return -1;
}
if(below == NULL){
ncplane_move_top(n);
return 0;
}
if(ncplane_pile(n) != ncplane_pile(below)){ // can't move among piles
return -1;
}
@ -1444,39 +1452,10 @@ void ncplane_move_bottom(ncplane* n){
}
}
void ncplane_move_family_top(ncplane* n){
ncplane* below = ncplane_below(n);
ncplane_move_top(n);
// traverse the planes below n, until we hit NULL. do the planes below n
// first, so that we know the bottommost element of our new ensplicification.
// at this point, n is the topmost plane, and we're inserting below it.
ncplane* targ = n;
while(below){
ncplane* tmp = ncplane_below(below);
if(ncplane_descendant_p(below, n)){
ncplane_move_below(below, targ);
targ = below;
}
below = tmp;
}
// n remains the topmost plane, and we're inserting above it. we have to be
// careful this time not to cross into any we moved below n.
const ncplane* bottommost = targ;
targ = n;
// if above is NULL, we're moving to the bottom
void ncplane_move_family_above(ncplane* restrict n, ncplane* restrict bpoint){
ncplane* above = ncplane_above(n);
while(above && above != bottommost){
ncplane* tmp = ncplane_above(above);
if(ncplane_descendant_p(above, n)){
ncplane_move_above(above, targ);
targ = above;
}
above = tmp;
}
}
void ncplane_move_family_bottom(ncplane* n){
ncplane* above = ncplane_above(n);
ncplane_move_bottom(n);
ncplane_move_above(n, bpoint);
// traverse the planes above n, until we hit NULL. do the planes above n
// first, so that we know the topmost element of our new ensplicification.
// at this point, n is the bottommost plane, and we're inserting above it.
@ -1504,14 +1483,35 @@ void ncplane_move_family_bottom(ncplane* n){
}
}
void ncplane_move_family_above(ncplane* restrict n, ncplane* restrict above){
ncplane_move_above(n, above);
// FIXME walk above and below, moving descendants
}
void ncplane_move_family_below(ncplane* restrict n, ncplane* restrict below){
ncplane_move_below(n, below);
// FIXME walk above and below, moving descendants
// if below is NULL, we're moving to the top
void ncplane_move_family_below(ncplane* restrict n, ncplane* restrict bpoint){
ncplane* below = ncplane_below(n);
ncplane_move_below(n, bpoint);
// traverse the planes below n, until we hit NULL. do the planes below n
// first, so that we know the bottommost element of our new ensplicification.
// we're inserting below n...
ncplane* targ = n;
while(below){
ncplane* tmp = ncplane_below(below);
if(ncplane_descendant_p(below, n)){
ncplane_move_below(below, targ);
targ = below;
}
below = tmp;
}
// n remains the topmost plane, and we're inserting above it. we have to be
// careful this time not to cross into any we moved below n.
const ncplane* bottommost = targ;
targ = n;
ncplane* above = ncplane_above(n);
while(above && above != bottommost){
ncplane* tmp = ncplane_above(above);
if(ncplane_descendant_p(above, n)){
ncplane_move_above(above, targ);
targ = above;
}
above = tmp;
}
}
void ncplane_cursor_yx(const ncplane* n, int* y, int* x){

View File

@ -168,5 +168,72 @@ TEST_CASE("ZAxis") {
CHECK(0 == notcurses_render(nc_));
}
SUBCASE("FamilyTop") {
struct ncplane_options nopts{};
nopts.rows = nopts.cols = 1;
auto a = ncplane_create(n_, &nopts);
REQUIRE(nullptr != a);
auto b = ncplane_create(n_, &nopts);
REQUIRE(nullptr != b);
auto c = ncplane_create(n_, &nopts);
REQUIRE(nullptr != c);
auto d = ncplane_create(n_, &nopts);
REQUIRE(nullptr != d);
auto e = ncplane_create(c, &nopts);
REQUIRE(nullptr != e);
ncplane_move_below(b, a);
ncplane_move_below(c, b);
ncplane_move_below(d, c);
ncplane_move_below(e, d);
CHECK(ncpile_top(n_) == a);
CHECK(ncplane_below(a) == b);
CHECK(ncplane_below(b) == c);
CHECK(ncplane_below(c) == d);
CHECK(ncplane_below(d) == e);
ncplane_move_family_top(c);
CHECK(ncpile_top(n_) == c);
CHECK(ncplane_below(c) == e);
CHECK(ncplane_below(e) == a);
CHECK(ncplane_below(a) == b);
CHECK(ncplane_below(b) == d);
CHECK(ncpile_bottom(n_) == n_);
}
SUBCASE("FamilyBottom") {
struct ncplane_options nopts{};
nopts.rows = nopts.cols = 1;
auto a = ncplane_create(n_, &nopts);
REQUIRE(nullptr != a);
auto b = ncplane_create(n_, &nopts);
REQUIRE(nullptr != b);
auto c = ncplane_create(n_, &nopts);
REQUIRE(nullptr != c);
auto d = ncplane_create(n_, &nopts);
REQUIRE(nullptr != d);
auto e = ncplane_create(c, &nopts);
REQUIRE(nullptr != e);
ncplane_move_below(b, a);
ncplane_move_below(c, b);
ncplane_move_below(d, c);
ncplane_move_below(e, d);
// ABCDEs, E is bound to C
CHECK(ncpile_top(n_) == a);
CHECK(ncplane_below(a) == b);
CHECK(ncplane_below(b) == c);
CHECK(ncplane_below(c) == d);
CHECK(ncplane_below(d) == e);
CHECK(ncplane_below(e) == n_);
CHECK(ncplane_bottom(n_) == n_);
ncplane_move_family_bottom(c);
// ABDsCE, E is bound to C (FIXME have ABDEsC)
CHECK(ncpile_top(n_) == a);
CHECK(ncplane_below(a) == b);
CHECK(ncplane_below(b) == d);
CHECK(ncplane_below(d) == e);
CHECK(ncplane_below(e) == n_);
CHECK(ncplane_below(n_) == c);
CHECK(ncpile_bottom(n_) == c);
}
CHECK(0 == notcurses_stop(nc_));
}