From 0da6a8c44bb40a8cee0e433d8bee1a9ed3d384f4 Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 22 Nov 2020 02:52:18 -0500 Subject: [PATCH] add NCPLANE_OPTION_NEWPILE #1078 --- NEWS.md | 15 +++++++++++ USAGE.md | 13 ++++++++-- doc/man/man3/notcurses_plane.3.md | 42 +++++++++++++++++++++++++++---- include/notcurses/notcurses.h | 10 +++++++- 4 files changed, 72 insertions(+), 8 deletions(-) diff --git a/NEWS.md b/NEWS.md index 256bcbe02..0db0b5a79 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,21 @@ This document attempts to list user-visible changes and any major internal rearrangements of Notcurses. +* 2.0.8 (not yet released) + * Move to a multipile model. For full details, consult + https://groups.google.com/g/notcurses/c/knB4ojndv8A and + https://github.com/dankamongmen/notcurses/issues/1078 and + `notcurses_plane(3)`. In short: + * A `struct notcurses` is now made up of one or more piles. A pile is one + or more `ncplane`s, with a bindtree and a z-axis. Different piles can be + mutated or rendered concurrently. There is no new user-visible type: a + `struct notcurses` can be treated as a single pile. + * To create a new pile, use the new `NCPLANE_OPTION_NEWPILE` with + `ncplane_create()`. The returned plane will be the top, bottom, and root + of a new plane. Alternatively, use `ncplane_reparent()` or + `ncplane_reparent_family()` with a `NULL` destination. + + * 2.0.7 (2020-11-21) * The `horiz` union of `ncplane_options` has been discarded; the `int x` within has been promoted. This union brought no actual type safety, and was diff --git a/USAGE.md b/USAGE.md index e6f425bfe..ec6c3f35c 100644 --- a/USAGE.md +++ b/USAGE.md @@ -647,6 +647,7 @@ When an `ncplane` is no longer needed, free it with ```c #define NCPLANE_OPTION_HORALIGNED 0x0001ull +#define NCPLANE_OPTION_NEWPILE 0x0002ull typedef struct ncplane_options { int y; // vertical placement relative to parent plane @@ -666,10 +667,18 @@ typedef struct ncplane_options { // retrieved (and reset) later. A 'name' can be set, used in debugging. struct ncplane* ncplane_create(struct ncplane* n, const ncplane_options* nopts); -// Plane 'n' will be unbound from its parent plane, if it is currently bound, -// and will be made a bound child of 'newparent', if 'newparent' is not NULL. +// Plane 'n' will be unbound from its parent plane, and will be made a bound +// child of 'newparent'. It is an error if 'n' or 'newparent' are NULL. If +// 'newparent' is equal to 'n', 'n' becomes the root of a new pile, unless 'n' +// is already the root of a pile, in which case this is a no-op. Returns 'n'. +// The standard plane cannot be reparented. Any planes bound to 'n' are +// reparented to the previous parent of 'n'. struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent); +// The same as ncplane_reparent(), except any planes bound to 'n' come along +// with it to its new destination. Their z-order is maintained. +struct ncplane* ncplane_reparent_family(struct ncplane* n, struct ncplane* newparent); + // Replace the ncplane's existing resizecb with 'resizecb' (which may be NULL). void ncplane_set_resizecb(struct ncplane* n, int(*resizecb)(struct ncplane*)); diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md index 47c20e80d..e3f09bfcd 100644 --- a/doc/man/man3/notcurses_plane.3.md +++ b/doc/man/man3/notcurses_plane.3.md @@ -12,6 +12,7 @@ notcurses_plane - operations on ncplanes ```c #define NCPLANE_OPTION_HORALIGNED 0x0001ull +#define NCPLANE_OPTION_NEWPILE 0x0002ull typedef struct ncplane_options { int y; // vertical placement relative to parent plane @@ -33,6 +34,8 @@ typedef struct ncplane_options { **struct ncplane* ncplane_reparent(struct ncplane* ***n***, struct ncplane* ***newparent***);** +**struct ncplane* ncplane_reparent_family(struct ncplane* ***n***, struct ncplane* ***newparent***);** + **int ncplane_resize_realign(struct ncplane* ***n***);** **void ncplane_set_resizecb(struct ncplane* ***n***, int(*resizecb)(struct ncplane*));** @@ -199,11 +202,14 @@ New planes can be created with **ncplane_create**. If a plane is bound to another, x and y coordinates are relative to the plane to which it is bound, and if this latter plane moves, all its bound planes move along with it. When a plane is destroyed, all planes bound to it (directly or transitively) are -destroyed. **ncplane_reparent** detaches the plane **n** from any plane to -which it is bound, and binds it to **newparent**. The standard plane cannot be -reparented. If **newparent** is **NULL**, the plane becomes the root plane of a -new, unrendered stack. All planes bound to **n** move along with it during a -reparenting operation. +destroyed. + +**ncplane_reparent** detaches the plane **n** from any plane to which it is +bound, and binds it to **newparent**. Its children are reparented to its +previous parent. The standard plane cannot be reparented. If **newparent** is +**NULL**, the plane becomes the root plane of a new, unrendered stack. When +**ncplane_reparent_family** is used, all planes bound to **n** move along with +it during a reparenting operation. See [Piles][] below. **ncplane_destroy** destroys a particular ncplane, after which it must not be used again. **notcurses_drop_planes** destroys all ncplanes other than the @@ -240,6 +246,29 @@ invoked following resizing of its parent's plane. If it returns non-zero, the resizing cascade terminates, returning non-zero. Otherwise, resizing proceeds recursively. +## Piles + +A single **notcurses** context is made up of one or more piles. A pile is a +set of one or more **ncplane**s, including the partial orderings made up of +their binding and z-axis pointers. A pile has a top and bottom **ncplane** +(this might be a single plane), and one or more root planes (planes which are +bound to themselves). Multiple threads can concurrently operate on distinct +piles, even changing one while rendering another. + +Each plane is part of one and only one pile. By default, a plane is part of the +same pile containing that plane to which it is bound. If the +**NCPLANE_OPTION_NEWPILE** flag is given to **ncplane_create**, the returned +plane becomes the root plane, top, and bottom of a new pile. As a root plane, +it is bound to itself. A new pile can also be created by reparenting a plane +to itself, though if the plane is already a root plane, this is a no-op. + +When a plane is moved to a different pile (whether new or preexisting), any +planes which were bound to it are rebound to its previous parent. If the plane +was a root plane of some pile, any bound planes become root planes. The new +plane is placed immediately atop its new parent on its new pile's z-axis. +When `ncplane_reparent_family()` is used, all planes bound to the reparented +plane are moved along with it. Their relative z-order is maintained. + ## Scrolling All planes, including the standard plane, are created with scrolling disabled. @@ -286,6 +315,9 @@ All other functions cannot fail (and return **void**). # NOTES +**ncplane_new** is defined as a deprecated wrapper around **ncplane_create**. +It should not be used in new code. + # SEE ALSO **notcurses(3)**, **notcurses_cell(3)**, **notcurses_output(3)**, diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 980b4d149..f694dc8b6 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1026,6 +1026,9 @@ API char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff, // Horizontal alignment relative to the parent plane. Use 'align' instead of 'x'. #define NCPLANE_OPTION_HORALIGNED 0x0001ull +// The new place will be the root of a new pile. +#define NCPLANE_OPTION_NEWPILE 0x0002ull + typedef struct ncplane_options { int y; // vertical placement relative to parent plane int x; // horizontal placement relative to parent plane @@ -1062,9 +1065,14 @@ API int (*ncplane_resizecb(const struct ncplane* n))(struct ncplane*); // child of 'newparent'. It is an error if 'n' or 'newparent' are NULL. If // 'newparent' is equal to 'n', 'n' becomes the root of a new pile, unless 'n' // is already the root of a pile, in which case this is a no-op. Returns 'n'. -// The standard plane cannot be reparented. +// The standard plane cannot be reparented. Any planes bound to 'n' are +// reparented to the previous parent of 'n'. API struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent); +// The same as ncplane_reparent(), except any planes bound to 'n' come along +// with it to its new destination. Their z-order is maintained. +API struct ncplane* ncplane_reparent_family(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, and will