diff --git a/NEWS.md b/NEWS.md index 4a8ba7a4c..9745ac70a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,8 @@ rearrangements of Notcurses. static linking on systems with libtinfo embedded into libncurses. * Added `ncblit_rgb_loose()` and `ncblit_rgb_packed()` helpers for blitting 32bpp RGBx and 24bpp RGB. + * Added `ncplane_erase_region()` to initialize all `nccell`s within a + region of a plane. * 2.2.10 (2021-05-05) * Added `NCVISUAL_OPTION_CHILDPLANE` to interpret the `n` field of diff --git a/USAGE.md b/USAGE.md index c1d234ad7..0862144eb 100644 --- a/USAGE.md +++ b/USAGE.md @@ -820,6 +820,14 @@ int ncplane_mergedown_simple(const ncplane* restrict src, ncplane* restrict dst) // with this ncplane are invalidated, and must not be used after the call, // excluding the base cell. The cursor is homed. void ncplane_erase(struct ncplane* n); + +// Erase every cell in the region starting at {ystart, xstart} and having size +// {ylen, xlen}. It is an error if any of ystart, xstart, ylen, or xlen is +// negative. A value of 0 may be provided for ylen and/or xlen, meaning to +// erase everything along that dimension. It is an error if ystart + ylen +// or xstart + xlen is not in the plane. +int ncplane_erase_region(struct ncplane* n, int ystart, int xstart, + int ylen, int xlen); ``` All planes, including the standard plane, are created with scrolling disabled. diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md index 6e2c0168b..ac4a333bb 100644 --- a/doc/man/man3/notcurses_plane.3.md +++ b/doc/man/man3/notcurses_plane.3.md @@ -192,6 +192,8 @@ typedef struct ncplane_options { **void ncplane_erase(struct ncplane* ***n***);** +**int ncplane_erase_region(struct ncplane* ***n***, int ***ystart***, int ***xstart***, int ***ylen***, int ***xlen***);** + **bool ncplane_set_scrolling(struct ncplane* ***n***, bool ***scrollp***);** **int ncplane_rotate_cw(struct ncplane* ***n***);** @@ -286,6 +288,9 @@ 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, as are the active attributes. +**ncplane_erase_region** does the same for a subregion of the plane. For the +latter, supply 0 for ***ylen*** and/or ***xlen*** to erase through that +dimension, starting at the specified point. When a plane is resized (whether by **ncplane_resize**, **SIGWINCH**, or any other mechanism), a depth-first recursion is performed on its children. @@ -397,6 +402,9 @@ destroyed. The caller should release this **nccell** with **nccell_release**. **ncplane_as_rgba** returns a heap-allocated array of **uint32_t** values, each representing a single RGBA pixel, or **NULL** on failure. +**ncplane_erase_region** returns -1 if any of its parameters are negative, or +if they specify any area beyond the plane. + Functions returning **int** return 0 on success, and non-zero on error. All other functions cannot fail (and return **void**). diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 30ef7b477..adfa776ee 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1982,6 +1982,15 @@ API int ncplane_mergedown(struct ncplane* RESTRICT src, // The cursor is homed. The plane's active attributes are unaffected. API void ncplane_erase(struct ncplane* n); +// Erase every cell in the region starting at {ystart, xstart} and having size +// {ylen, xlen}. It is an error if any of ystart, xstart, ylen, or xlen is +// negative. A value of 0 may be provided for ylen and/or xlen, meaning to +// erase everything along that dimension. It is an error if ystart + ylen +// or xstart + xlen is not in the plane. +API int ncplane_erase_region(struct ncplane* n, int ystart, int xstart, + int ylen, int xlen) + __attribute__ ((nonnull (1))); + // Extract 24 bits of foreground RGB from 'cl', shifted to LSBs. static inline uint32_t nccell_fg_rgb(const nccell* cl){ diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 4ed6870ed..8cf9dd6b8 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -2030,6 +2030,39 @@ void ncplane_erase(ncplane* n){ n->y = n->x = 0; } +int ncplane_erase_region(ncplane* n, int ystart, int xstart, int ylen, int xlen){ + const notcurses* nc = ncplane_notcurses_const(n); + if(ylen < 0 || xlen < 0){ + logerror(nc, "Won't erase section of negative length (%d, %d)\n", ylen, xlen); + return -1; + } + if(ystart < 0 || xstart < 0){ + logerror(nc, "Illegal start of erase (%d, %d)\n", ystart, xstart); + return -1; + } + if(ystart >= ncplane_dim_y(n) || ystart + ylen > ncplane_dim_y(n)){ + logerror(nc, "Illegal y spec for erase (%d, %d)\n", ystart, ylen); + return -1; + } + if(ylen == 0){ + ylen = ncplane_dim_y(n) - ystart; + } + if(xstart >= ncplane_dim_x(n) || xstart + xlen > ncplane_dim_x(n)){ + logerror(nc, "Illegal x spec for erase (%d, %d)\n", xstart, xlen); + return -1; + } + if(xlen == 0){ + xlen = ncplane_dim_x(n) - ystart; + } + for(int y = ystart ; y < ystart + ylen ; ++y){ + for(int x = xstart ; x < xstart + xlen ; ++x){ + nccell_release(n, &n->fb[nfbcellidx(n, y, x)]); + nccell_init(&n->fb[nfbcellidx(n, y, x)]); + } + } + return 0; +} + ncplane* notcurses_top(notcurses* n){ return ncplane_pile(n->stdplane)->top; }