Normalize ncplane_at_* / ncplane_set_base() (#479)

* ncplane_at_* and ncplane_at_cursor_*

We had notcurses_at_yx() expanding into three distinct parts of
the cell structure, and ncplane_at_yx() / ncplane_at_cursor()
writing directly to a cell. It was annoying to remember which
was which. The latter two now have a signature matching
notcurses_at_yx(), while the old functionality has been moved
to ncplane_at_yx_cell() and ncplane_at_cursor_yx(). #476
This commit is contained in:
Nick Black 2020-04-18 00:09:14 -04:00 committed by GitHub
parent 50e0870432
commit c6a9997554
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 439 additions and 333 deletions

View File

@ -1,19 +1,36 @@
This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 1.3.1
* 1.3.1 (not yet released)
* `ncplane_at_yx()` and `ncplane_at_cursor()` have been changed to return a
heap-allocated EGC, and write the attributes and channels to value-result
`uint32_t*` and `uint64_t*` parameters, instead of to a `cell*`. This
matches `notcurses_at_yx()`, and means they're no longer invalidated if the
plane in question is destroyed. The previous functionality is available as
new functions `ncplane_at_yx_cell()` and `ncplane_at_cursor_cell()`.
* `ncplane_set_base()` inverted its `uint32_t attrword` and `uint64_t channels`
parameters, thus matching every other function with these two parameters.
It moved `const char* egc` before either, to force a type error, as the
change would otherwise be likely to go overlooked.
* The C++ `Notcurses::render()` function now returns non-zero on failure,
mirroring the behavior of the core C `notcurses_render()`. This is an
inversion of its previous behavior.
mirroring the behavior of the core C `notcurses_render()`. This is an
inversion of its previous behavior.
* 1.2.8
* 1.3.0 (2020-04-12)
* No user-visible changes
* 1.2.9 (2020-04-11)
* No user-visible changes
* 1.2.8 (2020-04-10)
* `notcurses-tetris` now happily continues if it can't load its background.
* 1.2.7
* 1.2.7 (2020-04-10)
* Plots now always keep the most recent data to their far right (i.e., the
gap that is initially filled is on the left, rather than the right).
* 1.2.6
* 1.2.6 (2020-04-08)
* `ncplane_putsimple_yx()` and `ncplane_putstr_yx()` have been exported as
static inline functions.
* `ncplane_set_scrolling()` has been added, allowing control over whether a
@ -35,7 +52,7 @@ rearrangements of Notcurses.
`notcurses_resize()` internally, as `notcurses_render()` always has).
* First Fedora packaging.
* 1.2.5
* 1.2.5 (2020-04-05)
* Add ncplot, with support for sliding-windowed horizontal histograms.
* gradient, polyfill, `ncplane_format()` and `ncplane_stain()` all now return
the number of cells written on success. Failure still sees -1 returned.
@ -51,6 +68,6 @@ rearrangements of Notcurses.
and a source of blunders. The EGC is returned via the `char*` return
value. https://github.com/dankamongmen/notcurses/issues/410
* 1.2.4 2020-03-24
* 1.2.4 (2020-03-24)
* Add ncmultiselector
* Add `ncdirect_cursor_enable()` and `ncdirect_cursor_disable()`.

View File

