add ncplane_create() + ncplane_options #1020

pull/1022/head
nick black 4 years ago committed by Nick Black
parent 607c03edc4
commit 36aed3c521

@ -4,7 +4,13 @@ rearrangements of Notcurses.
* 1.7.4 (not yet released)
* All `_rgb_clipped()` functions have been renamed `_rgb8_clipped()`, to
match the changes made in 1.7.2. Sorry, I ought have done this before.
* `ncplane_create()` has been introduced, taking a `struct ncplane_options`
parameter. This replaces `ncplane_aligned()`, and will replace
`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.
and
* 1.7.3 (2020-09-19)
* API changes pursuant to 2.0 API finalization:
* `mbswidth()` has been renamed `ncstrwidth()`.

@ -600,8 +600,9 @@ In addition to its framebuffer--a rectilinear matrix of cells
* a current style, foreground channel, and background channel,
* its geometry,
* a configured user curry (a `void*`),
* its position relative to the visible plane, and
* its z-index.
* its position relative to the visible plane,
* its z-index, and
* a name (used only for debugging).
If opaque, a `cell` on a higher `ncplane` completely obstructs a corresponding
`cell` from a lower `ncplane` from being seen. An `ncplane` corresponds loosely
@ -609,23 +610,34 @@ to an [NCURSES Panel](https://invisible-island.net/ncurses/ncurses-intro.html#pa
but is the primary drawing surface of notcurses—there is no object
corresponding to a bare NCURSES `WINDOW`.
In addition to `ncplane_new()`, an `ncplane` can be created aligned relative
to an existing `ncplane` (including the standard plane) using
`ncplane_aligned()`. When an `ncplane` is no longer needed, free it with
An `ncplane` can be created aligned relative to an existing `ncplane`
(including the standard plane) using `NCPLANE_OPTION_ALIGNED`.
When an `ncplane` is no longer needed, free it with
`ncplane_destroy()`. To quickly reset the `ncplane`, use `ncplane_erase()`.
```c
// Create a new ncplane bound to plane 'n', at the offset 'y'x'x' (relative to
// the origin of 'n') and the specified size. The number of rows and columns
#define NCPLANE_OPTION_HORALIGNED 0x0001ull
typedef struct ncplane_options {
int y; // vertical placement relative to parent plane
union {
int x;
ncalign_e align;
} horiz; // horizontal placement relative to parent plane
int rows; // number of rows, must be positive
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
uint64_t flags; // closure over NCPLANE_OPTION_*
} ncplane_options;
// Create a new ncplane bound to plane 'n', at THE OFFset 'y'x'x' (relative to
// the origin of 'n') and the specified size. The number of 'rows' and 'cols'
// must both be positive. This plane is initially at the top of the z-buffer,
// as if ncplane_move_top() had been called on it. The void* 'opaque' can be
// retrieved (and reset) later. A name can be set, used in debugging.
struct ncplane* ncplane_new(struct ncplane* n, int rows, int cols,
int y, int x, void* opaque, const char* name);
// Create a plane bound to 'n', and aligned relative to it using 'align'.
struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
int y, ncalign_e align, void* opaque, const char* name);
// as if ncplane_move_top() had been called on it. The void* 'userptr' can be
// 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.

