diff --git a/USAGE.md b/USAGE.md index c0c412a0c..64a59b3f9 100644 --- a/USAGE.md +++ b/USAGE.md @@ -900,10 +900,26 @@ int ncplane_mergedown_simple(struct ncplane* restrict src, 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. +// {|ylen|x|xlen|} for non-zero lengths. If ystart and/or xstart are -1, the current +// cursor position along that axis is used; other negative values are an error. A +// negative ylen means to move up from the origin, and a negative xlen means to move +// left from the origin. A positive ylen moves down, and a positive xlen moves right. +// A value of 0 for the length erases everything along that dimension. It is an error +// if the starting coordinate is not in the plane, but the ending coordinate may be +// outside the plane. +// +// For example, on a plane of 20 rows and 10 columns, with the cursor at row 10 and +// column 5, the following would hold: +// +// (-1, -1, 0, 1): clears the column to the right of the cursor (column 6) +// (-1, -1, 0, -1): clears the column to the left of the cursor (column 4) +// (-1, -1, INT_MAX, 0): clears all rows with or below the cursor (rows 10--19) +// (-1, -1, -INT_MAX, 0): clears all rows with or above the cursor (rows 0--10) +// (-1, 4, 3, 3): clears from row 10, column 4 through row 12, column 6 +// (-1, 4, 3, 3): clears from row 10, column 4 through row 8, column 2 +// (4, -1, 0, 3): clears columns 5, 6, and 7 +// (-1, -1, 0, 0): clears the plane *if the cursor is in a legal position* +// (0, 0, 0, 0): clears the plane in all cases int ncplane_erase_region(struct ncplane* n, int ystart, int xstart, int ylen, int xlen); ``` diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md index 7fc658dd9..9672d0cf6 100644 --- a/doc/man/man3/notcurses_plane.3.md +++ b/doc/man/man3/notcurses_plane.3.md @@ -320,7 +320,11 @@ might see changes. It is an error to merge a plane onto itself. 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. See [BUGS][] below. +dimension, starting at the specified point. Supply -1 for ***ystart*** and/or +***xstart*** to use the cursor's current position along that axis for a starting +point. Negative ***ylen*** and ***xlen*** move up and to the left from the starting +coordinate; positive ***ylen*** and ***xlen*** move down and to the right from same. +See [BUGS][] below. When a plane is resized (whether by **ncplane_resize**, **SIGWINCH**, or any other mechanism), a depth-first recursion is performed on its children. @@ -444,8 +448,8 @@ plane is destroyed. The caller should release this **nccell** with **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. +**ncplane_erase_region** returns -1 if **ystart** or **xstart** are less than -1, +or outside the plane. **ncplane_cursor_move_yx** returns -1 if the coordinates are beyond the dimensions of the specified plane (except for the special value -1). @@ -480,6 +484,12 @@ ncplane_set_base(notcurses_stdplane(nc), " ", 0, 0); notcurses_render(nc); ``` +or simply: + +```c +notcurses_refresh(nc); +``` + # SEE ALSO **notcurses(3)**, diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 89d557f3f..39f065d1a 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2231,10 +2231,26 @@ API int ncplane_mergedown(struct ncplane* RESTRICT src, 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. +// {|ylen|x|xlen|} for non-zero lengths. If ystart and/or xstart are -1, the current +// cursor position along that axis is used; other negative values are an error. A +// negative ylen means to move up from the origin, and a negative xlen means to move +// left from the origin. A positive ylen moves down, and a positive xlen moves right. +// A value of 0 for the length erases everything along that dimension. It is an error +// if the starting coordinate is not in the plane, but the ending coordinate may be +// outside the plane. +// +// For example, on a plane of 20 rows and 10 columns, with the cursor at row 10 and +// column 5, the following would hold: +// +// (-1, -1, 0, 1): clears the column to the right of the cursor (column 6) +// (-1, -1, 0, -1): clears the column to the left of the cursor (column 4) +// (-1, -1, INT_MAX, 0): clears all rows with or below the cursor (rows 10--19) +// (-1, -1, -INT_MAX, 0): clears all rows with or above the cursor (rows 0--10) +// (-1, 4, 3, 3): clears from row 10, column 4 through row 12, column 6 +// (-1, 4, 3, 3): clears from row 10, column 4 through row 8, column 2 +// (4, -1, 0, 3): clears columns 5, 6, and 7 +// (-1, -1, 0, 0): clears the plane *if the cursor is in a legal position* +// (0, 0, 0, 0): clears the plane in all cases API int ncplane_erase_region(struct ncplane* n, int ystart, int xstart, int ylen, int xlen) __attribute__ ((nonnull (1))); diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index c3bb05eb8..9887599cb 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -2122,27 +2122,44 @@ void ncplane_erase(ncplane* n){ } int ncplane_erase_region(ncplane* n, int ystart, int xstart, int ylen, int xlen){ - if(ylen < 0 || xlen < 0){ - logerror("Won't erase section of negative length (%d, %d)\n", ylen, xlen); - return -1; + if(ystart == -1){ + ystart = n->y; + } + if(xstart == -1){ + xstart = n->x; } if(ystart < 0 || xstart < 0){ logerror("Illegal start of erase (%d, %d)\n", ystart, xstart); return -1; } - if(ystart >= ncplane_dim_y(n) || ystart + ylen > ncplane_dim_y(n)){ - logerror("Illegal y spec for erase (%d, %d)\n", ystart, ylen); + if(ystart >= ncplane_dim_y(n) || xstart >= ncplane_dim_x(n)){ + logerror("Illegal start of erase (%d, %d)\n", ystart, xstart); return -1; } if(ylen == 0){ - ylen = ncplane_dim_y(n) - ystart; + ystart = 0; + ylen = ncplane_dim_y(n); } - if(xstart >= ncplane_dim_x(n) || xstart + xlen > ncplane_dim_x(n)){ - logerror("Illegal x spec for erase (%d, %d)\n", xstart, xlen); + if(ystart + ylen > ncplane_dim_y(n) || ystart + ylen < -1){ + logerror("Illegal y spec for erase (%d, %d)\n", ystart, ylen); return -1; } if(xlen == 0){ - xlen = ncplane_dim_x(n) - xstart; + xstart = 0; + xlen = ncplane_dim_x(n); + } + if(xstart + xlen > ncplane_dim_x(n) || xstart + xlen < -1){ + logerror("Illegal x spec for erase (%d, %d)\n", xstart, xlen); + return -1; + } + if(xlen < 0){ + xstart = xstart + xlen; + xlen = -xlen; + } + if(ylen < 0){ + ystart = ystart + ylen; + ylen = -ylen; +>>>>>>> 4e10ad795 ([ncplane_erase_region] generalize #2181) } for(int y = ystart ; y < ystart + ylen ; ++y){ for(int x = xstart ; x < xstart + xlen ; ++x){ diff --git a/src/tests/erase.cpp b/src/tests/erase.cpp new file mode 100644 index 000000000..21cd502a4 --- /dev/null +++ b/src/tests/erase.cpp @@ -0,0 +1,31 @@ +#include +#include +#include "main.h" + +TEST_CASE("Erase") { + auto nc_ = testing_notcurses(); + if(!nc_){ + return; + } + struct ncplane* n_ = notcurses_stdplane(nc_); + REQUIRE(n_); + + // clear all columns to the left of cursor, inclusive + SUBCASE("EraseColumnsLeft") { + } + + // clear all columns to the right of cursor, inclusive + SUBCASE("EraseColumnsRight") { + } + + // clear all rows above cursor, inclusive + SUBCASE("EraseRowsLeft") { + } + + // clear all rows below cursor, inclusive + SUBCASE("EraseRowsBelow") { + } + + CHECK(0 == notcurses_stop(nc_)); + +}