From d1c9dd93cf51968acb28388abeec76e7ff0cd4af Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 17 Nov 2021 04:02:49 -0500 Subject: [PATCH] [core] add ncplane_resize_placewithin #1478 --- NEWS.md | 1 + doc/man/man3/notcurses_plane.3.md | 2 ++ include/notcurses/notcurses.h | 21 ++++++++++----- src/lib/notcurses.c | 44 +++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index 703ce94ac..3f16397df 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,6 +29,7 @@ rearrangements of Notcurses. * `ncplayer` now defaults to pixel blitting. * `NCKEY_SIGNAL` is no longer a synonym for `NCKEY_RESIZE`, but instead indicates receipt of `SIGCONT`. + * A new resize callback, `ncplane_resize_placewithin()`, has been added. * 2.4.9 (2021-11-11) * Added `ncnmetric()`, which uses `snprintf()` internally. `ncmetric()` diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md index e03d48604..c69e7e75f 100644 --- a/doc/man/man3/notcurses_plane.3.md +++ b/doc/man/man3/notcurses_plane.3.md @@ -61,6 +61,8 @@ typedef struct ncplane_options { **int ncplane_resize_marginalized(struct ncplane* ***n***);** +**int ncplane_resize_placewithin(struct ncplane* ***n***);** + **void ncplane_set_resizecb(struct ncplane* ***n***, int(*resizecb)(struct ncplane*));** **int (*ncplane_resizecb(const struct ncplane* ***n***))(struct ncplane*);** diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index fde08460c..e387dc316 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1299,19 +1299,26 @@ API ALLOC struct ncplane* ncplane_create(struct ncplane* n, const ncplane_option API ALLOC struct ncplane* ncpile_create(struct notcurses* nc, const ncplane_options* nopts) __attribute__ ((nonnull (1, 2))); -// Suitable for use as a 'resizecb', this will resize the plane to the visual -// region's size. It is used for the standard plane. +// Utility resize callbacks. When a parent plane is resized, it invokes each +// child's resize callback. Any logic can be run in a resize callback, but +// these are some generically useful ones. + +// resize the plane to the visual region's size (used for the standard plane). API int ncplane_resize_maximize(struct ncplane* n); -// Suitable for use as a 'resizecb' with planes created with -// NCPLANE_OPTION_MARGINALIZED. This will resize the plane 'n' against its -// parent, attempting to enforce the supplied margins. +// resize the plane to its parent's size, attempting to enforce the margins +// supplied along with NCPLANE_OPTION_MARGINALIZED. API int ncplane_resize_marginalized(struct ncplane* n); -// Suitable for use as a 'resizecb'. This will realign the plane 'n' against -// its parent, using the alignment specified at ncplane_create()-time. +// realign the plane 'n' against its parent, using the alignments specified +// with NCPLANE_OPTION_HORALIGNED and/or NCPLANE_OPTION_VERALIGNED. API int ncplane_resize_realign(struct ncplane* n); +// move the plane such that it is entirely within its parent, if possible. +// no resizing is performed. +API int ncplane_resize_placewithin(struct ncplane* n); +/////////////////////////////////////////////////////////////////////////////// + // Replace the ncplane's existing resizecb with 'resizecb' (which may be NULL). // The standard plane's resizecb may not be changed. API void ncplane_set_resizecb(struct ncplane* n, int(*resizecb)(struct ncplane*)); diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 9996ac3c2..66de8383a 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -2385,6 +2385,50 @@ int (*ncplane_resizecb(const ncplane* n))(ncplane*){ return n->resizecb; } +int ncplane_resize_placewithin(ncplane* n){ + if(n->boundto == n){ + return 0; + } + int absy = ncplane_abs_y(n); + int absx = ncplane_abs_x(n); + int ret = 0; + if(absy + ncplane_dim_y(n) > ncplane_dim_y(n->boundto)){ + const int dy = (absy + ncplane_dim_y(n)) - ncplane_dim_y(n->boundto); + logdebug("moving up %d\n", dy); + if(ncplane_move_rel(n, -dy, 0)){ + ret = -1; + } + absy = ncplane_abs_y(n); + } + if(absx + ncplane_dim_x(n) > ncplane_dim_x(n->boundto)){ + const int dx = ncplane_dim_x(n->boundto) - (absx + ncplane_dim_x(n)); + logdebug("moving left %d\n", dx); + if(ncplane_move_rel(n, 0, dx)){ + ret = -1; + } + absx = ncplane_abs_x(n); + } + // this will prefer upper-left material if the child plane is larger than + // the parent. we might want a smarter rule, one based on origin? + if(absy < 0){ + logdebug("moving down %d\n", -absy); + // we're at least partially above our parent + if(ncplane_move_rel(n, -absy, 0)){ + ret = -1; + } + absy = ncplane_abs_y(n); + } + if(absx < 0){ + logdebug("moving right %d\n", -absx); + // we're at least partially to the left of our parent + if(ncplane_move_rel(n, 0, -absx)){ + ret = -1; + } + absx = ncplane_abs_x(n); + } + return ret; +} + int ncplane_resize_marginalized(ncplane* n){ const ncplane* parent = ncplane_parent_const(n); // a marginalized plane cannot be larger than its oppressor plane =]