@ -10,14 +10,29 @@ notcurses_plane - operations on ncplanes
**#include <notcurses/notcurses.h>**
```c
#define NCPLANE_OPTION_HORALIGNED 0x0001ull
typedef struct ncplane_options {
int y; // vertical placement relative to parent plane
union {
int x;
ncalign_e align;
} horiz; // horizontal placement relative to parent plane
int rows; // number of rows, must be positive
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
uint64_t flags; // closure over NCPLANE_OPTION_*
} ncplane_options;
```
**struct ncplane* ncplane_create(struct ncplane* n, const ncplane_options* nopts);**
**struct ncplane* notcurses_top(struct notcurses* n);**
**struct ncplane* notcurses_bottom(struct notcurses* n);**
**struct ncplane* ncplane_new(struct ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque, const char* name);**
**struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols, int yoff, ncalign_e align, void* opaque, const char* name);**
**struct ncplane* ncplane_reparent(struct ncplane* n, struct ncplane* newparent);**
**struct ncplane* ncplane_dup(struct ncplane* n, void* opaque);**
@ -174,17 +189,18 @@ anywhere. In addition to its framebuffer--a rectilinear matrix of cells
* position relative to the standard plane,
* the plane, if any, to which it is bound,
* the next plane bound by the plane to which it is bound,
* the head of the list of its bound planes, and
* its z-index.
New planes can be created with **ncplane_new** and **ncplane_aligned**. 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** if **newparent**
is not **NULL**. All planes bound to **n** move along with it during a
reparenting operation.
* the head of the list of its bound planes,
* its z-index, and
* a name (used only for debugging).
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** if **newparent** is not
**NULL**. All planes bound to **n** move along with it during a reparenting
operation.
**ncplane_destroy** destroys a particular ncplane, after which it must not be
used again. **notcurses_drop_planes** destroys all ncplanes other than the

