diff --git a/NEWS.md b/NEWS.md index b8d650f78..6c6bcb965 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,9 @@ rearrangements of Notcurses. `ncplane_new()`. The latter ought be considered deprecated, and will be removed in the future. To align a place as previously done with `ncplane_aligned()`, use the `NCPLANE_OPTION_HORALIGNED` flag. + * The `ncplane_options` struct includes a function pointer member, + `resizecb`. If not `NULL`, this function will be called after the parent + plane is resized. See `notcurses_plane.3` for more information. * 1.7.3 (2020-09-19) * API changes pursuant to 2.0 API finalization: diff --git a/USAGE.md b/USAGE.md index 96642427f..f79e35779 100644 --- a/USAGE.md +++ b/USAGE.md @@ -629,6 +629,7 @@ typedef struct ncplane_options { int cols; // number of columns, must be positive void* userptr; // user curry, may be NULL const char* name; // name (used only for debugging), may be NULL + int (*resizecb)(struct ncplane*); // callback when parent is resized uint64_t flags; // closure over NCPLANE_OPTION_* } ncplane_options; diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md index 59d3c9e15..1960d9841 100644 --- a/doc/man/man3/notcurses_plane.3.md +++ b/doc/man/man3/notcurses_plane.3.md @@ -23,6 +23,7 @@ typedef struct ncplane_options { int cols; // number of columns, must be positive void* userptr; // user curry, may be NULL const char* name; // name (used only for debugging), may be NULL + int (*resizecb)(struct ncplane*); // callback when parent is resized uint64_t flags; // closure over NCPLANE_OPTION_* } ncplane_options; ``` @@ -230,6 +231,13 @@ might see changes. It is an error to merge a plane onto itself. **ncplane_erase** zeroes out every cell of the plane, dumps the egcpool, and homes the cursor. The base cell is preserved. +When a plane is resized (whether by **ncplane_resize**, **SIGWINCH**, or any +other mechanism), a breadth-first recursion is performed on its children. +Each child plane having a non-**NULL** **resizecb** will see that callback +invoked following resizing of its parent's plane. If it returns non-zero, the +resizing cascade terminates, returning non-zero. Otherwise, resizing proceeds +recursively. + ## Scrolling All planes, including the standard plane, are created with scrolling disabled. diff --git a/include/ncpp/Plane.hh b/include/ncpp/Plane.hh index 74e72aaaf..01a7d1b7e 100644 --- a/include/ncpp/Plane.hh +++ b/include/ncpp/Plane.hh @@ -1118,6 +1118,7 @@ namespace ncpp cols, opaque, nullptr, + nullptr, 0 }; ncplane *ret = ncplane_create ( diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index a94fd5bdb..c070c8e32 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1006,6 +1006,7 @@ typedef struct ncplane_options { int cols; // number of columns, must be positive void* userptr; // user curry, may be NULL const char* name; // name (used only for debugging), may be NULL + int (*resizecb)(struct ncplane*); // callback when parent is resized uint64_t flags; // closure over NCPLANE_OPTION_* } ncplane_options; @@ -1029,6 +1030,7 @@ ncplane_new(struct ncplane* n, int rows, int cols, int y, int x, void* opaque, c .cols = cols, .userptr = opaque, .name = name, + .resizecb = NULL, .flags = 0, }; return ncplane_create(n, &nopts); diff --git a/python/src/notcurses/build_notcurses.py b/python/src/notcurses/build_notcurses.py index 7dc05c2b3..7071ad308 100644 --- a/python/src/notcurses/build_notcurses.py +++ b/python/src/notcurses/build_notcurses.py @@ -83,6 +83,7 @@ typedef struct ncplane_options { int cols; // number of columns, must be positive void* userptr; // user curry, may be NULL const char* name; // name (used only for debugging), may be NULL + int (*resizecb)(struct ncplane*); // callback when parent is resized uint64_t flags; // closure over NCPLANE_OPTION_* } ncplane_options; struct ncplane* ncplane_create(struct ncplane* n, const ncplane_options* nopts); diff --git a/src/lib/direct.cpp b/src/lib/direct.cpp index 4292c3c55..0a573f3ae 100644 --- a/src/lib/direct.cpp +++ b/src/lib/direct.cpp @@ -445,7 +445,7 @@ int ncdirect_render_image(ncdirect* n, const char* file, ncalign_e align, struct ncplane* faken = ncplane_new_internal(nullptr, nullptr, disprows / encoding_y_scale(bset), dispcols / encoding_x_scale(bset), - 0, 0, nullptr, nullptr); + 0, 0, nullptr, nullptr, nullptr); if(faken == nullptr){ return -1; } diff --git a/src/lib/internal.h b/src/lib/internal.h index 9fe8f3fb9..887174414 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -81,6 +81,7 @@ typedef struct ncplane { egcpool pool; // attached storage pool for UTF-8 EGCs uint64_t channels; // works the same way as cells void* userptr; // slot for the user to stick some opaque pointer + int (*resizecb)(struct ncplane*); // callback after parent is resized cell basecell; // cell written anywhere that fb[i].gcluster == 0 struct notcurses* nc; // notcurses object of which we are a part char* name; // used only for debugging @@ -775,8 +776,10 @@ calc_gradient_channels(uint64_t* channels, uint64_t ul, uint64_t ur, // ncdirect needs to "fake" an isolated ncplane as a drawing surface for // ncvisual_render(), and thus calls these low-level internal functions. // they are not for general use -- check ncplane_new() and ncplane_destroy(). +// FIXME rewrite using ncplane_options ncplane* ncplane_new_internal(notcurses* nc, ncplane* n, int rows, int cols, - int yoff, int xoff, void* opaque, const char* name); + int yoff, int xoff, void* opaque, + const char* name, int (*resizecb)(ncplane*)); void free_plane(ncplane* p); diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 0745e2df5..207761a71 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -296,7 +296,8 @@ void free_plane(ncplane* p){ // ncplane created by ncdirect for rendering visuals. in that case (and only in // that case), nc is NULL. ncplane* ncplane_new_internal(notcurses* nc, ncplane* n, int rows, int cols, - int yoff, int xoff, void* opaque, const char* name){ + int yoff, int xoff, void* opaque, const char* name, + int (*resizecb)(ncplane*)){ if(rows <= 0 || cols <= 0){ logerror(nc, "Won't create denormalized plane (r=%d, c=%d)\n", rows, cols); return NULL; @@ -332,6 +333,7 @@ ncplane* ncplane_new_internal(notcurses* nc, ncplane* n, int rows, int cols, p->bprev = NULL; p->boundto = p; } + p->resizecb = resizecb; p->stylemask = 0; p->channels = 0; egcpool_init(&p->pool); @@ -360,7 +362,7 @@ static ncplane* create_initial_ncplane(notcurses* nc, int dimy, int dimx){ nc->stdplane = ncplane_new_internal(nc, NULL, dimy - (nc->margin_t + nc->margin_b), dimx - (nc->margin_l + nc->margin_r), 0, 0, NULL, - "std"); + "std", NULL); return nc->stdplane; } @@ -379,7 +381,7 @@ ncplane* ncplane_create(ncplane* n, const ncplane_options* nopts){ const int x = (nopts->flags & NCPLANE_OPTION_HORALIGNED) ? ncplane_align(n, nopts->horiz.align, nopts->cols) : nopts->horiz.x; return ncplane_new_internal(n->nc, n, nopts->rows, nopts->cols, nopts->y, - x, nopts->userptr, nopts->name); + x, nopts->userptr, nopts->name, nopts->resizecb); } void ncplane_home(ncplane* n){