diff --git a/NEWS.md b/NEWS.md index a999277fa..fa83926f0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,8 +2,12 @@ This document attempts to list user-visible changes and any major internal rearrangements of Notcurses. * 3.0.1 (not yet released) - * Added `ncplane_growtext()`, which allows you to dump text to a plane - (ala `ncplane_puttext()`), and have it grow right along with you. + * Added the `NCPLANE_OPTION_VSCROLL` flag. Creating an `ncplane` with this + flag is equivalent to immediately calling `ncplane_set_scrolling(true)`. + * Added the `NCPLANE_OPTION_AUTOGROW` flag and the `ncplane_set_autogrow()` + and `ncplane_autogrow_p()` functions. When autogrow is enabled, the plane + is automatically enlarged to accommodate output at its right (no scrolling) + or bottom (scrolling enabled) boundaries. * 3.0.0 (2021-12-01) **"In the A"** * Made the ABI/API changes that have been planned/collected during 2.x diff --git a/USAGE.md b/USAGE.md index a34da695d..9f14ce203 100644 --- a/USAGE.md +++ b/USAGE.md @@ -787,9 +787,9 @@ When an `ncplane` is no longer needed, free it with ```c // Horizontal alignment relative to the parent plane. Use ncalign_e for 'x'. -#define NCPLANE_OPTION_HORALIGNED 0x0001ull +#define NCPLANE_OPTION_HORALIGNED 0x0001ull // Vertical alignment relative to the parent plane. Use ncalign_e for 'y'. -#define NCPLANE_OPTION_VERALIGNED 0x0002ull +#define NCPLANE_OPTION_VERALIGNED 0x0002ull // Maximize relative to the parent plane, modulo the provided margins. The // margins are best-effort; the plane will always be at least 1 column by // 1 row. If the margins can be effected, the plane will be sized to all @@ -800,7 +800,15 @@ When an `ncplane` is no longer needed, free it with // If this plane is bound to a scrolling plane, it ought *not* scroll along // with the parent (it will still move with the parent, maintaining its // relative position, if the parent is moved to a new location). -#define NCPLANE_OPTION_FIXED 0x0008ull +#define NCPLANE_OPTION_FIXED 0x0008ull +// Enable automatic growth of the plane to accommodate output. Creating a +// plane with this flag is equivalent to immediately calling +// ncplane_set_autogrow(p, true) following plane creation. +#define NCPLANE_OPTION_AUTOGROW 0x0010ull +// Enable vertical scrolling of the plane to accommodate output. Creating a +// plane with this flag is equivalent to immediately calling +// ncplane_set_scrolling(p, true) following plane creation. +#define NCPLANE_OPTION_VSCROLL 0x0020ull typedef struct ncplane_options { int y; // vertical placement relative to parent plane @@ -938,7 +946,10 @@ scrolling is enabled). // All planes are created with scrolling disabled. Scrolling can be dynamically // controlled with ncplane_set_scrolling(). Returns true if scrolling was // previously enabled, or false if it was disabled. -bool ncplane_set_scrolling(struct ncplane* n, bool scrollp); +bool ncplane_set_scrolling(struct ncplane* n, unsigned scrollp); + +// Returns true iff the plane is scrolling. +bool ncplane_scrolling_p(const struct ncplane* n); // Effect |r| scroll events on the plane |n|. Returns an error if |n| is not // a scrolling plane, and otherwise returns the number of lines scrolled. @@ -1052,6 +1063,23 @@ void ncplane_translate(const struct ncplane* src, const struct ncplane* dst, bool ncplane_translate_abs(const struct ncplane* n, int* restrict y, int* restrict x); ``` +Normally, when text reaches the end of a plane (the horizontal end unless +scrolling is enabled, and the vertical end otherwise), more cannot be written. +If a plane is autogrowing, it will be enlarged to accommodate the extra text. +If it is scrolling, it will be enlarged down; it will otherwise be enlarged +right. Note that attempting to explicitly move the cursor outside the plane is +still an error. The growth occurs when text is written, *not* when the cursor +is moved. + +```c +// By default, planes are created with autogrow disabled. Autogrow can be +// dynamically controlled with ncplane_set_autogrow(). Returns true if +// autogrow was previously enabled, or false if it was disabled. +API bool ncplane_set_autogrow(struct ncplane* n, unsigned growp); + +API bool ncplane_autogrow_p(const struct ncplane* n); +``` + If a given cell's glyph is zero, or its foreground channel is fully transparent, it is considered to have no foreground. A _default_ cell can be chosen for the `ncplane`, to be consulted in this case. If the base cell's glyph is likewise diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md index 5026e0c0b..23b718bc7 100644 --- a/doc/man/man3/notcurses_plane.3.md +++ b/doc/man/man3/notcurses_plane.3.md @@ -15,6 +15,8 @@ notcurses_plane - operations on ncplanes #define NCPLANE_OPTION_VERALIGNED 0x0002ull #define NCPLANE_OPTION_MARGINALIZED 0x0004ull #define NCPLANE_OPTION_FIXED 0x0008ull +#define NCPLANE_OPTION_AUTOGROW 0x0010ull +#define NCPLANE_OPTION_VSCROLL 0x0020ull typedef struct ncplane_options { int y; // vertical placement relative to parent plane @@ -207,10 +209,14 @@ typedef struct ncplane_options { **int ncplane_erase_region(struct ncplane* ***n***, int ***ystart***, int ***xstart***, int ***ylen***, int ***xlen***);** -**bool ncplane_set_scrolling(struct ncplane* ***n***, bool ***scrollp***);** +**bool ncplane_set_scrolling(struct ncplane* ***n***, unsigned ***scrollp***);** **bool ncplane_scrolling_p(const struct ncplane* ***n***);** +**bool ncplane_set_autogrow(struct ncplane* ***n***, unsigned ***growp***);** + +**bool ncplane_autogrow_p(const struct ncplane* ***n***);** + **int ncplane_scrollup(struct ncplane* ***n***, int ***r***);** **int ncplane_scrollup_child(struct ncplane* ***n***, const struct ncplane* ***child***);** @@ -436,10 +442,29 @@ other rows are moved up, the last row is cleared, and output begins at the beginning of the last row. This does not take place until output is generated (i.e. it is possible to fill a plane when scrolling is enabled). +Creating a plane with the **NCPLANE_OPTION_VSCROLL** flag is equivalent to +immediately calling **ncplane_set_scrolling** on that plane with an argument +of **true**. + By default, planes bound to a scrolling plane will scroll along with it, if they intersect the plane. This can be disabled by creating them with the **NCPLANE_OPTION_FIXED** flag. +## Autogrow + +Normally, once output reaches the right boundary of a plane, it is impossible +to place more output unless the cursor is first moved. If scrolling is +enabled, the cursor will automatically move down and to the left in this case, +but upon reaching the bottom right corner of the plane, it is impossible to +place more output without a scrolling event. If autogrow is in play, the plane +will automatically be enlarged to accommodate output. If scrolling is disabled, +growth takes place to the right; it otherwise takes place at the bottom. The +plane only grows in one dimension. + +Creating a plane with the **NCPLANE_OPTION_AUTOGROW** flag is equivalent to +immediately calling **ncplane_set_autogrow** on that plane with an argument +of **true**. + ## Bitmaps **ncplane_pixel_geom** retrieves pixel geometry details. **pxy** and **pxx** diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index af902bdf6..cf475a856 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1265,9 +1265,9 @@ API char* notcurses_at_yx(struct notcurses* nc, unsigned yoff, unsigned xoff, __attribute__ ((nonnull (1))); // Horizontal alignment relative to the parent plane. Use ncalign_e for 'x'. -#define NCPLANE_OPTION_HORALIGNED 0x0001ull +#define NCPLANE_OPTION_HORALIGNED 0x0001ull // Vertical alignment relative to the parent plane. Use ncalign_e for 'y'. -#define NCPLANE_OPTION_VERALIGNED 0x0002ull +#define NCPLANE_OPTION_VERALIGNED 0x0002ull // Maximize relative to the parent plane, modulo the provided margins. The // margins are best-effort; the plane will always be at least 1 column by // 1 row. If the margins can be effected, the plane will be sized to all @@ -1278,7 +1278,15 @@ API char* notcurses_at_yx(struct notcurses* nc, unsigned yoff, unsigned xoff, // If this plane is bound to a scrolling plane, it ought *not* scroll along // with the parent (it will still move with the parent, maintaining its // relative position, if the parent is moved to a new location). -#define NCPLANE_OPTION_FIXED 0x0008ull +#define NCPLANE_OPTION_FIXED 0x0008ull +// Enable automatic growth of the plane to accommodate output. Creating a +// plane with this flag is equivalent to immediately calling +// ncplane_set_autogrow(p, true) following plane creation. +#define NCPLANE_OPTION_AUTOGROW 0x0010ull +// Enable vertical scrolling of the plane to accommodate output. Creating a +// plane with this flag is equivalent to immediately calling +// ncplane_set_scrolling(p, true) following plane creation. +#define NCPLANE_OPTION_VSCROLL 0x0020ull typedef struct ncplane_options { int y; // vertical placement relative to parent plane @@ -1380,12 +1388,21 @@ API bool ncplane_translate_abs(const struct ncplane* n, int* RESTRICT y, int* RE // All planes are created with scrolling disabled. Scrolling can be dynamically // controlled with ncplane_set_scrolling(). Returns true if scrolling was // previously enabled, or false if it was disabled. -API bool ncplane_set_scrolling(struct ncplane* n, bool scrollp) +API bool ncplane_set_scrolling(struct ncplane* n, unsigned scrollp) __attribute__ ((nonnull (1))); API bool ncplane_scrolling_p(const struct ncplane* n) __attribute__ ((nonnull (1))); +// By default, planes are created with autogrow disabled. Autogrow can be +// dynamically controlled with ncplane_set_autogrow(). Returns true if +// autogrow was previously enabled, or false if it was disabled. +API bool ncplane_set_autogrow(struct ncplane* n, unsigned growp) + __attribute__ ((nonnull (1))); + +API bool ncplane_autogrow_p(const struct ncplane* n) + __attribute__ ((nonnull (1))); + // Palette API. Some terminals only support 256 colors, but allow the full // palette to be specified with arbitrary RGB colors. In all cases, it's more // performant to use indexed colors, since it's much less data to write to the @@ -2359,15 +2376,6 @@ API int ncplane_puttext(struct ncplane* n, int y, ncalign_e align, const char* text, size_t* bytes) __attribute__ ((nonnull (1, 4))); -// Like ncplane_puttext(), we're going for an orderly presentation of (possibly -// bulk) text. Unlike ncplane_puttext(), we're going to grow the plane as -// necessary to present it. If the plane is scrolling, we'll grow the bottom -// out; we'll otherwise grow out to the right. Either way, no actual scrolling -// will occur. -API int ncplane_growtext(struct ncplane* n, int y, ncalign_e align, - const char* text, size_t* bytes) - __attribute__ ((nonnull (1, 4))); - // Draw horizontal or vertical lines using the specified cell, starting at the // current cursor position. The cursor will end at the cell following the last // cell output (even, perhaps counter-intuitively, when drawing vertical diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 204aa23f8..50714ea74 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -2822,7 +2822,7 @@ ncplane* ncplane_reparent_family(ncplane* n, ncplane* newparent){ return n; } -bool ncplane_set_scrolling(ncplane* n, bool scrollp){ +bool ncplane_set_scrolling(ncplane* n, unsigned scrollp){ bool old = n->scrolling; n->scrolling = scrollp; return old;