@ -1111,15 +1111,19 @@ namespace ncpp
ncplane* create_plane (Plane &n, int rows, int cols, int yoff, NCAlign align, void *opaque)
{
ncplane *ret = ncplane_aligned (
n.plane,
rows,
cols,
yoff,
static_cast<ncalign_e>(align),
opaque,
nullptr
);
ncplane_options nopts = {
yoff,
static_cast<ncalign_e>(align),
rows,
cols,
opaque,
nullptr,
0
};
ncplane *ret = ncplane_create (
n.plane,
&nopts
);
if (ret == nullptr)
throw init_error ("Notcurses failed to create an aligned plane");

@ -993,18 +993,46 @@ notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows, int* RESTRI
API char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff,
uint16_t* stylemask, uint64_t* channels);
// Create a new ncplane bound to plane 'n', at the offset 'y'x'x' (relative to
// the origin of 'n') and the specified size. The number of rows and columns
// Horizontal alignment relative to the parent plane. Use 'align' instead of 'x'.
#define NCPLANE_OPTION_HORALIGNED 0x0001ull
typedef struct ncplane_options {
int y; // vertical placement relative to parent plane
union {
int x;
ncalign_e align;
} horiz; // horizontal placement relative to parent plane
int rows; // number of rows, must be positive
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
uint64_t flags; // closure over NCPLANE_OPTION_*
} ncplane_options;
// Create a new ncplane bound to plane 'n', at THE OFFset 'y'x'x' (relative to
// the origin of 'n') and the specified size. The number of 'rows' and 'cols'
// must both be positive. This plane is initially at the top of the z-buffer,
// as if ncplane_move_top() had been called on it. The void* 'opaque' can be
// retrieved (and reset) later. A name can be set, used in debugging.
API struct ncplane* ncplane_new(struct ncplane* n, int rows, int cols,
int y, int x, void* opaque, const char* name);
// Create a plane bound to 'n', and aligned relative to it using 'align'.
API struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols,
int yoff, ncalign_e align, void* opaque,
const char* name);
// as if ncplane_move_top() had been called on it. The void* 'userptr' can be
// retrieved (and reset) later. A 'name' can be set, used in debugging.
API struct ncplane* ncplane_create(struct ncplane* n, const ncplane_options* nopts);
// This function will be marked deprecated in 2.0 in favor of ncplane_create().
// It persists only for backwards compatibility.
static inline struct ncplane*
ncplane_new(struct ncplane* n, int rows, int cols, int y, int x, void* opaque, const char* name){
ncplane_options nopts = {
.y = y,
.horiz = {
.x = x,
},
.rows = rows,
.cols = cols,
.userptr = opaque,
.name = name,
.flags = 0,
};
return ncplane_create(n, &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.

@ -73,8 +73,19 @@ typedef enum {
NCALIGN_CENTER,
NCALIGN_RIGHT,
} ncalign_e;
struct ncplane* ncplane_new(struct ncplane* n, int rows, int cols, int yoff, int xoff, void* opaque, const char* name);
struct ncplane* ncplane_aligned(struct ncplane* n, int rows, int cols, int yoff, ncalign_e align, void* opaque, const char* name);
typedef struct ncplane_options {
int y; // vertical placement relative to parent plane
union {
int x;
ncalign_e align;
} horiz; // horizontal placement relative to parent plane
int rows; // number of rows, must be positive
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
uint64_t flags; // closure over NCPLANE_OPTION_*
} ncplane_options;
struct ncplane* ncplane_create(struct ncplane* n, const ncplane_options* nopts);
unsigned notcurses_supported_styles(const struct notcurses* nc);
unsigned notcurses_palette_size(const struct notcurses* nc);
bool notcurses_cantruecolor(const struct notcurses* nc);

@ -104,8 +104,16 @@ int allglyphs_demo(struct notcurses* nc){
}
}
const int planey = (dimy - height) / 2 + 1;
struct ncplane* column = ncplane_aligned(n, height, width, planey,
NCALIGN_CENTER, NULL, NULL);
ncplane_options nopts = {
.y = planey,
.horiz = {
.align = NCALIGN_CENTER,
},
.rows = height,
.cols = width,
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* column = ncplane_create(n, &nopts);
if(column == NULL){
return -1;
}

@ -72,8 +72,16 @@ about_toggle(struct notcurses* nc){
const int ABOUT_COLS = 40;
int dimy;
notcurses_term_dim_yx(nc, &dimy, NULL);
struct ncplane* n = ncplane_aligned(notcurses_stdplane(nc), ABOUT_ROWS,
ABOUT_COLS, 3, NCALIGN_CENTER, NULL, NULL);
ncplane_options nopts = {
.y = 3,
.horiz = {
.align = NCALIGN_CENTER,
},
.rows = ABOUT_ROWS,
.cols = ABOUT_COLS,
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* n = ncplane_create(notcurses_stdplane(nc), &nopts);
// let the glyphs below show through, but only dimly
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_BLEND);

@ -3391,7 +3391,19 @@ const char subdivision_flag[] =
static struct ncplane*
mojiplane(struct ncplane* title, int y, int rows, const char* summary){
struct ncplane* n = ncplane_aligned(title, rows, planewidth, y, NCALIGN_CENTER, NULL, NULL);
ncplane_options nopts = {
.y = y,
.horiz = {
.align = NCALIGN_CENTER,
},
.rows = rows,
.cols = planewidth,
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* n = ncplane_create(title, &nopts);
if(n == NULL){
return NULL;
}
uint64_t channels = CHANNELS_RGB_INITIALIZER(0xf0, 0xa0, 0xf0, 0x10, 0x10, 0x60);
if(ncplane_perimeter_rounded(n, 0, channels, NCBOXMASK_RIGHT) < 0){
ncplane_destroy(n);
@ -3545,7 +3557,16 @@ makegroup(struct ncplane* title, int y, const char* emoji, const char* name){
struct ncplane*
maketitle(struct ncplane* std){
struct ncplane* title = ncplane_aligned(std, 3, 74, 2, NCALIGN_CENTER, NULL, NULL);
ncplane_options nopts = {
.y = 2,
.horiz = {
.align = NCALIGN_CENTER,
},
.rows = 3,
.cols = 74,
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* title = ncplane_create(std, &nopts);
if(title == NULL){
return NULL;
}

@ -111,9 +111,16 @@ outro_message(struct notcurses* nc, int* rows, int* cols){
const char str1[] = " throw your hands in the air ";
const char str2[] = " hack on! —dank❤ ";
int ystart = *rows - 6;
struct ncplane* non = ncplane_aligned(notcurses_stdplane(nc), 5,
strlen(str1) + 4, ystart,
NCALIGN_CENTER, NULL, NULL);
ncplane_options nopts = {
.rows = 5,
.cols = strlen(str1) + 4,
.y = ystart,
.horiz = {
.align = NCALIGN_CENTER,
},
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* non = ncplane_create(notcurses_stdplane(nc), &nopts);
if(non == NULL){
return NULL;
}

@ -28,9 +28,16 @@ static struct ncplane*
legend(struct notcurses* nc, const char* msg){
int dimx, dimy;
notcurses_term_dim_yx(nc, &dimy, &dimx);
struct ncplane* n = ncplane_aligned(notcurses_stdplane(nc), 3,
strlen(msg) + 4, 3,
NCALIGN_CENTER, NULL, NULL);
ncplane_options nopts = {
.rows = 3,
.cols = strlen(msg) + 4,
.y = 3,
.horiz = {
.align = NCALIGN_CENTER,
},
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* n = ncplane_create(notcurses_stdplane(nc), &nopts);
if(n == NULL){
return NULL;
}

@ -186,9 +186,16 @@ int unicodeblocks_demo(struct notcurses* nc){
struct timespec subdelay;
uint64_t nstotal = timespec_to_ns(&demodelay);
ns_to_timespec(nstotal / 5, &subdelay);
struct ncplane* header = ncplane_aligned(notcurses_stdplane(nc), 2,
(CHUNKSIZE * 2) - 2, 2,
NCALIGN_CENTER, NULL, NULL);
ncplane_options nopts = {
.y = 2,
.horiz = {
.align = NCALIGN_CENTER,
},
.rows = 2,
.cols = (CHUNKSIZE * 2) - 2,
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* header = ncplane_create(n, &nopts);
if(header == NULL){
return -1;
}
@ -209,8 +216,10 @@ int unicodeblocks_demo(struct notcurses* nc){
return -1;
}
struct ncplane* nn;
if((nn = ncplane_aligned(notcurses_stdplane(nc), BLOCKSIZE / CHUNKSIZE + 2,
(CHUNKSIZE * 2) + 2, 4, NCALIGN_CENTER, NULL, NULL)) == NULL){
nopts.rows = BLOCKSIZE / CHUNKSIZE + 2;
nopts.cols = (CHUNKSIZE * 2) + 2;
nopts.y = 4;
if((nn = ncplane_create(header, &nopts)) == NULL){
return -1;
}
if(draw_block(nn, blockstart)){

@ -317,10 +317,16 @@ infoplane(struct ncdirect* ncd, const fetched_info* fi){
}
int dimy;
struct ncplane* std = notcurses_stddim_yx(nc, &dimy, NULL);
struct ncplane* infop = ncplane_aligned(std,
planeheight, planewidth,
dimy - planeheight,
NCALIGN_CENTER, NULL, "info");
struct ncplane_options nopts = {
.y = dimy - planeheight,
.horiz.align = NCALIGN_CENTER,
.rows = planeheight,
.cols = planewidth,
.userptr = NULL,
.name = "info",
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* infop = ncplane_create(std, &nopts);
if(infop == NULL){
return -1;
}

@ -442,10 +442,10 @@ int ncdirect_render_image(ncdirect* n, const char* file, ncalign_e align,
leny = (leny / (double)ncv->rows) * ((double)disprows);
lenx = (lenx / (double)ncv->cols) * ((double)dispcols);
//fprintf(stderr, "render: %d+%d of %d/%d stride %u %p\n", leny, lenx, ncv->rows, ncv->cols, ncv->rowstride, ncv->data);
struct ncplane* faken = ncplane_create(nullptr, nullptr,
disprows / encoding_y_scale(bset),
dispcols / encoding_x_scale(bset),
0, 0, nullptr, nullptr);
struct ncplane* faken = ncplane_new_internal(nullptr, nullptr,
disprows / encoding_y_scale(bset),
dispcols / encoding_x_scale(bset),
0, 0, nullptr, nullptr);
if(faken == nullptr){
return -1;
}

@ -775,8 +775,9 @@ 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().
ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
int yoff, int xoff, void* opaque, const char* name);
ncplane* ncplane_new_internal(notcurses* nc, ncplane* n, int rows, int cols,
int yoff, int xoff, void* opaque, const char* name);
void free_plane(ncplane* p);
// heap-allocated formatted output

@ -295,8 +295,8 @@ void free_plane(ncplane* p){
// there's a denormalized case we also must handle, that of the "fake" isolated
// ncplane created by ncdirect for rendering visuals. in that case (and only in
// that case), nc is NULL.
ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
int yoff, int xoff, void* opaque, const char* name){
ncplane* ncplane_new_internal(notcurses* nc, ncplane* n, int rows, int cols,
int yoff, int xoff, void* opaque, const char* name){
if(rows <= 0 || cols <= 0){
logerror(nc, "Won't create denormalized plane (r=%d, c=%d)\n", rows, cols);
return NULL;
@ -358,9 +358,9 @@ ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
// the z-buffer. clear out all cells. this is for a wholly new context.
static ncplane*
create_initial_ncplane(notcurses* nc, int dimy, int dimx){
nc->stdplane = ncplane_create(nc, NULL, dimy - (nc->margin_t + nc->margin_b),
dimx - (nc->margin_l + nc->margin_r), 0, 0, NULL,
"std");
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");
return nc->stdplane;
}
@ -372,14 +372,14 @@ const ncplane* notcurses_stdplane_const(const notcurses* nc){
return nc->stdplane;
}
ncplane* ncplane_new(ncplane* n, int rows, int cols, int y, int x,
void* opaque, const char* name){
return ncplane_create(n->nc, n, rows, cols, y, x, opaque, name);
}
ncplane* ncplane_aligned(ncplane* n, int rows, int cols, int y,
ncalign_e align, void* opaque, const char* name){
return ncplane_create(n->nc, n, rows, cols, y, ncplane_align(n, align, cols), opaque, name);
ncplane* ncplane_create(ncplane* n, const ncplane_options* nopts){
if(nopts->flags > NCPLANE_OPTION_HORALIGNED){
logwarn(n->nc, "Provided unsupported flags %016lx\n", nopts->flags);
}
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);
}
void ncplane_home(ncplane* n){
@ -426,8 +426,8 @@ ncplane* ncplane_dup(const ncplane* n, void* opaque){
const struct notcurses* nc = ncplane_notcurses_const(n);
const int placey = n->absy - nc->margin_t;
const int placex = n->absx - nc->margin_l;
ncplane* newn = ncplane_create(n->nc, n->boundto, dimy, dimx,
placey, placex, opaque, n->name);
ncplane* newn = ncplane_new(n->boundto, dimy, dimx,
placey, placex, opaque, n->name);
if(newn){
if(egcpool_dup(&newn->pool, &n->pool)){
ncplane_destroy(newn);

@ -6,7 +6,16 @@
static int
run_menu(struct notcurses* nc, struct ncmenu* ncm){
struct ncplane* selplane = ncplane_aligned(notcurses_stdplane(nc), 3, 40, 10, NCALIGN_CENTER, NULL, NULL);
ncplane_options nopts = {
.y = 10,
.horiz = {
.align = NCALIGN_CENTER,
},
.rows = 3,
.cols = 40,
.flags = NCPLANE_OPTION_HORALIGNED,
};
struct ncplane* selplane = ncplane_create(notcurses_stdplane(nc), &nopts);
if(selplane == NULL){
return -1;
}

Loading…
Cancel
Save