@ -789,8 +789,8 @@ int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);
// rendering anywhere that the ncplane's gcluster is 0. Erasing the ncplane
// does not reset the base cell; this function must be called with an empty
// 'egc'. 'egc' must be a single extended grapheme cluster.
int ncplane_set_base(struct ncplane* ncp, uint64_t channels,
uint32_t attrword, const char* egc);
int ncplane_set_base(struct ncplane* ncp, const char* egc,
uint32_t attrword, uint64_t channels);
// Extract the ncplane's base cell into 'c'. The reference is invalidated if
// 'ncp' is destroyed.
@ -820,13 +820,24 @@ addition, the plane's virtual framebuffer can be accessed (note that this does
not necessarily reflect anything on the actual screen).
```c
// Retrieve the cell at the cursor location on the specified plane, returning
// it in 'c'. This copy is safe to use until the ncplane is destroyed/erased.
int ncplane_at_cursor(struct ncplane* n, cell* c);
// Retrieve the current contents of the cell under the cursor. The EGC is
// returned, or NULL on error. This EGC must be free()d by the caller. The
// attrword and channels are written to 'attrword' and 'channels', respectively.
char* ncplane_at_cursor(struct ncplane* n, uint32_t* attrword, uint64_t* channels);
// Retrieve the cell at the specified location on the specified plane, returning
// it in 'c'. This copy is safe to use until the ncplane is destroyed/erased.
int ncplane_at_yx(struct ncplane* n, int y, int x, cell* c);
// Retrieve the current contents of the cell under the cursor into 'c'. This
// cell is invalidated if the associated plane is destroyed.
int ncplane_at_cursor_cell(struct ncplane* n, cell* c);
// Retrieve the current contents of the specified cell. The EGC is returned, or
// NULL on error. This EGC must be free()d by the caller. The attrword and
// channels are written to 'attrword' and 'channels', respectively.
char* ncplane_at_yx(struct ncplane* n, int y, int x,
uint32_t* attrword, uint64_t* channels);
// Retrieve the current contents of the specified cell into 'c'. This cell is
// invalidated if the associated plane is destroyed.
int ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c);
// Manipulate the opaque user pointer associated with this plane.
// ncplane_set_userptr() returns the previous userptr after replacing

View File

@ -28,7 +28,7 @@ notcurses_ncplane - operations on notcurses planes
**int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);**
**int ncplane_set_base(struct ncplane* ncp, uint64_t channels, uint32_t attrword, const char* egc);**
**int ncplane_set_base(struct ncplane* ncp, const char* egc, uint32_t attrword, uint64_t channels);**
**int ncplane_base(struct ncplane* ncp, cell* c);**
@ -42,9 +42,13 @@ notcurses_ncplane - operations on notcurses planes
**struct ncplane* ncplane_below(struct ncplane* n);**
**int ncplane_at_cursor(struct ncplane* n, cell* c);**
**char* ncplane_at_cursor(struct ncplane* n, uint32_t* attrword, uint64_t* channels);**
**int ncplane_at_yx(struct ncplane* n, int y, int x, cell* c);**
**int ncplane_at_cursor_cell(struct ncplane* n, cell* c);**
**char* ncplane_at_yx(struct ncplane* n, int y, int x, uint32_t* attrword, uint64_t* channels);**
**int ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c);**
**void* ncplane_set_userptr(struct ncplane* n, void* opaque);**
@ -218,6 +222,12 @@ plane is the bottommost plane, NULL is returned. It cannot fail.
**ncplane_set_scrolling** returns **true** if scrolling was previously enabled,
and **false** otherwise.
**ncplane_at_yx** and **ncplane_at_cursor** return a heap-allocated copy of the
EGC at the relevant cell, or NULL if the cell is invalid. The caller should free
this result. **ncplane_at_yx_cell** and **ncplane_at_cursor_cell** instead load
these values into a **cell**, which is invalidated if the associated plane is
destroyed. The caller should release this cell with **cell_release**.
Functions returning **int** return 0 on success, and non-zero on error.
All other functions cannot fail (and return **void**).

View File

@ -585,8 +585,8 @@ namespace ncpp
}
bool box (const Cell &ul, const Cell &ur, const Cell &ll, const Cell &lr,
const Cell &hline, const Cell &vline, int ystop, int xstop,
unsigned ctlword) const NOEXCEPT_MAYBE
const Cell &hline, const Cell &vline, int ystop, int xstop,
unsigned ctlword) const NOEXCEPT_MAYBE
{
return error_guard (ncplane_box (plane, ul, ur, ll, lr, hline, vline, ystop, xstop, ctlword), -1);
}
@ -779,9 +779,9 @@ namespace ncpp
return error_guard_cond<bool, bool> (ret, ret);
}
bool set_base (uint64_t channels, uint32_t attrword, const char *egc) const NOEXCEPT_MAYBE
bool set_base (const char* egc, uint32_t attrword, uint64_t channels) const NOEXCEPT_MAYBE
{
bool ret = ncplane_set_base (plane, channels, attrword, egc) < 0;
bool ret = ncplane_set_base (plane, egc, attrword, channels) < 0;
return error_guard_cond<bool, bool> (ret, ret);
}
@ -793,7 +793,7 @@ namespace ncpp
bool at_cursor (Cell &c) const NOEXCEPT_MAYBE
{
bool ret = ncplane_at_cursor (plane, c) < 0;
bool ret = ncplane_at_cursor_cell (plane, c) < 0;
return error_guard_cond<bool, bool> (ret, ret);
}
@ -805,9 +805,17 @@ namespace ncpp
return at_cursor (*c);
}
char* at_cursor (uint32_t* attrword, uint64_t* channels) const
{
if (attrword == nullptr || channels == nullptr)
return nullptr;
return ncplane_at_cursor (plane, attrword, channels);
}
int get_at (int y, int x, Cell &c) const NOEXCEPT_MAYBE
{
return error_guard (ncplane_at_yx (plane, y, x, c), -1);
return error_guard<int> (ncplane_at_yx_cell (plane, y, x, c), -1);
}
int get_at (int y, int x, Cell *c) const
@ -818,6 +826,14 @@ namespace ncpp
return get_at (y, x, *c);
}
char* get_at (int y, int x, uint32_t* attrword, uint64_t* channels) const
{
if (attrword == nullptr || channels == nullptr)
return nullptr;
return ncplane_at_yx (plane, y, x, attrword, channels);
}
void* set_userptr (void *opaque) const noexcept
{
return ncplane_set_userptr (plane, opaque);

View File

@ -524,6 +524,198 @@ typedef struct cell {
uint64_t channels; // + 8B == 16B
} cell;
#define CELL_TRIVIAL_INITIALIZER { .gcluster = '\0', .attrword = 0, .channels = 0, }
#define CELL_SIMPLE_INITIALIZER(c) { .gcluster = (c), .attrword = 0, .channels = 0, }
#define CELL_INITIALIZER(c, a, chan) { .gcluster = (c), .attrword = (a), .channels = (chan), }
static inline void
cell_init(cell* c){
memset(c, 0, sizeof(*c));
}
// Breaks the UTF-8 string in 'gcluster' down, setting up the cell 'c'. Returns
// the number of bytes copied out of 'gcluster', or -1 on failure. The styling
// of the cell is left untouched, but any resources are released.
API int cell_load(struct ncplane* n, cell* c, const char* gcluster);
// cell_load(), plus blast the styling with 'attr' and 'channels'.
static inline int
cell_prime(struct ncplane* n, cell* c, const char* gcluster,
uint32_t attr, uint64_t channels){
c->attrword = attr;
c->channels = channels;
int ret = cell_load(n, c, gcluster);
return ret;
}
// Duplicate 'c' into 'targ'; both must be/will be bound to 'n'.
API int cell_duplicate(struct ncplane* n, cell* targ, const cell* c);
// Release resources held by the cell 'c'.
API void cell_release(struct ncplane* n, cell* c);
#define NCSTYLE_MASK 0xffff0000ul
#define NCSTYLE_STANDOUT 0x00800000ul
#define NCSTYLE_UNDERLINE 0x00400000ul
#define NCSTYLE_REVERSE 0x00200000ul
#define NCSTYLE_BLINK 0x00100000ul
#define NCSTYLE_DIM 0x00080000ul
#define NCSTYLE_BOLD 0x00040000ul
#define NCSTYLE_INVIS 0x00020000ul
#define NCSTYLE_PROTECT 0x00010000ul
#define NCSTYLE_ITALIC 0x01000000ul
// Set the specified style bits for the cell 'c', whether they're actively
// supported or not.
static inline void
cell_styles_set(cell* c, unsigned stylebits){
c->attrword = (c->attrword & ~NCSTYLE_MASK) | ((stylebits & NCSTYLE_MASK));
}
// Extract the style bits from the cell's attrword.
static inline unsigned
cell_styles(const cell* c){
return c->attrword & NCSTYLE_MASK;
}
// Add the specified styles (in the LSBs) to the cell's existing spec, whether
// they're actively supported or not.
static inline void
cell_styles_on(cell* c, unsigned stylebits){
c->attrword |= (stylebits & NCSTYLE_MASK);
}
// Remove the specified styles (in the LSBs) from the cell's existing spec.
static inline void
cell_styles_off(cell* c, unsigned stylebits){
c->attrword &= ~(stylebits & NCSTYLE_MASK);
}
// Use the default color for the foreground.
static inline void
cell_set_fg_default(cell* c){
channels_set_fg_default(&c->channels);
}
// Use the default color for the background.
static inline void
cell_set_bg_default(cell* c){
channels_set_bg_default(&c->channels);
}
static inline int
cell_set_fg_alpha(cell* c, int alpha){
return channels_set_fg_alpha(&c->channels, alpha);
}
static inline int
cell_set_bg_alpha(cell* c, int alpha){
return channels_set_bg_alpha(&c->channels, alpha);
}
// Does the cell contain an East Asian Wide codepoint?
static inline bool
cell_double_wide_p(const cell* c){
return (c->channels & CELL_WIDEASIAN_MASK);
}
// Is this the right half of a wide character?
static inline bool
cell_wide_right_p(const cell* c){
return cell_double_wide_p(c) && c->gcluster == 0;
}
// Is this the left half of a wide character?
static inline bool
cell_wide_left_p(const cell* c){
return cell_double_wide_p(c) && c->gcluster;
}
// Is the cell simple (a lone ASCII character, encoded as such)?
static inline bool
cell_simple_p(const cell* c){
return c->gcluster < 0x80;
}
// return a pointer to the NUL-terminated EGC referenced by 'c'. this pointer
// is invalidated by any further operation on the plane 'n', so...watch out!
API const char* cell_extended_gcluster(const struct ncplane* n, const cell* c);
// Extract the EGC from 'c' as a nul-terminated string.
static inline char*
cell_strdup(const struct ncplane* n, const cell* c){
char* ret;
if(cell_simple_p(c)){
if( (ret = (char*)malloc(2)) ){ // cast is here for C++ clients
ret[0] = c->gcluster;
ret[1] = '\0';
}
}else{
ret = strdup(cell_extended_gcluster(n, c));
}
return ret;
}
// Extract the three elements of a cell.
static inline char*
cell_extract(const struct ncplane* n, const cell* c, uint32_t* attrword, uint64_t* channels){
if(attrword){
*attrword = c->attrword;
}
if(channels){
*channels = c->channels;
}
return cell_strdup(n, c);
}
// Returns true if the two cells are distinct EGCs, attributes, or channels.
// The actual egcpool index needn't be the same--indeed, the planes needn't even
// be the same. Only the expanded EGC must be equal. The EGC must be bit-equal;
// it would probably be better to test whether they're Unicode-equal FIXME.
static inline bool
cellcmp(const struct ncplane* n1, const cell* RESTRICT c1,
const struct ncplane* n2, const cell* RESTRICT c2){
if(c1->attrword != c2->attrword){
return true;
}
if(c1->channels != c2->channels){
return true;
}
if(cell_simple_p(c1) && cell_simple_p(c2)){
return c1->gcluster != c2->gcluster;
}
if(cell_simple_p(c1) || cell_simple_p(c2)){
return true;
}
return strcmp(cell_extended_gcluster(n1, c1), cell_extended_gcluster(n2, c2));
}
// True if the cell does not generate foreground pixels (i.e., the cell is
// entirely whitespace or special characters).
// FIXME do this at cell prep time and set a bit in the channels
static inline bool
cell_noforeground_p(const cell* c){
return cell_simple_p(c) && (c->gcluster == ' ' || !isprint(c->gcluster));
}
static inline int
cell_load_simple(struct ncplane* n, cell* c, char ch){
cell_release(n, c);
c->channels &= ~CELL_WIDEASIAN_MASK;
c->gcluster = ch;
if(cell_simple_p(c)){
return 1;
}
return -1;
}
// get the offset into the egcpool for this cell's EGC. returns meaningless and
// unsafe results if called on a simple cell.
static inline uint32_t
cell_egc_idx(const cell* c){
return c->gcluster - 0x80;
}
// These log levels consciously map cleanly to those of libav; notcurses itself
// does not use this full granularity. The log level does not affect the opening
// and closing banners, which can be disabled via the notcurses_option struct's
@ -862,8 +1054,8 @@ API int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);
// rendering anywhere that the ncplane's gcluster is 0. Erasing the ncplane
// does not reset the base cell; this function must be called with an empty
// 'egc'. 'egc' must be a single extended grapheme cluster.
API int ncplane_set_base(struct ncplane* ncp, uint64_t channels,
uint32_t attrword, const char* egc);
API int ncplane_set_base(struct ncplane* ncp, const char* egc,
uint32_t attrword, uint64_t channels);
// Extract the ncplane's base cell into 'c'. The reference is invalidated if
// 'ncp' is destroyed.
@ -914,14 +1106,50 @@ API struct ncplane* ncplane_below(struct ncplane* n);
API int ncplane_rotate_cw(struct ncplane* n);
API int ncplane_rotate_ccw(struct ncplane* n);
// Retrieve the cell at the cursor location on the specified plane, returning
// it in 'c'. This copy is safe to use until the ncplane is destroyed/erased.
API int ncplane_at_cursor(struct ncplane* n, cell* c);
// Retrieve the current contents of the cell under the cursor. The EGC is
// returned, or NULL on error. This EGC must be free()d by the caller. The
// attrword and channels are written to 'attrword' and 'channels', respectively.
API char* ncplane_at_cursor(struct ncplane* n, uint32_t* attrword, uint64_t* channels);
// Retrieve the cell at the specified location on the specified plane, returning
// it in 'c'. This copy is safe to use until the ncplane is destroyed/erased.
// Returns the length of the EGC in bytes.
API int ncplane_at_yx(struct ncplane* n, int y, int x, cell* c);
// Retrieve the current contents of the cell under the cursor into 'c'. This
// cell is invalidated if the associated plane is destroyed.
static inline int
ncplane_at_cursor_cell(struct ncplane* n, cell* c){
char* egc = ncplane_at_cursor(n, &c->attrword, &c->channels);
if(!egc){
return -1;
}
uint64_t channels = c->channels; // need to preserve wide flag
int r = cell_load(n, c, egc);
c->channels = channels;
if(r < 0){
free(egc);
}
return r;
}
// Retrieve the current contents of the specified cell. The EGC is returned, or
// NULL on error. This EGC must be free()d by the caller. The attrword and
// channels are written to 'attrword' and 'channels', respectively.
API char* ncplane_at_yx(struct ncplane* n, int y, int x,
uint32_t* attrword, uint64_t* channels);
// Retrieve the current contents of the specified cell into 'c'. This cell is
// invalidated if the associated plane is destroyed.
static inline int
ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c){
char* egc = ncplane_at_yx(n, y, x, &c->attrword, &c->channels);
if(!egc){
return -1;
}
uint64_t channels = c->channels; // need to preserve wide flag
int r = cell_load(n, c, egc);
c->channels = channels;
if(r < 0){
free(egc);
}
return r;
}
// Manipulate the opaque user pointer associated with this plane.
// ncplane_set_userptr() returns the previous userptr after replacing
@ -958,174 +1186,6 @@ API void ncplane_cursor_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRI
API uint64_t ncplane_channels(const struct ncplane* n);
API uint32_t ncplane_attr(const struct ncplane* n);
// Working with cells
#define CELL_TRIVIAL_INITIALIZER { .gcluster = '\0', .attrword = 0, .channels = 0, }
#define CELL_SIMPLE_INITIALIZER(c) { .gcluster = (c), .attrword = 0, .channels = 0, }
#define CELL_INITIALIZER(c, a, chan) { .gcluster = (c), .attrword = (a), .channels = (chan), }
static inline void
cell_init(cell* c){
memset(c, 0, sizeof(*c));
}
// Breaks the UTF-8 string in 'gcluster' down, setting up the cell 'c'. Returns
// the number of bytes copied out of 'gcluster', or -1 on failure. The styling
// of the cell is left untouched, but any resources are released.
API int cell_load(struct ncplane* n, cell* c, const char* gcluster);
// cell_load(), plus blast the styling with 'attr' and 'channels'.
static inline int
cell_prime(struct ncplane* n, cell* c, const char* gcluster,
uint32_t attr, uint64_t channels){
c->attrword = attr;
c->channels = channels;
int ret = cell_load(n, c, gcluster);
return ret;
}
// Duplicate 'c' into 'targ'. Not intended for external use; exposed for the
// benefit of unit tests.
API int cell_duplicate(struct ncplane* n, cell* targ, const cell* c);
// Release resources held by the cell 'c'.
API void cell_release(struct ncplane* n, cell* c);
#define NCSTYLE_MASK 0xffff0000ul
#define NCSTYLE_STANDOUT 0x00800000ul
#define NCSTYLE_UNDERLINE 0x00400000ul
#define NCSTYLE_REVERSE 0x00200000ul
#define NCSTYLE_BLINK 0x00100000ul
#define NCSTYLE_DIM 0x00080000ul
#define NCSTYLE_BOLD 0x00040000ul
#define NCSTYLE_INVIS 0x00020000ul
#define NCSTYLE_PROTECT 0x00010000ul
#define NCSTYLE_ITALIC 0x01000000ul
// Set the specified style bits for the cell 'c', whether they're actively
// supported or not.
static inline void
cell_styles_set(cell* c, unsigned stylebits){
c->attrword = (c->attrword & ~NCSTYLE_MASK) | ((stylebits & NCSTYLE_MASK));
}
// Extract the style bits from the cell's attrword.
static inline unsigned
cell_styles(const cell* c){
return c->attrword & NCSTYLE_MASK;
}
// Add the specified styles (in the LSBs) to the cell's existing spec, whether
// they're actively supported or not.
static inline void
cell_styles_on(cell* c, unsigned stylebits){
c->attrword |= (stylebits & NCSTYLE_MASK);
}
// Remove the specified styles (in the LSBs) from the cell's existing spec.
static inline void
cell_styles_off(cell* c, unsigned stylebits){
c->attrword &= ~(stylebits & NCSTYLE_MASK);
}
// Use the default color for the foreground.
static inline void
cell_set_fg_default(cell* c){
channels_set_fg_default(&c->channels);
}
// Use the default color for the background.
static inline void
cell_set_bg_default(cell* c){
channels_set_bg_default(&c->channels);
}
static inline int
cell_set_fg_alpha(cell* c, int alpha){
return channels_set_fg_alpha(&c->channels, alpha);
}
static inline int
cell_set_bg_alpha(cell* c, int alpha){
return channels_set_bg_alpha(&c->channels, alpha);
}
// Does the cell contain an East Asian Wide codepoint?
static inline bool
cell_double_wide_p(const cell* c){
return (c->channels & CELL_WIDEASIAN_MASK);
}
// Is this the right half of a wide character?
static inline bool
cell_wide_right_p(const cell* c){
return cell_double_wide_p(c) && c->gcluster == 0;
}
// Is this the left half of a wide character?
static inline bool
cell_wide_left_p(const cell* c){
return cell_double_wide_p(c) && c->gcluster;
}
// Is the cell simple (a lone ASCII character, encoded as such)?
static inline bool
cell_simple_p(const cell* c){
return c->gcluster < 0x80;
}
// return a pointer to the NUL-terminated EGC referenced by 'c'. this pointer
// is invalidated by any further operation on the plane 'n', so...watch out!
API const char* cell_extended_gcluster(const struct ncplane* n, const cell* c);
// Returns true if the two cells are distinct EGCs, attributes, or channels.
// The actual egcpool index needn't be the same--indeed, the planes needn't even
// be the same. Only the expanded EGC must be equal. The EGC must be bit-equal;
// it would probably be better to test whether they're Unicode-equal FIXME.
static inline bool
cellcmp(const struct ncplane* n1, const cell* RESTRICT c1,
const struct ncplane* n2, const cell* RESTRICT c2){
if(c1->attrword != c2->attrword){
return true;
}
if(c1->channels != c2->channels){
return true;
}
if(cell_simple_p(c1) && cell_simple_p(c2)){
return c1->gcluster != c2->gcluster;
}
if(cell_simple_p(c1) || cell_simple_p(c2)){
return true;
}
return strcmp(cell_extended_gcluster(n1, c1), cell_extended_gcluster(n2, c2));
}
// True if the cell does not generate foreground pixels (i.e., the cell is
// entirely whitespace or special characters).
// FIXME do this at cell prep time and set a bit in the channels
static inline bool
cell_noforeground_p(const cell* c){
return cell_simple_p(c) && (c->gcluster == ' ' || !isprint(c->gcluster));
}
static inline int
cell_load_simple(struct ncplane* n, cell* c, char ch){
cell_release(n, c);
c->channels &= ~CELL_WIDEASIAN_MASK;
c->gcluster = ch;
if(cell_simple_p(c)){
return 1;
}
return -1;
}
// get the offset into the egcpool for this cell's EGC. returns meaningless and
// unsafe results if called on a simple cell.
static inline uint32_t
cell_egc_idx(const cell* c){
return c->gcluster - 0x80;
}
// Replace the cell at the specified coordinates with the provided cell 'c',
// and advance the cursor by the width of the cell (but not past the end of the
// plane). On success, returns the number of columns the cursor was advanced.

View File

@ -93,7 +93,7 @@ typedef struct ncinput {
uint64_t seqnum;
} ncinput;
int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);
int ncplane_set_base(struct ncplane* ncp, uint64_t channels, uint32_t attrword, const char* egc);
int ncplane_set_base(struct ncplane* ncp, const char* egc, uint32_t attrword, uint64_t channels);
int ncplane_base(struct ncplane* ncp, cell* c);
struct ncplane* notcurses_top(struct notcurses* n);
void notcurses_drop_planes(struct notcurses* nc);
@ -128,8 +128,10 @@ int ncplane_move_below(struct ncplane* n, struct ncplane* below);
int ncplane_move_above(struct ncplane* n, struct ncplane* above);
struct ncplane* ncplane_below(struct ncplane* n);
char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff, uint32_t* attrword, uint64_t* channels);
int ncplane_at_cursor(struct ncplane* n, cell* c);
int ncplane_at_yx(struct ncplane* n, int y, int x, cell* c);
char* ncplane_at_cursor(struct ncplane* n, uint32_t* attrword, uint64_t* channels);
int ncplane_at_cursor_cell(struct ncplane* n, cell* c);
char* ncplane_at_yx(struct ncplane* n, int y, int x, uint32_t* attrword, uint64_t* channels);
int ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c);
void* ncplane_set_userptr(struct ncplane* n, void* opaque);
void* ncplane_userptr(struct ncplane* n);
int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny,

View File

@ -5,30 +5,24 @@
static int
reload_corners(struct ncplane* n, cell* ul, cell* ur, cell* ll, cell* lr){
int dimy, dimx;
ncplane_dim_yx(n, &dimy, &dimx);
cell c = CELL_TRIVIAL_INITIALIZER;
if(ncplane_at_yx(n, 1, dimx - 1, &c) < 0){
cell_release(n, &c);
char* egc;
if( (egc = ncplane_at_yx(n, 1, dimx - 1, NULL, &ul->channels)) == NULL){
return -1;
}
ul->channels = c.channels;
if(ncplane_at_yx(n, dimy - 1, dimx - 1, &c) < 0){
cell_release(n, &c);
free(egc);
if( (egc = ncplane_at_yx(n, dimy - 1, dimx - 1, NULL, &ur->channels)) == NULL){
return -1;
}
ur->channels = c.channels;
if(ncplane_at_yx(n, dimy - 1, 0, &c) < 0){
cell_release(n, &c);
free(egc);
if( (egc = ncplane_at_yx(n, dimy - 1, 0, NULL, &lr->channels)) == NULL){
return -1;
}
lr->channels = c.channels;
if(ncplane_at_yx(n, 1, 0, &c) < 0){
cell_release(n, &c);
free(egc);
if( (egc = ncplane_at_yx(n, 1, 0, NULL, &ll->channels)) == NULL){
return -1;
}
ll->channels = c.channels;
cell_release(n, &c);
free(egc);
return 0;
}

View File

@ -141,7 +141,7 @@ int fallin_demo(struct notcurses* nc){
continue;
}
cell c = CELL_TRIVIAL_INITIALIZER;
if(ncplane_at_yx(stdn, usey, usex, &c) < 0){
if(ncplane_at_yx_cell(stdn, usey, usex, &c) < 0){
return -1;
}
if(!cell_simple_p(&c)){

View File

@ -58,7 +58,7 @@ hud_standard_bg(struct ncplane* n){
channels_set_fg_rgb(&channels, 0x0, 0x0, 0x0);
channels_set_bg_alpha(&channels, CELL_ALPHA_BLEND);
channels_set_bg_rgb(&channels, 0x0, 0x0, 0x0);
if(ncplane_set_base(n, channels, 0, "") >= 0){
if(ncplane_set_base(n, "", 0, channels) >= 0){
return -1;
}
return 0;
@ -103,7 +103,7 @@ about_toggle(struct notcurses* nc){
channels_set_fg_rgb(&channels, 0x0, 0x0, 0x0);
channels_set_bg_alpha(&channels, CELL_ALPHA_BLEND);
channels_set_bg_rgb(&channels, 0x0, 0x0, 0x0);
if(ncplane_set_base(n, channels, 0, "") >= 0){
if(ncplane_set_base(n, "", 0, channels) >= 0){
ncplane_set_fg(n, 0xc0f0c0);
ncplane_set_bg(n, 0);
ncplane_set_bg_alpha(n, CELL_ALPHA_BLEND);

View File

@ -114,7 +114,7 @@ draw_luigi(struct ncplane* n, const char* sprite){
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(n, channels, 0, "");
ncplane_set_base(n, "", 0, channels);
size_t s;
int sbytes;
// optimization so we can elide more color changes, see README's "#perf"
@ -202,7 +202,7 @@ int luigi_demo(struct notcurses* nc){
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(ncvisual_plane(wmncv), channels, 0, "");
ncplane_set_base(ncvisual_plane(wmncv), "", 0, channels);
if(ncvisual_render(wmncv, 0, 0, -1, -1) <= 0){
ncvisual_destroy(wmncv);
return -1;

View File

@ -72,7 +72,7 @@ outro_message(struct notcurses* nc, int* rows, int* cols){
ncplane_yx(non, NULL, &xs);
uint64_t channels = 0;
channels_set_bg_rgb(&channels, 0x58, 0x36, 0x58);
if(ncplane_set_base(non, channels, 0, " ") < 0){
if(ncplane_set_base(non, " ", 0, channels) < 0){
return NULL;
}
ncplane_dim_yx(non, rows, cols);

View File

@ -188,7 +188,7 @@ int unicodeblocks_demo(struct notcurses* nc){
channels_set_fg_alpha(&channels, CELL_ALPHA_BLEND);
channels_set_fg(&channels, 0x004000);
channels_set_bg(&channels, 0x0);
ncplane_set_base(header, channels, 0, "");
ncplane_set_base(header, "", 0, channels);
for(sindex = 0 ; sindex < sizeof(blocks) / sizeof(*blocks) ; ++sindex){
ncplane_set_bg_rgb(n, 0, 0, 0);
uint32_t blockstart = blocks[sindex].start;

View File

@ -38,7 +38,7 @@ legend(struct notcurses* nc, int dimy, int dimx){
ncplane_set_bg_alpha(n, CELL_ALPHA_TRANSPARENT);
uint64_t channels = 0;
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(n, channels, 0, " ");
ncplane_set_base(n, " ", 0, channels);
ncplane_styles_set(n, NCSTYLE_BOLD);
ncplane_set_fg_rgb(n, 0xff, 0xff, 0xff);
ncplane_set_fg_alpha(n, CELL_ALPHA_HIGHCONTRAST);
@ -122,7 +122,7 @@ int view_demo(struct notcurses* nc){
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(ncvisual_plane(ncv2), channels, 0, "");
ncplane_set_base(ncvisual_plane(ncv2), "", 0, channels);
demo_render(nc);
demo_nanosleep(nc, &demodelay);
ncvisual_destroy(ncv);

View File

@ -27,7 +27,7 @@ mathplane(struct notcurses* nc){
channels_set_fg(&channels, 0x2b50c8); // metallic gold, inverted
channels_set_fg_alpha(&channels, CELL_ALPHA_BLEND);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(n, channels, 0, "");
ncplane_set_base(n, "", 0, channels);
ncplane_set_fg(n, 0xd4af37); // metallic gold
ncplane_set_bg(n, 0x0);
if(n){
@ -61,7 +61,7 @@ lighten(struct ncplane* n, cell* c, int distance, int y, int x){
static void
surrounding_cells(struct ncplane* n, cell* lightup, int y, int x){
ncplane_at_yx(n, y, x, lightup);
ncplane_at_yx_cell(n, y, x, lightup);
}
static int
@ -171,7 +171,7 @@ message(struct ncplane* n, int maxy, int maxx, int num, int total,
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(n, channels, 0, "");
ncplane_set_base(n, "", 0, channels);
ncplane_set_fg_rgb(n, 255, 255, 255);
ncplane_set_bg_rgb(n, 32, 64, 32);
channels = 0;

View File

@ -44,7 +44,7 @@ perframecb(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused)),
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(n, channels, 0, " ");
ncplane_set_base(n, " ", 0, channels);
ncplane_set_bg_alpha(n, CELL_ALPHA_BLEND);
ncplane_set_scrolling(n, true);
}

View File

@ -455,10 +455,10 @@ static int
rotate_2x1_cw(ncplane* src, ncplane* dst, int srcy, int srcx, int dsty, int dstx){
cell c1 = CELL_TRIVIAL_INITIALIZER;
cell c2 = CELL_TRIVIAL_INITIALIZER;
if(ncplane_at_yx(src, srcy, srcx, &c1) < 0){
if(ncplane_at_yx_cell(src, srcy, srcx, &c1) < 0){
return -1;
}
if(ncplane_at_yx(src, srcy, srcx + 1, &c2) < 0){
if(ncplane_at_yx_cell(src, srcy, srcx + 1, &c2) < 0){
cell_release(src, &c1);
return -1;
}
@ -494,10 +494,10 @@ rotate_2x1_cw(ncplane* src, ncplane* dst, int srcy, int srcx, int dsty, int dstx
int rotate_2x1_ccw(ncplane* src, ncplane* dst, int srcy, int srcx, int dsty, int dstx){
cell c1 = CELL_TRIVIAL_INITIALIZER;
cell c2 = CELL_TRIVIAL_INITIALIZER;
if(ncplane_at_yx(src, srcy, srcx, &c1) < 0){
if(ncplane_at_yx_cell(src, srcy, srcx, &c1) < 0){
return -1;
}
if(ncplane_at_yx(src, srcy, srcx + 1, &c2) < 0){
if(ncplane_at_yx_cell(src, srcy, srcx + 1, &c2) < 0){
cell_release(src, &c1);
return -1;
}

View File

@ -263,7 +263,7 @@ write_header(ncmenu* ncm){ ncm->ncp->channels = ncm->headerchannels;
}
if(ncm->sections[i].shortcut_offset >= 0){
cell cl = CELL_TRIVIAL_INITIALIZER;
if(ncplane_at_yx(ncm->ncp, ypos, xoff + ncm->sections[i].shortcut_offset, &cl) < 0){
if(ncplane_at_yx_cell(ncm->ncp, ypos, xoff + ncm->sections[i].shortcut_offset, &cl) < 0){
return -1;
}
cell_styles_on(&cl, NCSTYLE_UNDERLINE|NCSTYLE_BOLD);
@ -396,7 +396,7 @@ int ncmenu_unroll(ncmenu* n, int sectionidx){
}
if(sec->items[i].shortcut_offset >= 0){
cell cl = CELL_TRIVIAL_INITIALIZER;
if(ncplane_at_yx(n->ncp, ypos, xpos + 1 + sec->items[i].shortcut_offset, &cl) < 0){
if(ncplane_at_yx_cell(n->ncp, ypos, xpos + 1 + sec->items[i].shortcut_offset, &cl) < 0){
return -1;
}
cell_styles_on(&cl, NCSTYLE_UNDERLINE|NCSTYLE_BOLD);

View File

@ -184,18 +184,18 @@ cursor_invalid_p(const ncplane* n){
return false;
}
int ncplane_at_cursor(ncplane* n, cell* c){
char* ncplane_at_cursor(ncplane* n, uint32_t* attrword, uint64_t* channels){
if(cursor_invalid_p(n)){
return -1;
return NULL;
}
return cell_duplicate(n, c, &n->fb[nfbcellidx(n, n->y, n->x)]);
return cell_extract(n, &n->fb[nfbcellidx(n, n->y, n->x)], attrword, channels);
}
int ncplane_at_yx(ncplane* n, int y, int x, cell* c){
int ret = -1;
char* ncplane_at_yx(ncplane* n, int y, int x, uint32_t* attrword, uint64_t* channels){
char* ret = NULL;
if(y < n->leny && x < n->lenx){
if(y >= 0 && x >= 0){
ret = cell_duplicate(n, c, &n->fb[nfbcellidx(n, y, x)]);
ret = cell_extract(n, &n->fb[nfbcellidx(n, y, x)], attrword, channels);
}
}
return ret;
@ -1123,7 +1123,7 @@ int ncplane_set_base_cell(ncplane* ncp, const cell* c){
return cell_duplicate(ncp, &ncp->basecell, c);
}
int ncplane_set_base(ncplane* ncp, uint64_t channels, uint32_t attrword, const char* egc){
int ncplane_set_base(ncplane* ncp, const char* egc, uint32_t attrword, uint64_t channels){
return cell_prime(ncp, &ncp->basecell, egc, attrword, channels);
}

View File

@ -616,7 +616,7 @@ ncreel* ncreel_create(ncplane* w, const ncreel_options* ropts, int efd){
free(nr);
return NULL;
}
ncplane_set_base(nr->p, ropts->bgchannel, 0, "");
ncplane_set_base(nr->p, "", 0, ropts->bgchannel);
if(ncreel_redraw(nr)){
ncplane_destroy(nr->p);
free(nr);

View File

@ -220,7 +220,7 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const selector_options*
uint64_t transchan = 0;
channels_set_fg_alpha(&transchan, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&transchan, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(ns->ncp, transchan, 0, "");
ncplane_set_base(ns->ncp, "", 0, transchan);
if(cell_prime(ns->ncp, &ns->background, " ", 0, opts->bgchannels) < 0){
ncplane_destroy(ns->ncp);
goto freeitems;
@ -707,7 +707,7 @@ ncmultiselector* ncmultiselector_create(ncplane* n, int y, int x, const multisel
uint64_t transchan = 0;
channels_set_fg_alpha(&transchan, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&transchan, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(ns->ncp, transchan, 0, "");
ncplane_set_base(ns->ncp, "", 0, transchan);
if(cell_prime(ns->ncp, &ns->background, " ", 0, opts->bgchannels) < 0){
ncplane_destroy(ns->ncp);
goto freeitems;

View File

@ -15,7 +15,7 @@ run_menu(struct notcurses* nc, struct ncmenu* ncm){
uint64_t channels = 0;
channels_set_fg(&channels, 0x000088);
channels_set_bg(&channels, 0x88aa00);
if(ncplane_set_base(selplane, channels, 0, " ") < 0){
if(ncplane_set_base(selplane, " ", 0, channels) < 0){
goto err;
}
char32_t keypress;
@ -119,7 +119,7 @@ int main(void){
uint64_t channels = 0;
channels_set_fg(&channels, 0x88aa00);
channels_set_bg(&channels, 0x000088);
if(ncplane_set_base(n, channels, 0, "x") < 0){
if(ncplane_set_base(n, "x", 0, channels) < 0){
return EXIT_FAILURE;
}

View File

@ -13,7 +13,7 @@ int main(void){
char c = 'A';
ncplane_set_scrolling(n, true);
while(true){
struct timespec req = { .tv_sec = 0, .tv_nsec = 10000000, };
struct timespec req = { .tv_sec = 0, .tv_nsec = 1000000, };
nanosleep(&req, NULL);
if(ncplane_putsimple(n, c) != 1){
break;

View File

@ -23,9 +23,6 @@ int main(int argc, char** argv){
if(n->load(c, "🐳") < 0){
goto err;
}
if(dimy > 5){
dimy = 5;
}
for(int i = 0 ; i < dimy ; ++i){
for(int j = 8 ; j < dimx / 2 ; ++j){ // leave some empty spaces
if(n->putc(i, j * 2, &c) < 0){
@ -57,7 +54,6 @@ int main(int argc, char** argv){
if(!nc.render()){
goto err;
}
printf("\n");
return !nc.stop() ? EXIT_FAILURE : EXIT_SUCCESS;
err:

View File

@ -36,7 +36,7 @@ void DrawBoard() { // draw all fixed components of the game
throw TetrisNotcursesErr("double_box()");
}
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
board_->set_base(channels, 0, "");
board_->set_base("", 0, channels);
scoreplane_ = std::make_unique<ncpp::Plane>(2, 30, y - BOARD_HEIGHT, 2, nullptr);
if(!scoreplane_){
throw TetrisNotcursesErr("Plane()");
@ -44,7 +44,7 @@ void DrawBoard() { // draw all fixed components of the game
uint64_t scorechan = 0;
channels_set_bg_alpha(&scorechan, CELL_ALPHA_TRANSPARENT);
channels_set_fg_alpha(&scorechan, CELL_ALPHA_TRANSPARENT);
if(!scoreplane_->set_base(scorechan, 0, "")){
if(!scoreplane_->set_base("", 0, scorechan)){
throw TetrisNotcursesErr("set_base()");
}
scoreplane_->set_bg_alpha(CELL_ALPHA_TRANSPARENT);

View File

@ -23,7 +23,7 @@ std::unique_ptr<ncpp::Plane> NewPiece() {
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
n->set_fg(t->color);
n->set_bg_alpha(CELL_ALPHA_TRANSPARENT);
n->set_base(channels, 0, "");
n->set_base("", 0, channels);
y = 0; x = 0;
for(size_t i = 0 ; i < strlen(t->texture) ; ++i){
if(t->texture[i] == '*'){

View File

@ -23,7 +23,7 @@ static void usage(std::ostream& os, const char* name, int exitcode)
__attribute__ ((noreturn));
void usage(std::ostream& o, const char* name, int exitcode){
o << "usage: " << name << " [ -h ] [ -l loglevel ] [ -d mult ] [ -s scaletype ] files" << '\n';
o << "usage: " << name << " [ -h ] [ -l loglevel ] [ -d mult ] [ -s scaling ] files" << '\n';
o << " -l loglevel: integer between 0 and 9, goes to stderr'\n";
o << " -s scaletype: one of 'none', 'scale', or 'stretch'\n";
o << " -d mult: non-negative floating point scale for frame time" << std::endl;
@ -67,7 +67,7 @@ int perframe([[maybe_unused]] struct notcurses* _nc, struct ncvisual* ncv, void*
uint64_t channels = 0;
channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
ncplane_set_base(subtitle_plane, channels, 0, "");
ncplane_set_base(subtitle_plane, "", 0, channels);
ncplane_set_fg(subtitle_plane, 0x00ffff);
ncplane_set_fg_alpha(subtitle_plane, CELL_ALPHA_HIGHCONTRAST);
ncplane_set_bg_alpha(subtitle_plane, CELL_ALPHA_TRANSPARENT);

View File

@ -95,7 +95,7 @@ TEST_CASE("Fills") {
// check all squares
for(int y = 0 ; y < dimy ; ++y){
for(int x = 0 ; x < dimx ; ++x){
REQUIRE(0 <= ncplane_at_yx(n_, y, x, &cl));
REQUIRE(0 <= ncplane_at_yx_cell(n_, y, x, &cl));
CHECK('M' == cl.gcluster);
CHECK(0 == cl.attrword);
CHECK(channels == cl.channels);
@ -129,7 +129,7 @@ TEST_CASE("Fills") {
for(int y = 0 ; y < dimy ; ++y){
lastxrgb = -1;
for(int x = 0 ; x < dimx ; ++x){
REQUIRE(0 <= ncplane_at_yx(n_, y, x, &c));
REQUIRE(0 <= ncplane_at_yx_cell(n_, y, x, &c));
CHECK('V' == c.gcluster);
CHECK(0 == c.attrword);
if(lastxrgb == (uint64_t)-1){
@ -222,7 +222,7 @@ TEST_CASE("Fills") {
cell_styles_on(&c, NCSTYLE_BOLD);
CHECK(0 < ncplane_format(n_, 0, 0, c.attrword));
cell d = CELL_TRIVIAL_INITIALIZER;
CHECK(1 == ncplane_at_yx(n_, 0, 0, &d));
CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
CHECK(d.attrword == c.attrword);
CHECK(0x444444 == cell_fg(&d));
}
@ -246,7 +246,7 @@ TEST_CASE("Fills") {
cell d = CELL_TRIVIAL_INITIALIZER;
for(int y = 0 ; y < 8 ; ++y){
for(int x = 0 ; x < 8 ; ++x){
CHECK(1 == ncplane_at_yx(n_, y, x, &d));
CHECK(1 == ncplane_at_yx_cell(n_, y, x, &d));
CHECK(channels == d.channels);
REQUIRE(cell_simple_p(&d));
CHECK('A' == d.gcluster);
@ -267,7 +267,7 @@ TEST_CASE("Fills") {
REQUIRE(0 < ncplane_gradient(n_, "A", 0, channels, channels, channels, channels, 0, 0));
CHECK(0 == notcurses_render(nc_));
cell d = CELL_TRIVIAL_INITIALIZER;
CHECK(1 == ncplane_at_yx(n_, 0, 0, &d));
CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
CHECK(channels == d.channels);
REQUIRE(cell_simple_p(&d));
CHECK('A' == d.gcluster);
@ -288,13 +288,13 @@ TEST_CASE("Fills") {
REQUIRE(0 < ncplane_gradient(n_, "A", 0, chan1, chan2, chan1, chan2, 0, 3));
CHECK(0 == notcurses_render(nc_));
cell d = CELL_TRIVIAL_INITIALIZER;
CHECK(1 == ncplane_at_yx(n_, 0, 0, &d));
CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
CHECK(chan1 == d.channels);
REQUIRE(cell_simple_p(&d));
CHECK('A' == d.gcluster);
CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_gradient(n_, "A", 0, chan2, chan1, chan2, chan1, 0, 3));
CHECK(1 == ncplane_at_yx(n_, 0, 0, &d));
CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
REQUIRE(cell_simple_p(&d));
CHECK('A' == d.gcluster);
CHECK(chan2 == d.channels);
@ -337,8 +337,8 @@ TEST_CASE("Fills") {
cell cbase = CELL_TRIVIAL_INITIALIZER;
cell cp = CELL_TRIVIAL_INITIALIZER;
for(int i = 0 ; i < 10 ; ++i){
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx(p1, 0, i, &cp));
CHECK(0 < ncplane_at_yx_cell(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx_cell(p1, 0, i, &cp));
CHECK(0 == cellcmp(n_, &cbase, p1, &cp));
}
CHECK(0 == ncplane_cursor_move_yx(p1, 0, 0));
@ -346,8 +346,8 @@ TEST_CASE("Fills") {
CHECK(0 < ncplane_putstr(p1, "9876543210"));
CHECK(0 == ncplane_mergedown(p1, n_));
for(int i = 0 ; i < 10 ; ++i){
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx(p1, 0, i, &cp));
CHECK(0 < ncplane_at_yx_cell(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx_cell(p1, 0, i, &cp));
CHECK(0 == cellcmp(n_, &cbase, p1, &cp));
}
// make sure nulls do not replace glyphs
@ -355,8 +355,8 @@ TEST_CASE("Fills") {
CHECK(0 == ncplane_mergedown(p2, n_));
ncplane_destroy(p2);
for(int i = 0 ; i < 10 ; ++i){
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx(p1, 0, i, &cp));
CHECK(0 < ncplane_at_yx_cell(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx_cell(p1, 0, i, &cp));
CHECK(0 == cellcmp(n_, &cbase, p1, &cp));
}
ncplane_destroy(p1);
@ -371,8 +371,8 @@ TEST_CASE("Fills") {
cell cbase = CELL_TRIVIAL_INITIALIZER;
cell cp = CELL_TRIVIAL_INITIALIZER;
for(int i = 0 ; i < 10 ; ++i){
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx(p1, 0, i, &cp));
CHECK(0 < ncplane_at_yx_cell(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx_cell(p1, 0, i, &cp));
CHECK(0 == cellcmp(n_, &cbase, p1, &cp));
}
ncplane_destroy(p1);
@ -384,8 +384,8 @@ TEST_CASE("Fills") {
CHECK(0 == ncplane_mergedown(p3, NULL));
cell c3 = CELL_TRIVIAL_INITIALIZER;
for(int i = 0 ; i < 10 ; ++i){
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx(p3, 0, i, &c3));
CHECK(0 < ncplane_at_yx_cell(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx_cell(p3, 0, i, &c3));
CHECK(0 == cellcmp(n_, &cbase, p3, &c3));
}
CHECK(0 == notcurses_render(nc_));
@ -394,8 +394,8 @@ TEST_CASE("Fills") {
CHECK(0 == ncplane_mergedown(p2, NULL));
ncplane_destroy(p2);
for(int i = 0 ; i < 10 ; ++i){
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx(p3, 0, i, &c3));
CHECK(0 < ncplane_at_yx_cell(n_, 0, i, &cbase));
CHECK(0 < ncplane_at_yx_cell(p3, 0, i, &c3));
CHECK(0 == cellcmp(n_, &cbase, p3, &c3));
}
ncplane_destroy(p3);
@ -426,11 +426,11 @@ TEST_CASE("Fills") {
CHECK(0 == notcurses_render(nc_));
for(int y = 0 ; y < DIMY ; ++y){
for(int x = 0 ; x < DIMX ; ++x){
CHECK(0 < ncplane_at_yx(p1, y, x, &c1));
CHECK(0 < ncplane_at_yx_cell(p1, y, x, &c1));
if(y < 1 || y > 5 || x < 1 || x > 5){
CHECK(0 == strcmp(extended_gcluster(p1, &c1), ""));
}else{
CHECK(0 < ncplane_at_yx(p2, y - 1, x - 1, &c2));
CHECK(0 < ncplane_at_yx_cell(p2, y - 1, x - 1, &c2));
CHECK(0 == cellcmp(p1, &c1, p2, &c2));
}
}

View File

@ -504,7 +504,7 @@ TEST_CASE("NCPlane") {
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_putstr(n_, STR1));
cell testcell = CELL_TRIVIAL_INITIALIZER;
REQUIRE(0 == ncplane_at_cursor(n_, &testcell)); // want nothing at the cursor
REQUIRE(0 == ncplane_at_cursor_cell(n_, &testcell)); // want nothing at the cursor
CHECK(0 == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
@ -518,12 +518,12 @@ TEST_CASE("NCPlane") {
REQUIRE(dimx == x);
REQUIRE(0 == ncplane_putstr(n_, STR3));
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_at_cursor(n_, &testcell)); // want first char of STR1
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell)); // want first char of STR1
CHECK(STR1[0] == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - 1));
REQUIRE(0 < ncplane_at_cursor(n_, &testcell)); // want last char of STR2
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell)); // want last char of STR2
CHECK(STR2[strlen(STR2) - 1] == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
@ -540,7 +540,7 @@ TEST_CASE("NCPlane") {
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_putstr(n_, STR1));
cell testcell = CELL_TRIVIAL_INITIALIZER;
ncplane_at_cursor(n_, &testcell); // should be nothing at the cursor
ncplane_at_cursor_cell(n_, &testcell); // should be nothing at the cursor
CHECK(0 == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
@ -554,12 +554,12 @@ TEST_CASE("NCPlane") {
REQUIRE(dimx == x);
REQUIRE(0 == ncplane_putstr(n_, STR3));
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_at_cursor(n_, &testcell)); // want first char of STR1
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell)); // want first char of STR1
CHECK(!strcmp("Σ", cell_extended_gcluster(n_, &testcell)));
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - mbstowcs(NULL, STR2, 0)));
REQUIRE(0 < ncplane_at_cursor(n_, &testcell)); // want first char of STR2
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell)); // want first char of STR2
CHECK(!strcmp("α", cell_extended_gcluster(n_, &testcell)));
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.channels);
@ -589,13 +589,13 @@ TEST_CASE("NCPlane") {
CHECK(newx == x);
cell testcell = CELL_TRIVIAL_INITIALIZER;
CHECK(0 == ncplane_cursor_move_yx(n_, y - 2, x - 1));
REQUIRE(1 == ncplane_at_cursor(n_, &testcell));
REQUIRE(1 == ncplane_at_cursor_cell(n_, &testcell));
CHECK(testcell.gcluster == STR1[strlen(STR1) - 1]);
CHECK(0 == ncplane_cursor_move_yx(n_, y - 1, x - 1));
REQUIRE(1 == ncplane_at_cursor(n_, &testcell));
REQUIRE(1 == ncplane_at_cursor_cell(n_, &testcell));
CHECK(testcell.gcluster == STR2[strlen(STR2) - 1]);
CHECK(0 == ncplane_cursor_move_yx(n_, y, x - 1));
REQUIRE(1 == ncplane_at_cursor(n_, &testcell));
REQUIRE(1 == ncplane_at_cursor_cell(n_, &testcell));
CHECK(testcell.gcluster == STR3[strlen(STR3) - 1]);
}
@ -701,7 +701,7 @@ TEST_CASE("NCPlane") {
REQUIRE(0 == cells_rounded_box(ncp, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl));
CHECK(0 == ncplane_box(ncp, &ul, &ur, &ll, &lr, &hl, &vl, y + 1, x + 1, 0));
CHECK(0 == notcurses_render(nc_));
// FIXME verify with ncplane_at_cursor()
// FIXME verify with ncplane_at_cursor_cell()
CHECK(0 == ncplane_destroy(ncp));
}
SUBCASE("MoveToLowerRight") {
@ -718,7 +718,7 @@ TEST_CASE("NCPlane") {
CHECK(0 == ncplane_move_yx(ncp, nrows - 3, ncols - 3));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncplane_destroy(ncp));
// FIXME verify with ncplane_at_cursor()
// FIXME verify with ncplane_at_cursor_cell()
}
SUBCASE("Perimeter") {
@ -741,12 +741,12 @@ TEST_CASE("NCPlane") {
CHECK(1 == ncplane_putegc_stainable(n_, "C", &sbytes));
CHECK(1 == ncplane_putegc_stainable(n_, "D", &sbytes));
uint64_t channels = 0;
CHECK(1 == ncplane_at_yx(n_, 0, 0, &c));
CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &c));
CHECK(cell_simple_p(&c));
CHECK('C' == c.gcluster);
CHECK(0 == channels_set_fg(&channels, 0x444444));
CHECK(channels == c.channels);
CHECK(1 == ncplane_at_yx(n_, 0, 1, &c));
CHECK(1 == ncplane_at_yx_cell(n_, 0, 1, &c));
CHECK(cell_simple_p(&c));
CHECK('D' == c.gcluster);
CHECK(0 == channels_set_fg(&channels, 0x888888));

View File

@ -81,7 +81,7 @@ TEST_CASE("Palette256") {
CHECK(0 < ncplane_putc_yx(n_, 0, 0, &c));
cell_release(n_, &c);
cell r = CELL_TRIVIAL_INITIALIZER;
CHECK(0 < ncplane_at_yx(n_, 0, 0, &r));
CHECK(0 < ncplane_at_yx_cell(n_, 0, 0, &r));
CHECK(cell_fg_palindex_p(&r));
CHECK(cell_bg_palindex_p(&r));
CHECK(CELL_ALPHA_OPAQUE == cell_fg_alpha(&r));

View File

@ -58,7 +58,7 @@ TEST_CASE("Rotate") {
uint64_t channels = 0;
CHECK(0 == channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT));
CHECK(0 == channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT));
REQUIRE(0 >= ncplane_set_base(testn, channels, 0, ""));
REQUIRE(0 >= ncplane_set_base(testn, "", 0, channels));
cell tl = CELL_TRIVIAL_INITIALIZER; cell tr = CELL_TRIVIAL_INITIALIZER;
cell bl = CELL_TRIVIAL_INITIALIZER; cell br = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER; cell vl = CELL_TRIVIAL_INITIALIZER;

View File

@ -77,7 +77,7 @@ TEST_CASE("Wide") {
for(auto i = 0u ; i < tcells.size() ; ++i){
CHECK(0 == ncplane_cursor_move_yx(n_, 0, x));
cell testcell = CELL_TRIVIAL_INITIALIZER;
REQUIRE(0 < ncplane_at_cursor(n_, &testcell));
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell));
CHECK(!strcmp(cell_extended_gcluster(n_, &tcells[i]),
cell_extended_gcluster(n_, &testcell)));
CHECK(0 == testcell.attrword);
@ -109,19 +109,19 @@ TEST_CASE("Wide") {
CHECK(0 < ncplane_putegc_yx(n_, 0, 0, w, &sbytes));
CHECK(0 < ncplane_putegc_yx(n_, 1, 0, w, &sbytes));
cell c = CELL_TRIVIAL_INITIALIZER;
ncplane_at_yx(n_, 0, 0, &c);
ncplane_at_yx_cell(n_, 0, 0, &c);
const char* wres = extended_gcluster(n_, &c);
CHECK(0 == strcmp(wres, "\xf0\x9f\x90\xb8")); // should be frog
ncplane_at_yx(n_, 0, 1, &c);
ncplane_at_yx_cell(n_, 0, 1, &c);
CHECK(cell_double_wide_p(&c)); // should be wide
ncplane_at_yx(n_, 0, 2, &c);
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(0 == c.gcluster); // should be nothing
ncplane_at_yx(n_, 1, 0, &c);
ncplane_at_yx_cell(n_, 1, 0, &c);
wres = extended_gcluster(n_, &c);
CHECK(0 == strcmp(wres, "\xf0\x9f\x90\xb8")); // should be frog
ncplane_at_yx(n_, 1, 1, &c);
ncplane_at_yx_cell(n_, 1, 1, &c);
CHECK(cell_double_wide_p(&c)); //should be wide
ncplane_at_yx(n_, 0, 2, &c);
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(0 == c.gcluster);
CHECK(0 == notcurses_render(nc_)); // should be nothing
}
@ -139,12 +139,12 @@ TEST_CASE("Wide") {
CHECK(0 == y);
CHECK(3 == x);
cell c = CELL_TRIVIAL_INITIALIZER;
ncplane_at_yx(n_, 0, 0, &c);
ncplane_at_yx_cell(n_, 0, 0, &c);
CHECK(0 == c.gcluster); // should be nothing
ncplane_at_yx(n_, 0, 1, &c);
ncplane_at_yx_cell(n_, 0, 1, &c);
const char* wres = extended_gcluster(n_, &c);
CHECK(0 == strcmp(wres, "\xf0\x9f\x90\x8d")); // should be snake
ncplane_at_yx(n_, 0, 2, &c);
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(cell_double_wide_p(&c)); // should be wide
CHECK(0 == notcurses_render(nc_));
}
@ -165,13 +165,13 @@ TEST_CASE("Wide") {
CHECK(0 == y);
CHECK(3 == x);
cell c = CELL_TRIVIAL_INITIALIZER;
ncplane_at_yx(n_, 0, 0, &c);
ncplane_at_yx_cell(n_, 0, 0, &c);
CHECK(0 == c.gcluster); // should be nothing
ncplane_at_yx(n_, 0, 1, &c);
ncplane_at_yx_cell(n_, 0, 1, &c);
CHECK(cc == c.gcluster); // should be 'X'
ncplane_at_yx(n_, 0, 2, &c);
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(cc == c.gcluster); // should be 'X"
ncplane_at_yx(n_, 0, 3, &c);
ncplane_at_yx_cell(n_, 0, 3, &c);
CHECK(0 == c.gcluster); // should be nothing
CHECK(0 == notcurses_render(nc_));
}
@ -191,17 +191,17 @@ TEST_CASE("Wide") {
CHECK(0 == y);
CHECK(3 == x);
cell c = CELL_TRIVIAL_INITIALIZER;
ncplane_at_yx(n_, 0, 0, &c);
ncplane_at_yx_cell(n_, 0, 0, &c);
const char* wres = extended_gcluster(n_, &c);
CHECK(0 == strcmp(wres, "\xf0\x9f\x90\x8d")); // should be snake
ncplane_at_yx(n_, 0, 1, &c);
ncplane_at_yx_cell(n_, 0, 1, &c);
CHECK(cell_double_wide_p(&c)); // should be snake
ncplane_at_yx(n_, 0, 2, &c);
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(cc == c.gcluster); // should be 'X'
ncplane_at_yx(n_, 0, 3, &c);
ncplane_at_yx_cell(n_, 0, 3, &c);
wres = extended_gcluster(n_, &c);
CHECK(0 == strcmp(wres, "\xf0\x9f\xa6\x82")); // should be scorpion
ncplane_at_yx(n_, 0, 4, &c);
ncplane_at_yx_cell(n_, 0, 4, &c);
CHECK(cell_double_wide_p(&c)); // should be scorpion
CHECK(0 == notcurses_render(nc_));
}
@ -215,14 +215,14 @@ TEST_CASE("Wide") {
CHECK(2 == ncplane_putegc_yx(ncp, 1, 1, "\xf0\x9f\xa6\x82", NULL)); // scorpion
CHECK(0 == notcurses_render(nc_));
cell c = CELL_TRIVIAL_INITIALIZER;
REQUIRE(0 < ncplane_at_yx(ncp, 1, 0, &c));
REQUIRE(0 < ncplane_at_yx_cell(ncp, 1, 0, &c));
CHECK(!strcmp(cell_extended_gcluster(ncp, &c), ""));
cell_release(ncp, &c);
char* egc = notcurses_at_yx(nc_, 1, 0, &c.attrword, &c.channels);
REQUIRE(egc);
CHECK(!strcmp(egc, ""));
free(egc);
REQUIRE(0 < ncplane_at_yx(ncp, 1, 3, &c));
REQUIRE(0 < ncplane_at_yx_cell(ncp, 1, 3, &c));
CHECK(!strcmp(cell_extended_gcluster(ncp, &c), ""));
cell_release(ncp, &c);
egc = notcurses_at_yx(nc_, 1, 3, &c.attrword, &c.channels);
@ -235,15 +235,15 @@ TEST_CASE("Wide") {
SUBCASE("RenderWides") {
CHECK(0 <= ncplane_putstr(n_, "\xe5\xbd\xa2\xe5\x85\xa8"));
cell c = CELL_TRIVIAL_INITIALIZER;
ncplane_at_yx(n_, 0, 0, &c);
ncplane_at_yx_cell(n_, 0, 0, &c);
CHECK(cell_double_wide_p(&c));
ncplane_at_yx(n_, 0, 1, &c);
ncplane_at_yx_cell(n_, 0, 1, &c);
CHECK(cell_double_wide_p(&c));
ncplane_at_yx(n_, 0, 2, &c);
ncplane_at_yx_cell(n_, 0, 2, &c);
CHECK(cell_double_wide_p(&c));
ncplane_at_yx(n_, 0, 3, &c);
ncplane_at_yx_cell(n_, 0, 3, &c);
CHECK(cell_double_wide_p(&c));
ncplane_at_yx(n_, 0, 4, &c);
ncplane_at_yx_cell(n_, 0, 4, &c);
CHECK(!cell_double_wide_p(&c));
REQUIRE(0 == notcurses_render(nc_));
notcurses_at_yx(nc_, 0, 0, &c.attrword, &c.channels);
@ -280,7 +280,7 @@ TEST_CASE("Wide") {
CHECK(!notcurses_render(nc_));
// should be wide char 1
REQUIRE(3 == ncplane_at_yx(n_, 0, 0, &c));
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 0, &c));
egc = cell_egc_copy(n_, &c);
REQUIRE(egc);
CHECK(!strcmp("\xe5\x85\xa8", egc));
@ -293,7 +293,7 @@ TEST_CASE("Wide") {
free(egc);
cell_init(&c);
// should be wide char 1 right side
REQUIRE(0 == ncplane_at_yx(n_, 0, 1, &c));
REQUIRE(0 == ncplane_at_yx_cell(n_, 0, 1, &c));
egc = cell_egc_copy(n_, &c);
REQUIRE(egc);
CHECK(!strcmp("", egc));
@ -307,7 +307,7 @@ TEST_CASE("Wide") {
cell_init(&c);
// should be wide char 2
REQUIRE(3 == ncplane_at_yx(n_, 0, 2, &c));
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 2, &c));
egc = cell_egc_copy(n_, &c);
REQUIRE(egc);
CHECK(!strcmp("\xe5\xbd\xa2", egc));
@ -320,7 +320,7 @@ TEST_CASE("Wide") {
free(egc);
cell_init(&c);
// should be wide char 2 right side
CHECK(0 == ncplane_at_yx(n_, 0, 3, &c));
CHECK(0 == ncplane_at_yx_cell(n_, 0, 3, &c));
egc = cell_egc_copy(n_, &c);
REQUIRE(egc);
CHECK(!strcmp("", egc));
@ -380,7 +380,7 @@ TEST_CASE("Wide") {
uint64_t channels = 0;
channels_set_bg_alpha(&channels, CELL_ALPHA_BLEND);
channels_set_bg_rgb(&channels, 0x80, 0xf0, 0x10);
CHECK(1 == ncplane_set_base(p, channels, 0, " "));
CHECK(1 == ncplane_set_base(p, " ", 0, channels));
CHECK(0 == notcurses_render(nc_));
uint32_t attrword;
uint64_t chanleft, chanright;
@ -393,10 +393,10 @@ TEST_CASE("Wide") {
CHECK(0 == strcmp(" ", egc));
free(egc);
cell cl = CELL_TRIVIAL_INITIALIZER, cr = CELL_TRIVIAL_INITIALIZER;
CHECK(3 == ncplane_at_yx(n_, 1, 1, &cl));
CHECK(3 == ncplane_at_yx_cell(n_, 1, 1, &cl));
REQUIRE(cell_extended_gcluster(n_, &cl));
CHECK(0 == strcmp("", extended_gcluster(n_, &cl)));
CHECK(0 == ncplane_at_yx(n_, 1, 2, &cr));
CHECK(0 == ncplane_at_yx_cell(n_, 1, 2, &cr));
REQUIRE(cell_simple_p(&cr));
CHECK(0 == cr.gcluster);
cell_release(n_, &cl);

View File

@ -95,7 +95,7 @@ TEST_CASE("ZAxisTest") {
REQUIRE(1 == ncplane_putc(n_, &c));
CHECK(!notcurses_render(nc_));
REQUIRE(!ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(1 == ncplane_at_cursor(n_, &cat));
REQUIRE(1 == ncplane_at_cursor_cell(n_, &cat));
REQUIRE(cell_simple_p(&cat));
REQUIRE('x' == cat.gcluster);
struct ncplane* n2 = ncplane_new(nc_, 2, 2, 0, 0, nullptr);
@ -104,7 +104,7 @@ TEST_CASE("ZAxisTest") {
REQUIRE(1 == ncplane_putc(n2, &c));
CHECK_EQ(0, notcurses_render(nc_));
REQUIRE(!ncplane_cursor_move_yx(n2, 0, 0));
REQUIRE(1 == ncplane_at_cursor(n2, &cat));
REQUIRE(1 == ncplane_at_cursor_cell(n2, &cat));
REQUIRE('y' == cat.gcluster);
struct ncplane* n3 = ncplane_new(nc_, 2, 2, 0, 0, nullptr);
REQUIRE(1 == cell_load(n3, &c, "z"));
@ -112,7 +112,7 @@ TEST_CASE("ZAxisTest") {
REQUIRE(1 == ncplane_putc(n3, &c));
CHECK(!notcurses_render(nc_));
REQUIRE(!ncplane_cursor_move_yx(n3, 0, 0));
REQUIRE(1 == ncplane_at_cursor(n3, &cat));
REQUIRE(1 == ncplane_at_cursor_cell(n3, &cat));
REQUIRE('z' == cat.gcluster);
// FIXME testing damage requires notcurses keeping a copy of the screen....
// FIXME move y atop z