blissful endianness-opacity

not caring about endianness is the opiate of the masses.
happy, happy masses. remove endianness.h and all its baleful
influence by explicitly breaking up the cell structure. #892
This commit is contained in:
nick black 2020-08-15 19:25:08 -04:00 committed by Nick Black
parent 248c49402e
commit 16ff667325
25 changed files with 402 additions and 453 deletions

View File

@ -1,6 +1,15 @@
This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 1.6.13 (not yet released)
* Styles now work properly with `ncdirect`, which apparently has never
been the case until now :/.
* EGCs occupying four bytes or fewer when encoded as UTF8 are now
inlined directly into the `cell` structure. This should mean nothing
for you save less memory consumption per plane, and faster operation.
In the course of doing so, the `attrword` field of the `cell` structure
was renamed `stylemask`, and reduced from 32 to 16 bits.
* 1.6.12 (2020-08-12)
* `ncreel`s `tabletcb` callback function semantics are radically simplified.
No more worrying about borders that might or might not have been drawn;

View File

@ -1408,7 +1408,7 @@ all implemented in terms of the lower-level [Channels API](#channels).
```c
// Get the current channels or attribute word for ncplane 'n'.
uint64_t ncplane_channels(const struct ncplane* n);
uint32_t ncplane_attr(const struct ncplane* n);
uint16_t ncplane_attr(const struct ncplane* n);
// Extract the 32-bit working background channel from an ncplane.
static inline unsigned

View File

@ -13,17 +13,19 @@ notcurses_cell - operations on notcurses cells
```c
// See DESCRIPTION below for information on EGC encoding
typedef struct cell {
uint32_t gcluster;
uint32_t attrword;
uint32_t gcluster; // 4B → 4B
uint8_t gcluster_backstop; // 1B → 5B (8 bits of zero)
uint8_t reserved; // 1B → 6B (8 reserved bits, ought be zero)
uint16_t stylemask; // 2B → 8B (16 bits of NCSTYLE_* attributes)
uint64_t channels;
} cell;
#define CELL_TRIVIAL_INITIALIZER \
{ .gcluster = '\0', .attrword = 0, .channels = 0, }
{ .gcluster = '\0', .stylemask = 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), }
{ .gcluster = (c), .stylemask = 0, .channels = 0, }
#define CELL_INITIALIZER(c, s, chan) \
{ .gcluster = (c), .stylemask = (s), .channels = (chan), }
#define CELL_WIDEASIAN_MASK 0x8000000080000000ull
#define CELL_BGDEFAULT_MASK 0x0000000040000000ull
@ -44,7 +46,7 @@ typedef struct cell {
**int cell_load(struct ncplane* n, cell* c, const char* gcluster);**
**int cell_prime(struct ncplane* n, cell* c, const char* gcluster,
uint32_t attr, uint64_t channels);**
uint32_t stylemask, uint64_t channels);**
**int cell_duplicate(struct ncplane* n, cell* targ, const cell* c);**

View File

@ -38,7 +38,7 @@ notcurses_plane - operations on ncplanes
**int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);**
**int ncplane_set_base(struct ncplane* ncp, const char* egc, uint32_t attrword, uint64_t channels);**
**int ncplane_set_base(struct ncplane* ncp, const char* egc, uint32_t stylemask, uint64_t channels);**
**int ncplane_base(struct ncplane* ncp, cell* c);**
@ -52,11 +52,11 @@ notcurses_plane - operations on ncplanes
**struct ncplane* ncplane_below(struct ncplane* n);**
**char* ncplane_at_cursor(struct ncplane* n, uint32_t* attrword, uint64_t* channels);**
**char* ncplane_at_cursor(struct ncplane* n, uint16_t* stylemask, uint64_t* channels);**
**int ncplane_at_cursor_cell(struct ncplane* n, cell* c);**
**char* ncplane_at_yx(const struct ncplane* n, int y, int x, uint32_t* attrword, uint64_t* channels);**
**char* ncplane_at_yx(const struct ncplane* n, int y, int x, uint16_t* stylemask, uint64_t* channels);**
**int ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c);**

View File

@ -40,7 +40,7 @@ namespace ncpp
_cell = CELL_SIMPLE_INITIALIZER (c);
}
explicit Cell (uint32_t c, uint32_t a, uint64_t chan, NotCurses *ncinst = nullptr) noexcept
explicit Cell (uint32_t c, uint16_t a, uint64_t chan, NotCurses *ncinst = nullptr) noexcept
: Root (ncinst)
{
_cell = CELL_INITIALIZER (c, a, chan);
@ -66,9 +66,9 @@ namespace ncpp
cell_init (&_cell);
}
uint32_t get_attrword () const noexcept
uint16_t get_stylemask () const noexcept
{
return _cell.attrword;
return _cell.stylemask;
}
uint64_t get_channels () const noexcept

View File

@ -238,7 +238,7 @@ namespace ncpp
return notcurses_getc_nblock (nc, ni);
}
char* get_at (int yoff, int xoff, uint32_t* attr, uint64_t* channels) const noexcept
char* get_at (int yoff, int xoff, uint16_t* attr, uint64_t* channels) const noexcept
{
return notcurses_at_yx (nc, yoff, xoff, attr, channels);
}

View File

@ -156,14 +156,14 @@ namespace ncpp
return error_guard (ncplane_pulse (plane, ts, fader, curry), -1);
}
int gradient (const char* egc, uint32_t attrword, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ystop, int xstop) const NOEXCEPT_MAYBE
int gradient (const char* egc, uint16_t stylemask, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ystop, int xstop) const NOEXCEPT_MAYBE
{
return error_guard<int> (ncplane_gradient (plane, egc, attrword, ul, ur, ll, lr, ystop, xstop), -1);
return error_guard<int> (ncplane_gradient (plane, egc, stylemask, ul, ur, ll, lr, ystop, xstop), -1);
}
int gradient_sized (const char* egc, uint32_t attrword, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ylen, int xlen) const NOEXCEPT_MAYBE
int gradient_sized (const char* egc, uint16_t stylemask, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ylen, int xlen) const NOEXCEPT_MAYBE
{
return error_guard<int> (ncplane_gradient_sized (plane, egc, attrword, ul, ur, ll, lr, ylen, xlen), -1);
return error_guard<int> (ncplane_gradient_sized (plane, egc, stylemask, ul, ur, ll, lr, ylen, xlen), -1);
}
int high_gradient (uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr, int ylen, int xlen) const NOEXCEPT_MAYBE
@ -476,9 +476,9 @@ namespace ncpp
return error_guard<int> (ncplane_putwstr_yx (plane, y, x, gclustarr), -1);
}
int putstr (int y, NCAlign atype, const wchar_t *gclustattr) const NOEXCEPT_MAYBE
int putstr (int y, NCAlign atype, const wchar_t *gcluststyles) const NOEXCEPT_MAYBE
{
return error_guard<int> (ncplane_putwstr_aligned (plane, y, static_cast<ncalign_e>(atype), gclustattr), -1);
return error_guard<int> (ncplane_putwstr_aligned (plane, y, static_cast<ncalign_e>(atype), gcluststyles), -1);
}
int putstr_stainable (const char* s) const NOEXCEPT_MAYBE
@ -575,34 +575,34 @@ namespace ncpp
return error_guard<int> (ncplane_vline_interp (plane, c, len, c1, c2), -1);
}
bool load_box (uint32_t attrs, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl, const char *gclusters) const NOEXCEPT_MAYBE
bool load_box (uint16_t styles, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl, const char *gclusters) const NOEXCEPT_MAYBE
{
return error_guard (cells_load_box (plane, attrs, channels, ul, ur, ll, lr, hl, vl, gclusters), -1);
return error_guard (cells_load_box (plane, styles, channels, ul, ur, ll, lr, hl, vl, gclusters), -1);
}
bool load_box (CellStyle style, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl, const char *gclusters) const NOEXCEPT_MAYBE
{
return load_box (static_cast<uint32_t>(style), channels, ul, ur, ll, lr, hl, vl, gclusters);
return load_box (static_cast<uint16_t>(style), channels, ul, ur, ll, lr, hl, vl, gclusters);
}
bool load_rounded_box (uint32_t attr, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const NOEXCEPT_MAYBE
bool load_rounded_box (uint16_t styles, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const NOEXCEPT_MAYBE
{
return error_guard (cells_rounded_box (plane, attr, channels, ul, ur, ll, lr, hl, vl), -1);
return error_guard (cells_rounded_box (plane, styles, channels, ul, ur, ll, lr, hl, vl), -1);
}
bool load_rounded_box (CellStyle style, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const NOEXCEPT_MAYBE
{
return load_rounded_box (static_cast<uint32_t>(style), channels, ul, ur, ll, lr, hl, vl);
return load_rounded_box (static_cast<uint16_t>(style), channels, ul, ur, ll, lr, hl, vl);
}
bool load_double_box (uint32_t attr, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const NOEXCEPT_MAYBE
bool load_double_box (uint16_t styles, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const NOEXCEPT_MAYBE
{
return error_guard (cells_double_box (plane, attr, channels, ul, ur, ll, lr, hl, vl), -1);
return error_guard (cells_double_box (plane, styles, channels, ul, ur, ll, lr, hl, vl), -1);
}
bool load_double_box (CellStyle style, uint64_t channels, Cell &ul, Cell &ur, Cell &ll, Cell &lr, Cell &hl, Cell &vl) const NOEXCEPT_MAYBE
{
return load_double_box (static_cast<uint32_t>(style), channels, ul, ur, ll, lr, hl, vl);
return load_double_box (static_cast<uint16_t>(style), channels, ul, ur, ll, lr, hl, vl);
}
bool box (const Cell &ul, const Cell &ur, const Cell &ll, const Cell &lr,
@ -619,24 +619,24 @@ namespace ncpp
return error_guard (ncplane_box_sized (plane, ul, ur, ll, lr, hline, vline, ylen, xlen, ctlword), -1);
}
bool rounded_box (uint32_t attr, uint64_t channels, int ystop, int xstop, unsigned ctlword) const NOEXCEPT_MAYBE
bool rounded_box (uint16_t styles, uint64_t channels, int ystop, int xstop, unsigned ctlword) const NOEXCEPT_MAYBE
{
return error_guard (ncplane_rounded_box (plane, attr, channels, ystop, xstop, ctlword), -1);
return error_guard (ncplane_rounded_box (plane, styles, channels, ystop, xstop, ctlword), -1);
}
bool rounded_box_sized (uint32_t attr, uint64_t channels, int ylen, int xlen, unsigned ctlword) const NOEXCEPT_MAYBE
bool rounded_box_sized (uint16_t styles, uint64_t channels, int ylen, int xlen, unsigned ctlword) const NOEXCEPT_MAYBE
{
return error_guard (ncplane_rounded_box_sized (plane, attr, channels, ylen, xlen, ctlword), -1);
return error_guard (ncplane_rounded_box_sized (plane, styles, channels, ylen, xlen, ctlword), -1);
}
bool double_box (uint32_t attr, uint64_t channels, int ystop, int xstop, unsigned ctlword) const NOEXCEPT_MAYBE
bool double_box (uint16_t styles, uint64_t channels, int ystop, int xstop, unsigned ctlword) const NOEXCEPT_MAYBE
{
return error_guard (ncplane_double_box (plane, attr, channels, ystop, xstop, ctlword), -1);
return error_guard (ncplane_double_box (plane, styles, channels, ystop, xstop, ctlword), -1);
}
bool double_box_sized (uint32_t attr, uint64_t channels, int ylen, int xlen, unsigned ctlword) const NOEXCEPT_MAYBE
bool double_box_sized (uint16_t styles, uint64_t channels, int ylen, int xlen, unsigned ctlword) const NOEXCEPT_MAYBE
{
return error_guard (ncplane_double_box_sized (plane, attr, channels, ylen, xlen, ctlword), -1);
return error_guard (ncplane_double_box_sized (plane, styles, channels, ylen, xlen, ctlword), -1);
}
bool perimeter (const Cell &ul, const Cell &ur, const Cell &ll, const Cell &lr, const Cell &hline, const Cell &vline, unsigned ctlword) const NOEXCEPT_MAYBE
@ -644,14 +644,14 @@ namespace ncpp
return error_guard (ncplane_perimeter (plane, ul, ur, ll, lr, hline, vline, ctlword), -1);
}
bool perimeter_rounded (uint32_t attrword, uint64_t channels, unsigned ctlword) const NOEXCEPT_MAYBE
bool perimeter_rounded (uint16_t stylemask, uint64_t channels, unsigned ctlword) const NOEXCEPT_MAYBE
{
return error_guard (ncplane_perimeter_rounded (plane, attrword, channels, ctlword), -1);
return error_guard (ncplane_perimeter_rounded (plane, stylemask, channels, ctlword), -1);
}
bool perimeter_double (uint32_t attrword, uint64_t channels, unsigned ctlword) const NOEXCEPT_MAYBE
bool perimeter_double (uint16_t stylemask, uint64_t channels, unsigned ctlword) const NOEXCEPT_MAYBE
{
return error_guard (ncplane_perimeter_double (plane, attrword, channels, ctlword), -1);
return error_guard (ncplane_perimeter_double (plane, stylemask, channels, ctlword), -1);
}
int polyfill (int y, int x, const Cell& c) const NOEXCEPT_MAYBE
@ -709,9 +709,9 @@ namespace ncpp
ncplane_set_channels (plane, channels);
}
void set_attr (uint32_t attrword) const noexcept
void set_attr (uint32_t attr) const noexcept
{
ncplane_set_attr (plane, attrword);
ncplane_set_attr (plane, attr);
}
bool set_fg_alpha (unsigned alpha) const NOEXCEPT_MAYBE
@ -809,9 +809,9 @@ namespace ncpp
ncplane_styles_off (plane, static_cast<unsigned>(styles));
}
int format (int ystop, int xstop, uint32_t attrword) const NOEXCEPT_MAYBE
int format (int ystop, int xstop, uint16_t stylemask) const NOEXCEPT_MAYBE
{
return error_guard<int> (ncplane_format (plane, ystop, xstop, attrword), -1);
return error_guard<int> (ncplane_format (plane, ystop, xstop, stylemask), -1);
}
int stain (int ystop, int xstop, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr) const NOEXCEPT_MAYBE
@ -830,9 +830,9 @@ namespace ncpp
return error_guard_cond<bool, bool> (ret, ret);
}
bool set_base (const char* egc, uint32_t attrword, uint64_t channels) const NOEXCEPT_MAYBE
bool set_base (const char* egc, uint16_t stylemask, uint64_t channels) const NOEXCEPT_MAYBE
{
bool ret = ncplane_set_base (plane, egc, attrword, channels) < 0;
bool ret = ncplane_set_base (plane, egc, stylemask, channels) < 0;
return error_guard_cond<bool, bool> (ret, ret);
}
@ -856,12 +856,12 @@ namespace ncpp
return at_cursor (*c);
}
char* at_cursor (uint32_t* attrword, uint64_t* channels) const
char* at_cursor (uint16_t* stylemask, uint64_t* channels) const
{
if (attrword == nullptr || channels == nullptr)
if (stylemask == nullptr || channels == nullptr)
return nullptr;
return ncplane_at_cursor (plane, attrword, channels);
return ncplane_at_cursor (plane, stylemask, channels);
}
int get_at (int y, int x, Cell &c) const NOEXCEPT_MAYBE
@ -877,12 +877,12 @@ namespace ncpp
return get_at (y, x, *c);
}
char* get_at (int y, int x, uint32_t* attrword, uint64_t* channels) const
char* get_at (int y, int x, uint16_t* stylemask, uint64_t* channels) const
{
if (attrword == nullptr || channels == nullptr)
if (stylemask == nullptr || channels == nullptr)
return nullptr;
return ncplane_at_yx (plane, y, x, attrword, channels);
return ncplane_at_yx (plane, y, x, stylemask, channels);
}
void* set_userptr (void *opaque) const noexcept
@ -925,9 +925,9 @@ namespace ncpp
return error_guard (cell_load_simple (plane, cell, ch), -1);
}
int prime (Cell &cell, const char *gcluster, uint32_t attr, uint64_t channels) const NOEXCEPT_MAYBE
int prime (Cell &cell, const char *gcluster, uint16_t styles, uint64_t channels) const NOEXCEPT_MAYBE
{
return error_guard<int> (cell_prime (plane, cell, gcluster, attr, channels), -1);
return error_guard<int> (cell_prime (plane, cell, gcluster, styles, channels), -1);
}
void release (Cell &cell) const noexcept

View File

@ -1,47 +0,0 @@
#ifndef NOTCURSES_ENDIANNESS
#define NOTCURSES_ENDIANNESS
// We would just use ntohl() and friends, except we need them in both a
// (1) compile-time and (2) C++ enum context. They're not permitted as
// C++ enum initializers. Thus this sorry affair.
#ifdef __cplusplus
extern "C" {
#endif
enum ncendianness_t {
NC_BIGENDIAN = 0x00000001llu,
NC_LITENDIAN = 0x01000000llu,
};
// Sprinkle parentheses of salt and recite the ancient incantation...
#ifdef __BIG_ENDIAN__
enum { NC_ENDIANNESS = NC_BIGENDIAN };
#define NC_LITTLEENDIAN 0
#else
#ifdef __LITTLE_ENDIAN__
enum { NC_ENDIANNESS = NC_LITENDIAN };
#define NC_LITTLEENDIAN 1
#else
#ifdef BSD
#include <sys/endian.h>
#else
#include <endian.h>
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
enum { NC_ENDIANNESS = NC_BIGENDIAN };
#define NC_LITTLEENDIAN 0
#elif __BYTE_ORDER == __LITTLE_ENDIAN
enum { NC_ENDIANNESS = NC_LITENDIAN };
#define NC_LITTLEENDIAN 1
#else
#error "Couldn't determine endianness"
#endif
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -15,7 +15,6 @@
#include <stdbool.h>
#include <notcurses/nckeys.h>
#include <notcurses/ncerrs.h>
#include <notcurses/endianness.h>
#ifdef __cplusplus
extern "C" {
@ -513,7 +512,7 @@ typedef struct cell {
// are required, it will be spilled into the egcpool. In either case, there's
// a NUL-terminated string available without copying, because (1) the egcpool
// is all NUL-terminated sequences and (2) the fifth byte of this struct (the
// first byte of the attrword, see below) is guaranteed to be zero, as are any
// gcluster_backstop field, see below) is guaranteed to be zero, as are any
// unused bytes in gcluster.
//
// A spilled EGC is indicated by the value 0x01XXXXXX. This cannot alias a
@ -524,15 +523,10 @@ typedef struct cell {
// The cost of this scheme is that the character 0x01 (SOH) cannot be encoded
// in a cell, which is absolutely fine because what 70s horseshit is SOH? It
// must not be allowed through the API, or havoc will result.
uint32_t gcluster; // 4B -> 4B
// 8 bits of zero + 8 reserved bits + NCSTYLE_* attributes (16 bits). The
// values of the NCSTYLE_* bits depend on endianness at compile time: we need
// them in the higher memory addresses, because we rely on the octet adjacent
// to gcluster being zero, as a backstop to a 4-byte inlined UTF-8 value.
// (attrword & 0xff000000): egc backstop, *must be zero*
// (attrword & 0x00ff0000): reserved
// (attrword & 0x0000ffff): NCSTYLE_* booleans
uint32_t attrword; // + 4B -> 8B
uint32_t gcluster; // 4B → 4B
uint8_t gcluster_backstop; // 1B → 5B (8 bits of zero)
uint8_t reserved; // 1B → 6B (8 reserved bits, ought be zero)
uint16_t stylemask; // 2B → 8B (16 bits of NCSTYLE_* attributes)
// (channels & 0x8000000000000000ull): part of a wide glyph
// (channels & 0x4000000000000000ull): foreground is *not* "default color"
// (channels & 0x3000000000000000ull): foreground alpha (2 bits)
@ -554,9 +548,9 @@ 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), }
#define CELL_TRIVIAL_INITIALIZER { }
#define CELL_SIMPLE_INITIALIZER(c) { .gcluster = (c), .gcluster_backstop = 0, .reserved = 0, .stylemask = 0, .channels = 0, }
#define CELL_INITIALIZER(c, s, chan) { .gcluster = (c), .gcluster_backstop = 0, .reserved = 0, .stylemask = (s), .channels = (chan), }
static inline void
cell_init(cell* c){
@ -572,8 +566,8 @@ 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;
uint32_t stylemask, uint64_t channels){
c->stylemask = stylemask;
c->channels = channels;
int ret = cell_load(n, c, gcluster);
return ret;
@ -587,46 +581,42 @@ API void cell_release(struct ncplane* n, cell* c);
// We want the 2 bytes at the highest address of a 32-bit word, so that the
// octet adjacent to g->clusters is left undisturbed as zero.
#ifdef NC_LITTLEENDIAN
#define NCSTYLE_MASK (0x0000fffful << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_STANDOUT (0x00000080ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_UNDERLINE (0x00000040ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_REVERSE (0x00000020ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_BLINK (0x00000010ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_DIM (0x00000008ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_BOLD (0x00000004ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_INVIS (0x00000002ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_PROTECT (0x00000001ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_ITALIC (0x00000100ul << (16u * NC_LITTLEENDIAN))
#define NCSTYLE_MASK 0xfffful
#define NCSTYLE_STANDOUT 0x0080ul
#define NCSTYLE_UNDERLINE 0x0040ul
#define NCSTYLE_REVERSE 0x0020ul
#define NCSTYLE_BLINK 0x0010ul
#define NCSTYLE_DIM 0x0008ul
#define NCSTYLE_BOLD 0x0004ul
#define NCSTYLE_INVIS 0x0002ul
#define NCSTYLE_PROTECT 0x0001ul
#define NCSTYLE_ITALIC 0x0100ul
#define NCSTYLE_NONE 0
#else
#error "Groping blindly through an uncaring universe, I know not my endianness"
#endif
// Set the specified style bits for the cell 'c', whether they're actively
// supported or not.
// supported or not. Only the lower 16 bits are meaningful.
static inline void
cell_styles_set(cell* c, unsigned stylebits){
c->attrword = (c->attrword & ~NCSTYLE_MASK) | ((stylebits & NCSTYLE_MASK));
c->stylemask = stylebits & NCSTYLE_MASK;
}
// Extract the style bits from the cell's attrword.
// Extract the style bits from the cell.
static inline unsigned
cell_styles(const cell* c){
return c->attrword & NCSTYLE_MASK;
return c->stylemask;
}
// 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);
c->stylemask |= (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);
c->stylemask &= ~(stylebits & NCSTYLE_MASK);
}
// Use the default color for the foreground.
@ -690,9 +680,9 @@ cell_strdup(const struct ncplane* n, const cell* c){
// 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;
uint16_t* stylemask, uint64_t* channels){
if(stylemask){
*stylemask = c->stylemask;
}
if(channels){
*channels = c->channels;
@ -707,7 +697,7 @@ cell_extract(const struct ncplane* n, const cell* c,
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){
if(c1->stylemask != c2->stylemask){
return true;
}
if(c1->channels != c2->channels){
@ -987,11 +977,11 @@ notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows, int* RESTRI
ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
}
// Retrieve the contents of the specified cell as last rendered. 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.
// Retrieve the contents of the specified cell as last rendered. Returns the EGC
// or NULL on error. This EGC must be free()d by the caller. The stylemask and
// channels are written to 'stylemask' and 'channels', respectively.
API char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff,
uint32_t* attrword, uint64_t* channels);
uint16_t* stylemask, uint64_t* channels);
// Create a new ncplane at the specified offset (relative to the standard plane)
// and the specified size. The number of rows and columns must both be positive.
@ -1158,7 +1148,7 @@ API int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);
// 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, const char* egc,
uint32_t attrword, uint64_t channels);
uint32_t stylemask, uint64_t channels);
// Extract the ncplane's base cell into 'c'. The reference is invalidated if
// 'ncp' is destroyed.
@ -1207,20 +1197,18 @@ API int ncplane_rotate_ccw(struct ncplane* n);
// 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);
// stylemask and channels are written to 'stylemask' and 'channels', respectively.
API char* ncplane_at_cursor(struct ncplane* n, uint16_t* stylemask, uint64_t* channels);
// 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);
char* egc = ncplane_at_cursor(n, &c->stylemask, &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);
}
@ -1228,16 +1216,16 @@ 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.
// NULL on error. This EGC must be free()d by the caller. The stylemask and
// channels are written to 'stylemask' and 'channels', respectively.
API char* ncplane_at_yx(const struct ncplane* n, int y, int x,
uint32_t* attrword, uint64_t* channels);
uint16_t* stylemask, 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);
char* egc = ncplane_at_yx(n, y, x, &c->stylemask, &c->channels);
if(!egc){
return -1;
}
@ -1297,7 +1285,9 @@ API void ncplane_cursor_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRI
// Get the current channels or attribute word for ncplane 'n'.
API uint64_t ncplane_channels(const struct ncplane* n);
API uint32_t ncplane_attr(const struct ncplane* n);
// Return the current styling for this ncplane.
API uint16_t ncplane_attr(const struct ncplane* n);
// 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
@ -1642,7 +1632,7 @@ ncplane_perimeter(struct ncplane* n, const cell* ul, const cell* ur,
API int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const cell* c);
// Draw a gradient with its upper-left corner at the current cursor position,
// stopping at 'ystop'x'xstop'. The glyph composed of 'egc' and 'attrword' is
// stopping at 'ystop'x'xstop'. The glyph composed of 'egc' and 'stylemask' is
// used for all cells. The channels specified by 'ul', 'ur', 'll', and 'lr'
// are composed into foreground and background gradients. To do a vertical
// gradient, 'ul' ought equal 'ur' and 'll' ought equal 'lr'. To do a
@ -1660,7 +1650,7 @@ API int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const cell* c);
// 1x1: all four colors must be the same
// 1xN: both top and both bottom colors must be the same (vertical gradient)
// Nx1: both left and both right colors must be the same (horizontal gradient)
API int ncplane_gradient(struct ncplane* n, const char* egc, uint32_t attrword,
API int ncplane_gradient(struct ncplane* n, const char* egc, uint32_t stylemask,
uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr,
int ystop, int xstop);
@ -1674,7 +1664,7 @@ API int ncplane_highgradient(struct ncplane* n, uint32_t ul, uint32_t ur,
// Draw a gradient with its upper-left corner at the current cursor position,
// having dimensions 'ylen'x'xlen'. See ncplane_gradient for more information.
static inline int
ncplane_gradient_sized(struct ncplane* n, const char* egc, uint32_t attrword,
ncplane_gradient_sized(struct ncplane* n, const char* egc, uint32_t stylemask,
uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr,
int ylen, int xlen){
if(ylen < 1 || xlen < 1){
@ -1682,7 +1672,8 @@ ncplane_gradient_sized(struct ncplane* n, const char* egc, uint32_t attrword,
}
int y, x;
ncplane_cursor_yx(n, &y, &x);
return ncplane_gradient(n, egc, attrword, ul, ur, ll, lr, y + ylen - 1, x + xlen - 1);
return ncplane_gradient(n, egc, stylemask, ul, ur, ll, lr,
y + ylen - 1, x + xlen - 1);
}
static inline int
@ -1703,7 +1694,7 @@ ncplane_highgradient_sized(struct ncplane* n, uint32_t ul, uint32_t ur,
// Set the given style throughout the specified region, keeping content and
// channels unchanged. Returns the number of cells set, or -1 on failure.
API int ncplane_format(struct ncplane* n, int ystop, int xstop, uint32_t attrword);
API int ncplane_format(struct ncplane* n, int ystop, int xstop, uint32_t stylemask);
// Set the given channels throughout the specified region, keeping content and
// attributes unchanged. Returns the number of cells set, or -1 on failure.
@ -1950,7 +1941,17 @@ ncplane_fchannel(const struct ncplane* nc){
API void ncplane_set_channels(struct ncplane* nc, uint64_t channels);
API void ncplane_set_attr(struct ncplane* nc, uint32_t attrword);
API void ncplane_set_attr(struct ncplane* n, unsigned stylebits);
// Set the specified style bits for the ncplane 'n', whether they're actively
// supported or not.
API void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
// Add the specified styles to the ncplane's existing spec.
API void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
// Remove the specified styles from the ncplane's existing spec.
API void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
// Extract 24 bits of working foreground RGB from an ncplane, shifted to LSBs.
static inline unsigned
@ -2030,19 +2031,6 @@ API int ncplane_set_bg_palindex(struct ncplane* n, int idx);
API int ncplane_set_fg_alpha(struct ncplane* n, int alpha);
API int ncplane_set_bg_alpha(struct ncplane* n, int alpha);
// Set the specified style bits for the ncplane 'n', whether they're actively
// supported or not.
API void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
// Add the specified styles to the ncplane's existing spec.
API void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
// Remove the specified styles from the ncplane's existing spec.
API void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
// Return the current styling for this ncplane.
API unsigned ncplane_styles(const struct ncplane* n);
// Called for each fade iteration on 'ncp'. If anything but 0 is returned,
// the fading operation ceases immediately, and that value is propagated out.
// The recommended absolute display time target is passed in 'tspec'.
@ -2094,16 +2082,16 @@ API void ncfadectx_free(struct ncfadectx* nctx);
// have loaded before the error are cell_release()d. There must be at least
// six EGCs in gcluster.
static inline int
cells_load_box(struct ncplane* n, uint32_t attrs, uint64_t channels,
cells_load_box(struct ncplane* n, uint32_t styles, uint64_t channels,
cell* ul, cell* ur, cell* ll, cell* lr,
cell* hl, cell* vl, const char* gclusters){
int ulen;
if((ulen = cell_prime(n, ul, gclusters, attrs, channels)) > 0){
if((ulen = cell_prime(n, ur, gclusters += ulen, attrs, channels)) > 0){
if((ulen = cell_prime(n, ll, gclusters += ulen, attrs, channels)) > 0){
if((ulen = cell_prime(n, lr, gclusters += ulen, attrs, channels)) > 0){
if((ulen = cell_prime(n, hl, gclusters += ulen, attrs, channels)) > 0){
if((ulen = cell_prime(n, vl, gclusters += ulen, attrs, channels)) > 0){
if((ulen = cell_prime(n, ul, gclusters, styles, channels)) > 0){
if((ulen = cell_prime(n, ur, gclusters += ulen, styles, channels)) > 0){
if((ulen = cell_prime(n, ll, gclusters += ulen, styles, channels)) > 0){
if((ulen = cell_prime(n, lr, gclusters += ulen, styles, channels)) > 0){
if((ulen = cell_prime(n, hl, gclusters += ulen, styles, channels)) > 0){
if((ulen = cell_prime(n, vl, gclusters += ulen, styles, channels)) > 0){
return 0;
}
cell_release(n, hl);
@ -2119,18 +2107,18 @@ cells_load_box(struct ncplane* n, uint32_t attrs, uint64_t channels,
return -1;
}
API int cells_rounded_box(struct ncplane* n, uint32_t attr, uint64_t channels,
API int cells_rounded_box(struct ncplane* n, uint32_t styles, uint64_t channels,
cell* ul, cell* ur, cell* ll, cell* lr,
cell* hl, cell* vl);
static inline int
ncplane_rounded_box(struct ncplane* n, uint32_t attr, uint64_t channels,
ncplane_rounded_box(struct ncplane* n, uint32_t styles, uint64_t channels,
int ystop, int xstop, unsigned ctlword){
int ret = 0;
cell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
cell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER, vl = CELL_TRIVIAL_INITIALIZER;
if((ret = cells_rounded_box(n, attr, channels, &ul, &ur, &ll, &lr, &hl, &vl)) == 0){
if((ret = cells_rounded_box(n, styles, channels, &ul, &ur, &ll, &lr, &hl, &vl)) == 0){
ret = ncplane_box(n, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword);
}
cell_release(n, &ul); cell_release(n, &ur);
@ -2140,7 +2128,7 @@ ncplane_rounded_box(struct ncplane* n, uint32_t attr, uint64_t channels,
}
static inline int
ncplane_perimeter_rounded(struct ncplane* n, uint32_t attrword,
ncplane_perimeter_rounded(struct ncplane* n, uint32_t stylemask,
uint64_t channels, unsigned ctlword){
if(ncplane_cursor_move_yx(n, 0, 0)){
return -1;
@ -2153,7 +2141,7 @@ ncplane_perimeter_rounded(struct ncplane* n, uint32_t attrword,
cell lr = CELL_TRIVIAL_INITIALIZER;
cell vl = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER;
if(cells_rounded_box(n, attrword, channels, &ul, &ur, &ll, &lr, &hl, &vl)){
if(cells_rounded_box(n, stylemask, channels, &ul, &ur, &ll, &lr, &hl, &vl)){
return -1;
}
int r = ncplane_box_sized(n, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, ctlword);
@ -2164,11 +2152,11 @@ ncplane_perimeter_rounded(struct ncplane* n, uint32_t attrword,
}
static inline int
ncplane_rounded_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels,
ncplane_rounded_box_sized(struct ncplane* n, uint32_t styles, uint64_t channels,
int ylen, int xlen, unsigned ctlword){
int y, x;
ncplane_cursor_yx(n, &y, &x);
return ncplane_rounded_box(n, attr, channels, y + ylen - 1,
return ncplane_rounded_box(n, styles, channels, y + ylen - 1,
x + xlen - 1, ctlword);
}
@ -2193,7 +2181,7 @@ ncplane_double_box(struct ncplane* n, uint32_t attr, uint64_t channels,
}
static inline int
ncplane_perimeter_double(struct ncplane* n, uint32_t attrword,
ncplane_perimeter_double(struct ncplane* n, uint32_t stylemask,
uint64_t channels, unsigned ctlword){
if(ncplane_cursor_move_yx(n, 0, 0)){
return -1;
@ -2206,7 +2194,7 @@ ncplane_perimeter_double(struct ncplane* n, uint32_t attrword,
cell lr = CELL_TRIVIAL_INITIALIZER;
cell vl = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER;
if(cells_double_box(n, attrword, channels, &ul, &ur, &ll, &lr, &hl, &vl)){
if(cells_double_box(n, stylemask, channels, &ul, &ur, &ll, &lr, &hl, &vl)){
return -1;
}
int r = ncplane_box_sized(n, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, ctlword);

View File

@ -27,8 +27,10 @@ char32_t notcurses_getc_nblock(struct notcurses* n, ncinput* ni);
char32_t notcurses_getc_blocking(struct notcurses* n, ncinput* ni);
int notcurses_inputready_fd(struct notcurses* n);
typedef struct cell {
uint32_t gcluster; // 1 * 4b -> 4b
uint32_t attrword; // + 4b -> 8b
uint32_t gcluster; // 4B 4B
uint8_t gcluster_backstop; // 1B 5B (8 bits of zero)
uint8_t reserved; // 1B 6B (8 reserved bits, ought be zero)
uint16_t stylemask; // 2B 8B (16 bits of NCSTYLE_* attributes)
uint64_t channels; // + 8b == 16b
} cell;
typedef enum {
@ -57,6 +59,7 @@ int notcurses_render(struct notcurses*);
int notcurses_render_to_file(struct notcurses* nc, FILE* fp);
struct ncplane* notcurses_stdplane(struct notcurses*);
const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
void ncplane_set_channels(struct ncplane* nc, uint64_t channels);
int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);
int ncplane_set_base(struct ncplane* ncp, const char* egc, uint32_t attrword, uint64_t channels);
int ncplane_base(struct ncplane* ncp, cell* c);
@ -100,10 +103,10 @@ void ncplane_move_bottom(struct ncplane* n);
int ncplane_move_below(struct ncplane* restrict n, struct ncplane* restrict below);
int ncplane_move_above(struct ncplane* restrict n, struct ncplane* restrict 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);
char* ncplane_at_cursor(struct ncplane* n, uint32_t* attrword, uint64_t* channels);
char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff, uint16_t* stylemask, uint64_t* channels);
char* ncplane_at_cursor(struct ncplane* n, uint16_t* stylemask, uint64_t* channels);
int ncplane_at_cursor_cell(struct ncplane* n, cell* c);
char* ncplane_at_yx(const struct ncplane* n, int y, int x, uint32_t* attrword, uint64_t* channels);
char* ncplane_at_yx(const struct ncplane* n, int y, int x, uint16_t* stylemask, uint64_t* channels);
int ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c);
typedef enum {
NCBLIT_1x1, // full block
@ -124,7 +127,7 @@ void* ncplane_userptr(struct ncplane* n);
int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny,
int keeplenx, int yoff, int xoff, int ylen, int xlen);
uint64_t ncplane_channels(struct ncplane* n);
uint32_t ncplane_attr(struct ncplane* n);
uint16_t ncplane_attr(struct ncplane* n);
unsigned ncplane_bchannel(struct ncplane* nc);
unsigned ncplane_fchannel(struct ncplane* nc);
unsigned ncplane_fg(struct ncplane* nc);
@ -148,7 +151,7 @@ int ncplane_set_bg_palindex(struct ncplane* n, int idx);
void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
unsigned ncplane_styles(const struct ncplane* n);
unsigned ncplane_attr(const struct ncplane* n);
typedef struct ncstats {
uint64_t renders; // number of successful notcurses_render() runs
uint64_t failed_renders; // number of aborted renders, should be 0

View File

@ -253,7 +253,7 @@ ncreel_demo_core(struct notcurses* nc){
tctxs = newtablet;
}
do{
ncplane_styles_set(std, 0);
ncplane_styles_set(std, NCPLANE_NONE);
ncplane_set_fg_rgb(std, 197, 15, 31);
int count = ncreel_tabletcount(pr);
ncplane_styles_on(std, NCSTYLE_BOLD);

View File

@ -67,7 +67,7 @@ tria_blit_ascii(ncplane* nc, int placey, int placex, int linesize,
// use the default for the background, as that's the only way it's
// effective in that case anyway
c->channels = 0;
c->attrword = 0;
c->stylemask = 0;
if(blendcolors){
cell_set_bg_alpha(c, CELL_ALPHA_BLEND);
cell_set_fg_alpha(c, CELL_ALPHA_BLEND);
@ -121,7 +121,7 @@ tria_blit(ncplane* nc, int placey, int placex, int linesize,
// use the default for the background, as that's the only way it's
// effective in that case anyway
c->channels = 0;
c->attrword = 0;
c->stylemask = 0;
if(blendcolors){
cell_set_bg_alpha(c, CELL_ALPHA_BLEND);
cell_set_fg_alpha(c, CELL_ALPHA_BLEND);
@ -307,7 +307,7 @@ quadrant_blit(ncplane* nc, int placey, int placex, int linesize,
//fprintf(stderr, "[%04d/%04d] bpp: %d lsize: %d %02x %02x %02x %02x\n", y, x, bpp, linesize, rgbbase_tl[0], rgbbase_tr[1], rgbbase_bl[2], rgbbase_br[3]);
cell* c = ncplane_cell_ref_yx(nc, y, x);
c->channels = 0;
c->attrword = 0;
c->stylemask = 0;
// FIXME for now, we're only transparent if all four are transparent. we ought
// match transparent like anything else...
const char* egc = NULL;
@ -443,7 +443,7 @@ braille_blit(ncplane* nc, int placey, int placex, int linesize,
// use the default for the background, as that's the only way it's
// effective in that case anyway
c->channels = 0;
c->attrword = 0;
c->stylemask = 0;
if(blendcolors){
cell_set_fg_alpha(c, CELL_ALPHA_BLEND);
}

View File

@ -277,7 +277,7 @@ ncdirect_dump_plane(ncdirect* n, const ncplane* np, int xoff){
}
}
for(int x = 0 ; x < dimx ; ++x){
uint32_t attrword;
uint16_t attrword;
uint64_t channels;
char* egc = ncplane_at_yx(np, y, x, &attrword, &channels);
if(egc == nullptr){

View File

@ -188,7 +188,7 @@ int ncplane_highgradient(ncplane* n, uint32_t ul, uint32_t ur,
return total;
}
int ncplane_gradient(ncplane* n, const char* egc, uint32_t attrword,
int ncplane_gradient(ncplane* n, const char* egc, uint32_t stylemask,
uint64_t ul, uint64_t ur, uint64_t bl, uint64_t br,
int ystop, int xstop){
if(check_gradient_args(ul, ur, bl, br)){
@ -236,7 +236,7 @@ int ncplane_gradient(ncplane* n, const char* egc, uint32_t attrword,
if(cell_load(n, targc, egc) < 0){
return -1;
}
targc->attrword = attrword;
targc->stylemask = stylemask;
calc_gradient_channels(&targc->channels, ul, ur, bl, br,
y - yoff, x - xoff, ylen, xlen);
++total;
@ -281,7 +281,7 @@ int ncplane_stain(struct ncplane* n, int ystop, int xstop,
return total;
}
int ncplane_format(struct ncplane* n, int ystop, int xstop, uint32_t attrword){
int ncplane_format(struct ncplane* n, int ystop, int xstop, uint32_t stylemask){
int yoff, xoff, ymax, xmax;
ncplane_cursor_yx(n, &yoff, &xoff);
// must be at least 1x1, with its upper-left corner at the current cursor
@ -300,7 +300,7 @@ int ncplane_format(struct ncplane* n, int ystop, int xstop, uint32_t attrword){
for(int y = yoff ; y < ystop + 1 ; ++y){
for(int x = xoff ; x < xstop + 1 ; ++x){
cell* targc = ncplane_cell_ref_yx(n, y, x);
targc->attrword = attrword;
targc->stylemask = stylemask;
++total;
}
}

View File

@ -78,12 +78,12 @@ typedef struct ncplane {
struct ncplane* boundto; // plane to which we are bound, if any
egcpool pool; // attached storage pool for UTF-8 EGCs
uint64_t channels; // works the same way as cells
uint32_t attrword; // same deal as in a cell
void* userptr; // slot for the user to stick some opaque pointer
cell basecell; // cell written anywhere that fb[i].gcluster == 0
struct notcurses* nc; // notcurses object of which we are a part
bool scrolling; // is scrolling enabled? always disabled by default
char* name; // used only for debugging
uint16_t stylemask; // same deal as in a cell
bool scrolling; // is scrolling enabled? always disabled by default
} ncplane;
#include "blitset.h"
@ -542,13 +542,8 @@ ns_to_timespec(uint64_t ns, struct timespec* ts){
static inline void
cell_debug(const egcpool* p, const cell* c){
if(cell_simple_p(c)){
fprintf(stderr, "gcluster: %u %c attr: 0x%08x chan: 0x%016jx\n",
c->gcluster, c->gcluster, c->attrword, c->channels);
}else{
fprintf(stderr, "gcluster: %u %s attr: 0x%08x chan: 0x%016jx\n",
c->gcluster, egcpool_extended_gcluster(p, c), c->attrword, c->channels);
}
fprintf(stderr, "gcluster: %u %s style: 0x%04x chan: 0x%016jx\n",
c->gcluster, egcpool_extended_gcluster(p, c), c->stylemask, c->channels);
}
static inline void
@ -579,7 +574,7 @@ pool_release(egcpool* pool, cell* c){
static inline int
cell_duplicate_far(egcpool* tpool, cell* targ, const ncplane* splane, const cell* c){
pool_release(tpool, targ);
targ->attrword = c->attrword;
targ->stylemask = c->stylemask;
targ->channels = c->channels;
if(cell_simple_p(c)){
targ->gcluster = c->gcluster;

View File

@ -236,7 +236,7 @@ write_header(ncmenu* ncm){ ncm->ncp->channels = ncm->headerchannels;
return -1;
}
cell c = CELL_INITIALIZER(' ', 0, ncm->headerchannels);
ncplane_styles_set(ncm->ncp, 0);
ncplane_set_attr(ncm->ncp, 0);
if(ncplane_putc(ncm->ncp, &c) < 0){
return -1;
}
@ -372,9 +372,9 @@ int ncmenu_unroll(ncmenu* n, int sectionidx){
if(sec->items[i].desc){
n->ncp->channels = n->sectionchannels;
if(i == sec->itemselected){
ncplane_styles_set(n->ncp, NCSTYLE_REVERSE);
ncplane_set_attr(n->ncp, NCSTYLE_REVERSE);
}else{
ncplane_styles_set(n->ncp, 0);
ncplane_set_attr(n->ncp, 0);
}
int cols = ncplane_putstr_yx(n->ncp, ypos, xpos + 1, sec->items[i].desc);
if(cols < 0){
@ -411,7 +411,7 @@ int ncmenu_unroll(ncmenu* n, int sectionidx){
}
}else{
n->ncp->channels = n->headerchannels;
ncplane_styles_set(n->ncp, 0);
ncplane_set_attr(n->ncp, 0);
if(ncplane_putegc_yx(n->ncp, ypos, xpos, "", NULL) < 0){
return -1;
}

View File

@ -211,18 +211,18 @@ cursor_invalid_p(const ncplane* n){
return false;
}
char* ncplane_at_cursor(ncplane* n, uint32_t* attrword, uint64_t* channels){
char* ncplane_at_cursor(ncplane* n, uint16_t* stylemask, uint64_t* channels){
if(cursor_invalid_p(n)){
return NULL;
}
return cell_extract(n, &n->fb[nfbcellidx(n, n->y, n->x)], attrword, channels);
return cell_extract(n, &n->fb[nfbcellidx(n, n->y, n->x)], stylemask, channels);
}
char* ncplane_at_yx(const ncplane* n, int y, int x, uint32_t* attrword, uint64_t* channels){
char* ncplane_at_yx(const ncplane* n, int y, int x, uint16_t* stylemask, uint64_t* channels){
char* ret = NULL;
if(y < n->leny && x < n->lenx){
if(y >= 0 && x >= 0){
ret = cell_extract(n, &n->fb[nfbcellidx(n, y, x)], attrword, channels);
ret = cell_extract(n, &n->fb[nfbcellidx(n, y, x)], stylemask, channels);
}
}
return ret;
@ -330,7 +330,7 @@ ncplane* ncplane_create(notcurses* nc, ncplane* n, int rows, int cols,
p->bnext = NULL;
p->bprev = NULL;
}
p->attrword = 0;
p->stylemask = 0;
p->channels = 0;
egcpool_init(&p->pool);
cell_init(&p->basecell);
@ -438,7 +438,7 @@ inline int ncplane_cursor_move_yx(ncplane* n, int y, int x){
ncplane* ncplane_dup(const ncplane* n, void* opaque){
int dimy = n->leny;
int dimx = n->lenx;
uint32_t attr = ncplane_attr(n);
uint16_t attr = ncplane_attr(n);
uint64_t chan = ncplane_channels(n);
// if we're duping the standard plane, we need adjust for marginalia
const struct notcurses* nc = ncplane_notcurses_const(n);
@ -455,7 +455,7 @@ ncplane* ncplane_dup(const ncplane* n, void* opaque){
ncplane_destroy(newn);
return NULL;
}
newn->attrword = attr;
newn->stylemask = attr;
newn->channels = chan;
memmove(newn->fb, n->fb, sizeof(*n->fb) * dimx * dimy);
// we dupd the egcpool, so just dup the goffset
@ -724,15 +724,13 @@ init_banner(const notcurses* nc){
if(!nc->suppress_banner){
char prefixbuf[BPREFIXSTRLEN + 1];
term_fg_palindex(nc, stdout, nc->tcache.colors <= 256 ? 50 % nc->tcache.colors : 0x20e080);
// FIXME do runtime detection of endianness, ensure it matches compile time
printf("\n notcurses %s %s by nick black et al", notcurses_version(),
(int)NC_ENDIANNESS == (int)NC_BIGENDIAN ? "BE" : "LE");
printf("\n notcurses %s by nick black et al", notcurses_version());
term_fg_palindex(nc, stdout, nc->tcache.colors <= 256 ? 12 % nc->tcache.colors : 0x2080e0);
printf("\n %d rows, %d columns (%sB), %d colors (%s)\n"
printf("\n %d rows %d cols (%sB) %zub cells %d colors (%s)\n"
" compiled with gcc-%s\n"
" terminfo from %s\n",
nc->stdplane->leny, nc->stdplane->lenx,
bprefix(nc->stats.fbbytes, 1, prefixbuf, 0),
bprefix(nc->stats.fbbytes, 1, prefixbuf, 0), sizeof(cell),
nc->tcache.colors, nc->tcache.RGBflag ? "direct" : "palette",
__VERSION__, curses_version());
#ifdef USE_FFMPEG
@ -1098,18 +1096,14 @@ uint64_t ncplane_channels(const ncplane* n){
return n->channels;
}
uint32_t ncplane_attr(const ncplane* n){
return n->attrword;
uint16_t ncplane_attr(const ncplane* n){
return n->stylemask;
}
void ncplane_set_channels(ncplane* n, uint64_t channels){
n->channels = channels;
}
void ncplane_set_attr(ncplane* n, uint32_t attrword){
n->attrword = attrword;
}
void ncplane_set_fg_default(ncplane* n){
channels_set_fg_default(&n->channels);
}
@ -1157,8 +1151,8 @@ int ncplane_set_fg_palindex(ncplane* n, int idx){
n->channels |= CELL_FGDEFAULT_MASK;
n->channels |= CELL_FG_PALETTE;
channels_set_fg_alpha(&n->channels, CELL_ALPHA_OPAQUE);
n->attrword &= 0xffff00ff;
n->attrword |= (idx << 8u);
n->stylemask &= 0xffff00ff;
n->stylemask |= (idx << 8u);
return 0;
}
@ -1169,8 +1163,8 @@ int ncplane_set_bg_palindex(ncplane* n, int idx){
n->channels |= CELL_BGDEFAULT_MASK;
n->channels |= CELL_BG_PALETTE;
channels_set_bg_alpha(&n->channels, CELL_ALPHA_OPAQUE);
n->attrword &= 0xffffff00;
n->attrword |= idx;
n->stylemask &= 0xffffff00;
n->stylemask |= idx;
return 0;
}
@ -1178,8 +1172,8 @@ int ncplane_set_base_cell(ncplane* ncp, const cell* c){
return cell_duplicate(ncp, &ncp->basecell, c);
}
int ncplane_set_base(ncplane* ncp, const char* egc, uint32_t attrword, uint64_t channels){
return cell_prime(ncp, &ncp->basecell, egc, attrword, channels);
int ncplane_set_base(ncplane* ncp, const char* egc, uint32_t stylemask, uint64_t channels){
return cell_prime(ncp, &ncp->basecell, egc, stylemask, channels);
}
int ncplane_base(ncplane* ncp, cell* c){
@ -1461,7 +1455,7 @@ int ncplane_putegc_yx(ncplane* n, int y, int x, const char* gclust, int* sbytes)
return -1;
}
//fprintf(stderr, "%08x %d %d\n", targ->gcluster, bytes, cols);
targ->attrword = n->attrword;
targ->stylemask = n->stylemask;
targ->channels = channels;
if(wide){ // must set our right wide, and check for further damage
if(n->x < n->lenx - 1){ // check to our right
@ -1474,7 +1468,7 @@ int ncplane_putegc_yx(ncplane* n, int y, int x, const char* gclust, int* sbytes)
cell_obliterate(n, candidate);
cell_set_wide(candidate);
candidate->channels = channels;
candidate->attrword = n->attrword;
candidate->stylemask = n->stylemask;
}
}
n->x += cols;
@ -1483,37 +1477,37 @@ int ncplane_putegc_yx(ncplane* n, int y, int x, const char* gclust, int* sbytes)
int ncplane_putsimple_stainable(ncplane* n, char c){
uint64_t channels = n->channels;
uint32_t attrword = n->attrword;
uint32_t stylemask = n->stylemask;
const cell* targ = &n->fb[nfbcellidx(n, n->y, n->x)];
n->channels = targ->channels;
n->attrword = targ->attrword;
n->stylemask = targ->stylemask;
int ret = ncplane_putsimple(n, c);
n->channels = channels;
n->attrword = attrword;
n->stylemask = stylemask;
return ret;
}
int ncplane_putwegc_stainable(ncplane* n, const wchar_t* gclust, int* sbytes){
uint64_t channels = n->channels;
uint32_t attrword = n->attrword;
uint32_t stylemask = n->stylemask;
const cell* targ = &n->fb[nfbcellidx(n, n->y, n->x)];
n->channels = targ->channels;
n->attrword = targ->attrword;
n->stylemask = targ->stylemask;
int ret = ncplane_putwegc(n, gclust, sbytes);
n->channels = channels;
n->attrword = attrword;
n->stylemask = stylemask;
return ret;
}
int ncplane_putegc_stainable(ncplane* n, const char* gclust, int* sbytes){
uint64_t channels = n->channels;
uint32_t attrword = n->attrword;
uint32_t stylemask = n->stylemask;
const cell* targ = &n->fb[nfbcellidx(n, n->y, n->x)];
n->channels = targ->channels;
n->attrword = targ->attrword;
n->stylemask = targ->stylemask;
int ret = ncplane_putegc(n, gclust, sbytes);
n->channels = channels;
n->attrword = attrword;
n->stylemask = stylemask;
return ret;
}
@ -1553,23 +1547,28 @@ bool notcurses_cantruecolor(const notcurses* nc){
return nc->tcache.RGBflag;
}
// conform to the specified stylebits
void ncplane_styles_set(ncplane* n, unsigned stylebits){
n->stylemask = (stylebits & NCSTYLE_MASK);
}
// turn on any specified stylebits
void ncplane_styles_on(ncplane* n, unsigned stylebits){
n->attrword |= (stylebits & NCSTYLE_MASK);
n->stylemask |= (stylebits & NCSTYLE_MASK);
}
// turn off any specified stylebits
void ncplane_styles_off(ncplane* n, unsigned stylebits){
n->attrword &= ~(stylebits & NCSTYLE_MASK);
n->stylemask &= ~(stylebits & NCSTYLE_MASK);
}
// set the current stylebits to exactly those provided
void ncplane_styles_set(ncplane* n, unsigned stylebits){
n->attrword = (n->attrword & ~NCSTYLE_MASK) | ((stylebits & NCSTYLE_MASK));
void ncplane_set_attr(ncplane* n, unsigned stylebits){
n->stylemask = stylebits & NCSTYLE_MASK;
}
unsigned ncplane_styles(const ncplane* n){
return (n->attrword & NCSTYLE_MASK);
return n->stylemask;
}
// i hate the big allocation and two copies here, but eh what you gonna do?
@ -2141,7 +2140,7 @@ void ncplane_yx(const ncplane* n, int* y, int* x){
void ncplane_erase(ncplane* n){
// we must preserve the background, but a pure cell_duplicate() would be
// wiped out by the egcpool_dump(). do a duplication (to get the attrword
// wiped out by the egcpool_dump(). do a duplication (to get the stylemask
// and channels), and then reload.
char* egc = cell_strdup(n, &n->basecell);
memset(n->fb, 0, sizeof(*n->fb) * n->lenx * n->leny);
@ -2432,9 +2431,9 @@ uint32_t* ncplane_rgba(const ncplane* nc, ncblitter_e blit,
for(int y = begy, targy = 0 ; y < begy + leny ; ++y, targy += 2){
for(int x = begx, targx = 0 ; x < begx + lenx ; ++x, ++targx){
// FIXME what if there's a wide glyph to the left of the selection?
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* c = ncplane_at_yx(nc, y, x, &attrword, &channels);
char* c = ncplane_at_yx(nc, y, x, &stylemask, &channels);
if(c == NULL){
free(ret);
return NULL;
@ -2504,9 +2503,9 @@ char* ncplane_contents(const ncplane* nc, int begy, int begx, int leny, int lenx
if(ret){
for(int y = begy, targy = 0 ; y < begy + leny ; ++y, targy += 2){
for(int x = begx, targx = 0 ; x < begx + lenx ; ++x, ++targx){
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* c = ncplane_at_yx(nc, y, x, &attrword, &channels);
char* c = ncplane_at_yx(nc, y, x, &stylemask, &channels);
if(!c){
free(ret);
return NULL;

View File

@ -137,7 +137,7 @@ int cell_duplicate(ncplane* n, cell* targ, const cell* c){
static int
cellcmp_and_dupfar(egcpool* dampool, cell* damcell,
const ncplane* srcplane, const cell* srccell){
if(damcell->attrword == srccell->attrword){
if(damcell->stylemask == srccell->stylemask){
if(damcell->channels == srccell->channels){
bool srcsimple = cell_simple_p(srccell);
bool damsimple = cell_simple_p(damcell);
@ -329,7 +329,7 @@ paint(ncplane* p, cell* lastframe, struct crender* rvec,
}
}
crender->p = p;
targc->attrword = vis->attrword;
targc->stylemask = vis->stylemask;
}else if(cell_wide_left_p(vis)){
cell_set_wide(targc);
}
@ -396,7 +396,7 @@ fprintf(stderr, "WROTE %u [%s] to %d/%d (%d/%d)\n", targc->gcluster, extended_gc
++targc;
targc->gcluster = 0;
targc->channels = targc[-1].channels;
targc->attrword = targc[-1].attrword;
targc->stylemask = targc[-1].stylemask;
if(cellcmp_and_dupfar(pool, prevcell, crender->p, targc)){
crender->damaged = true;
}
@ -1080,14 +1080,14 @@ pool_egc_copy(const egcpool* e, const cell* c){
return strdup(egcpool_extended_gcluster(e, c));
}
char* notcurses_at_yx(notcurses* nc, int yoff, int xoff, uint32_t* attrword, uint64_t* channels){
char* notcurses_at_yx(notcurses* nc, int yoff, int xoff, uint16_t* stylemask, uint64_t* channels){
char* egc = NULL;
if(nc->lastframe){
if(yoff >= 0 && yoff < nc->lfdimy){
if(xoff >= 0 || xoff < nc->lfdimx){
const cell* srccell = &nc->lastframe[yoff * nc->lfdimx + xoff];
if(attrword){
*attrword = srccell->attrword;
if(stylemask){
*stylemask = srccell->stylemask;
}
if(channels){
*channels = srccell->channels;

View File

@ -94,7 +94,7 @@ TEST_CASE("Fills") {
for(int x = 0 ; x < dimx ; ++x){
REQUIRE(0 <= ncplane_at_yx_cell(n_, y, x, &cl));
CHECK('M' == cl.gcluster);
CHECK(0 == cl.attrword);
CHECK(0 == cl.stylemask);
CHECK(channels == cl.channels);
}
}
@ -128,7 +128,7 @@ TEST_CASE("Fills") {
for(int x = 0 ; x < dimx ; ++x){
REQUIRE(0 <= ncplane_at_yx_cell(n_, y, x, &c));
CHECK('V' == c.gcluster);
CHECK(0 == c.attrword);
CHECK(0 == c.stylemask);
if(lastxrgb == (uint64_t)-1){
if(lastyrgb == (uint64_t)-1){
lastyrgb = c.channels;
@ -217,10 +217,10 @@ TEST_CASE("Fills") {
CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
cell c = CELL_TRIVIAL_INITIALIZER;
cell_styles_on(&c, NCSTYLE_BOLD);
CHECK(0 < ncplane_format(n_, 0, 0, c.attrword));
CHECK(0 < ncplane_format(n_, 0, 0, c.stylemask));
cell d = CELL_TRIVIAL_INITIALIZER;
CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &d));
CHECK(d.attrword == c.attrword);
CHECK(d.stylemask == c.stylemask);
CHECK(0x444444 == cell_fg(&d));
}

View File

@ -482,13 +482,13 @@ TEST_CASE("NCPlane") {
const char STR1[] = "Jackdaws love my big sphinx of quartz";
const char STR2[] = "Cwm fjord bank glyphs vext quiz";
const char STR3[] = "Pack my box with five dozen liquor jugs";
ncplane_styles_set(n_, 0);
ncplane_styles_set(n_, NCSCALE_NONE);
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_cell(n_, &testcell)); // want nothing at the cursor
CHECK(0 == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.stylemask);
CHECK(0 == testcell.channels);
int dimy, dimx;
ncplane_dim_yx(n_, &dimy, &dimx);
@ -503,12 +503,12 @@ TEST_CASE("NCPlane") {
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
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.stylemask);
CHECK(0 == testcell.channels);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - 1));
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.stylemask);
CHECK(0 == testcell.channels);
// FIXME maybe check all cells?
CHECK(0 == notcurses_render(nc_));
@ -519,13 +519,13 @@ TEST_CASE("NCPlane") {
const char STR1[] = "Σιβυλλα τι θελεις; respondebat illa:";
const char STR2[] = "αποθανειν θελω";
const char STR3[] = "Война и мир"; // just thrown in to complicate things
ncplane_styles_set(n_, 0);
ncplane_styles_set(n_, NCSTYLE_NONE);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
REQUIRE(0 < ncplane_putstr(n_, STR1));
cell testcell = CELL_TRIVIAL_INITIALIZER;
ncplane_at_cursor_cell(n_, &testcell); // should be nothing at the cursor
CHECK(0 == testcell.gcluster);
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.stylemask);
CHECK(0 == testcell.channels);
int dimy, dimx;
ncplane_dim_yx(n_, &dimy, &dimx);
@ -540,12 +540,12 @@ TEST_CASE("NCPlane") {
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
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.stylemask);
CHECK(0 == testcell.channels);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - mbstowcs(nullptr, STR2, 0)));
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.stylemask);
CHECK(0 == testcell.channels);
// FIXME maybe check all cells?
CHECK(0 == notcurses_render(nc_));

View File

@ -91,7 +91,7 @@ TEST_CASE("Palette256") {
cell_release(n_, &c);
CHECK(0 == notcurses_render(nc_));
cell r = CELL_TRIVIAL_INITIALIZER;
CHECK(nullptr != notcurses_at_yx(nc_, 0, 0, &r.attrword, &r.channels));
CHECK(nullptr != notcurses_at_yx(nc_, 0, 0, &r.stylemask, &r.channels));
CHECK(cell_fg_palindex_p(&r));
CHECK(cell_bg_palindex_p(&r));
CHECK(CELL_ALPHA_OPAQUE == cell_fg_alpha(&r));

View File

@ -127,9 +127,9 @@ TEST_CASE("Rotate") {
free(rgbaret);
CHECK(0 == notcurses_render(nc_));
for(int x = 0 ; x < width ; ++x){
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* c = notcurses_at_yx(nc_, 0, x, &attrword, &channels);
char* c = notcurses_at_yx(nc_, 0, x, &stylemask, &channels);
REQUIRE(c);
CHECK(0 == strcmp(c, " "));
if(channels_fg(channels) & CELL_BG_RGB_MASK){
@ -178,9 +178,9 @@ TEST_CASE("Rotate") {
free(rgbaret);
CHECK(0 == notcurses_render(nc_));
for(int x = 0 ; x < width ; ++x){
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* c = notcurses_at_yx(nc_, 0, x, &attrword, &channels);
char* c = notcurses_at_yx(nc_, 0, x, &stylemask, &channels);
REQUIRE(c);
CHECK(0 == strcmp(c, " "));
if(channels_fg(channels) & CELL_BG_RGB_MASK){

View File

@ -140,9 +140,9 @@ TEST_CASE("Scrolling") {
CHECK(20 == x);
CHECK(0 == notcurses_render(nc_));
for(int i = 1 ; i < 21 ; ++i){
uint32_t attr;
uint16_t styles;
uint64_t channels;
char* egc = notcurses_at_yx(nc_, 2, i, &attr, &channels);
char* egc = notcurses_at_yx(nc_, 2, i, &styles, &channels);
REQUIRE(egc);
CHECK(onext[i - 1] == *egc);
free(egc);
@ -153,9 +153,9 @@ TEST_CASE("Scrolling") {
CHECK(10 == ncplane_putstr(n, next2));
CHECK(0 == notcurses_render(nc_));
for(int i = 1 ; i < 21 ; ++i){
uint32_t attr;
uint16_t styles;
uint64_t channels;
char* egc = notcurses_at_yx(nc_, 2, i, &attr, &channels);
char* egc = notcurses_at_yx(nc_, 2, i, &styles, &channels);
REQUIRE(egc);
if(i < 11){
CHECK(next2[i - 1] == *egc);
@ -186,9 +186,9 @@ TEST_CASE("Scrolling") {
CHECK(10 == ncplane_putstr(n, onext));
CHECK(0 == notcurses_render(nc_));
for(int i = 1 ; i < 21 ; ++i){
uint32_t attr;
uint16_t styles;
uint64_t channels;
char* egc = notcurses_at_yx(nc_, 2, i, &attr, &channels);
char* egc = notcurses_at_yx(nc_, 2, i, &styles, &channels);
REQUIRE(egc);
if(i < 11){
CHECK(onext[i - 1] == *egc);

View File

@ -191,9 +191,9 @@ TEST_CASE("Visual") {
CHECK(0 == notcurses_render(nc_));
for(int y = 0 ; y < DIMY / 2 ; ++y){
for(int x = 0 ; x < DIMX ; ++x){
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* egc = notcurses_at_yx(nc_, y, x, &attrword, &channels);
char* egc = notcurses_at_yx(nc_, y, x, &stylemask, &channels);
REQUIRE(nullptr != egc);
CHECK((rgba[y * 2 * DIMX + x] & 0xffffff) == channels_bg(channels));
CHECK((rgba[(y * 2 + 1) * DIMX + x] & 0xffffff) == channels_fg(channels));
@ -231,9 +231,9 @@ TEST_CASE("Visual") {
CHECK(0 == notcurses_render(nc_));
for(int y = 0 ; y < DIMY / 2 ; ++y){
for(int x = 0 ; x < DIMX / 2 ; ++x){
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* egc = notcurses_at_yx(nc_, y, x, &attrword, &channels);
char* egc = notcurses_at_yx(nc_, y, x, &stylemask, &channels);
REQUIRE(nullptr != egc);
CHECK((rgba[(y * 2 * DIMX) + (x * 2)] & 0xffffff) == channels_fg(channels));
CHECK((rgba[(y * 2 + 1) * DIMX + (x * 2) + 1] & 0xffffff) == channels_fg(channels));
@ -289,9 +289,9 @@ TEST_CASE("Visual") {
CHECK(0 == notcurses_render(nc_));
for(int y = 0 ; y < DIMY / 2 ; ++y){
for(int x = 0 ; x < DIMX / 2 ; ++x){
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* egc = notcurses_at_yx(nc_, y, x, &attrword, &channels);
char* egc = notcurses_at_yx(nc_, y, x, &stylemask, &channels);
REQUIRE(nullptr != egc);
/* FIXME need to match
[] 00000000 00000000

View File

@ -75,7 +75,7 @@ TEST_CASE("Wide") {
cell testcell = CELL_TRIVIAL_INITIALIZER;
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell));
CHECK(!strcmp(cell_extended_gcluster(n_, &tcell), cell_extended_gcluster(n_, &testcell)));
CHECK(0 == testcell.attrword);
CHECK(0 == testcell.stylemask);
wchar_t w;
REQUIRE(0 < mbtowc(&w, cell_extended_gcluster(n_, &tcell), MB_CUR_MAX));
if(wcwidth(w) == 2){
@ -216,14 +216,14 @@ TEST_CASE("Wide") {
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);
char* egc = notcurses_at_yx(nc_, 1, 0, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(!strcmp(egc, ""));
free(egc);
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);
egc = notcurses_at_yx(nc_, 1, 3, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(!strcmp(egc, ""));
free(egc);
@ -244,15 +244,15 @@ TEST_CASE("Wide") {
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);
notcurses_at_yx(nc_, 0, 0, &c.stylemask, &c.channels);
CHECK(0 != (c.channels & 0x8000000080000000ull));
notcurses_at_yx(nc_, 0, 1, &c.attrword, &c.channels);
notcurses_at_yx(nc_, 0, 1, &c.stylemask, &c.channels);
CHECK(0 != (c.channels & 0x8000000080000000ull));
notcurses_at_yx(nc_, 0, 2, &c.attrword, &c.channels);
notcurses_at_yx(nc_, 0, 2, &c.stylemask, &c.channels);
CHECK(0 != (c.channels & 0x8000000080000000ull));
notcurses_at_yx(nc_, 0, 3, &c.attrword, &c.channels);
notcurses_at_yx(nc_, 0, 3, &c.stylemask, &c.channels);
CHECK(0 != (c.channels & 0x8000000080000000ull));
notcurses_at_yx(nc_, 0, 4, &c.attrword, &c.channels);
notcurses_at_yx(nc_, 0, 4, &c.stylemask, &c.channels);
CHECK(!(c.channels & 0x8000000080000000ull));
}
@ -281,7 +281,7 @@ TEST_CASE("Wide") {
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 0, &c));
CHECK(!strcmp("\xe5\x85\xa8", cell_extended_gcluster(n_, &c)));
CHECK(cell_double_wide_p(&c));
egc = notcurses_at_yx(nc_, 0, 0, &c.attrword, &c.channels);
egc = notcurses_at_yx(nc_, 0, 0, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(!strcmp("\xe5\x85\xa8", egc));
CHECK(cell_double_wide_p(&c));
@ -291,7 +291,7 @@ TEST_CASE("Wide") {
REQUIRE(0 == ncplane_at_yx_cell(n_, 0, 1, &c));
CHECK(!strcmp("", cell_extended_gcluster(n_, &c)));
CHECK(cell_double_wide_p(&c));
egc = notcurses_at_yx(nc_, 0, 1, &c.attrword, &c.channels);
egc = notcurses_at_yx(nc_, 0, 1, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(!strcmp("", egc));
CHECK(cell_double_wide_p(&c));
@ -302,7 +302,7 @@ TEST_CASE("Wide") {
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 2, &c));
CHECK(!strcmp("\xe5\xbd\xa2", cell_extended_gcluster(n_, &c)));
CHECK(cell_double_wide_p(&c));
egc = notcurses_at_yx(nc_, 0, 2, &c.attrword, &c.channels);
egc = notcurses_at_yx(nc_, 0, 2, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(!strcmp("\xe5\xbd\xa2", egc));
CHECK(cell_double_wide_p(&c));
@ -312,7 +312,7 @@ TEST_CASE("Wide") {
CHECK(0 == ncplane_at_yx_cell(n_, 0, 3, &c));
CHECK(!strcmp("", cell_extended_gcluster(n_, &c)));
CHECK(cell_double_wide_p(&c));
egc = notcurses_at_yx(nc_, 0, 3, &c.attrword, &c.channels);
egc = notcurses_at_yx(nc_, 0, 3, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(!strcmp("", egc));
CHECK(cell_double_wide_p(&c));
@ -325,26 +325,26 @@ TEST_CASE("Wide") {
CHECK(!notcurses_render(nc_));
// should be nothing, having been stomped
egc = notcurses_at_yx(nc_, 0, 0, &c.attrword, &c.channels);
egc = notcurses_at_yx(nc_, 0, 0, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(0 == strcmp(" ", egc));
free(egc);
cell_init(&c);
// should be character from higher plane
egc = notcurses_at_yx(nc_, 0, 1, &c.attrword, &c.channels);
egc = notcurses_at_yx(nc_, 0, 1, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(0 == strcmp("A", egc));
free(egc);
cell_init(&c);
egc = notcurses_at_yx(nc_, 0, 2, &c.attrword, &c.channels);
egc = notcurses_at_yx(nc_, 0, 2, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(0 == strcmp("B", egc));
free(egc);
cell_init(&c);
// should be nothing, having been stomped
egc = notcurses_at_yx(nc_, 0, 3, &c.attrword, &c.channels);
egc = notcurses_at_yx(nc_, 0, 3, &c.stylemask, &c.channels);
REQUIRE(egc);
CHECK(0 == strcmp("", egc));
free(egc);
@ -368,13 +368,13 @@ TEST_CASE("Wide") {
channels_set_bg_rgb(&channels, 0x80, 0xf0, 0x10);
CHECK(1 == ncplane_set_base(p, " ", 0, channels));
CHECK(0 == notcurses_render(nc_));
uint32_t attrword;
uint16_t stylemask;
uint64_t chanleft, chanright;
char* egc = notcurses_at_yx(nc_, 1, 1, &attrword, &chanleft);
char* egc = notcurses_at_yx(nc_, 1, 1, &stylemask, &chanleft);
REQUIRE(nullptr != egc);
CHECK(0 == strcmp(" ", egc));
free(egc);
egc = notcurses_at_yx(nc_, 1, 2, &attrword, &chanright);
egc = notcurses_at_yx(nc_, 1, 2, &stylemask, &chanright);
REQUIRE(nullptr != egc);
CHECK(0 == strcmp(" ", egc));
free(egc);
@ -401,165 +401,165 @@ TEST_CASE("Wide") {
CHECK(4 == ncplane_putstr(topp, "abcd"));
CHECK(12 == ncplane_putstr(n_, "六六六六"));
CHECK(0 == notcurses_render(nc_));
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* egc;
uint64_t widechans = ncplane_channels(n_) | CELL_WIDEASIAN_MASK;
uint64_t narchans = ncplane_channels(topp);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
CHECK(widechans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
CHECK(widechans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "b"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "c"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "d"));
CHECK(narchans == channels);
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 3));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
CHECK(widechans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, " "));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "b"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "c"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "d"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 2));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
CHECK(widechans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "b"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "c"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "d"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
CHECK(widechans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 1));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, " "));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "b"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "c"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "d"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
CHECK(widechans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 0));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "b"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "c"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "d"));
CHECK(narchans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
CHECK(widechans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
CHECK(widechans == channels);
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
ncplane_destroy(topp);
@ -576,135 +576,135 @@ TEST_CASE("Wide") {
CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
CHECK(12 == ncplane_putstr(n_, "六六六六"));
CHECK(0 == notcurses_render(nc_));
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* egc;
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 3));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, " "));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 2));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 1));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, " "));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 0));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
ncplane_destroy(topp);
@ -720,142 +720,142 @@ TEST_CASE("Wide") {
CHECK(6 == ncplane_putstr(topp, "次次"));
CHECK(8 == ncplane_putstr(n_, "abcdefgh"));
CHECK(0 == notcurses_render(nc_));
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
char* egc;
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "b"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "c"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "d"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 3));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "b"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "c"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "h"));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 2));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "b"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "g"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "h"));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 1));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "a"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "f"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "g"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "h"));
free(egc);
CHECK(0 == ncplane_move_yx(topp, 0, 0));
CHECK(0 == notcurses_render(nc_));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 1, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 2, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 3, &stylemask, &channels)));
CHECK(0 == strcmp(egc, ""));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 4, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "e"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 5, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "f"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 6, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "g"));
free(egc);
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &attrword, &channels)));
REQUIRE((egc = notcurses_at_yx(nc_, 0, 7, &stylemask, &channels)));
CHECK(0 == strcmp(egc, "h"));
free(egc);
ncplane_destroy(topp);
}
// Verify that we can use long (4-byte) UTF-encoded characters together with
// styles without a problem (since the attrword holds both styling bits and
// styles without a problem (since the stylemask holds both styling bits and
// the NUL backstop for long inlined UTF8).
// U+1F90C PINCHED FINGERS → UTF8(f0 9f a4 8c)
SUBCASE("ItalicEmoji") {
@ -867,14 +867,14 @@ TEST_CASE("Wide") {
CHECK(0 == strcmp("\U0001F90C", cell_extended_gcluster(n_, &c)));
CHECK(0 < ncplane_putc_yx(n_, 0, 0, &c));
CHECK(0 == notcurses_render(nc_));
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
auto egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels);
auto egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels);
REQUIRE(nullptr != egc);
CHECK(4 == strlen(egc));
CHECK(0 == strcmp("\U0001F90C", egc));
free(egc);
CHECK(NCSTYLE_ITALIC == attrword);
CHECK(NCSTYLE_ITALIC == stylemask);
}
SUBCASE("StyleMaxEmoji") {
@ -886,14 +886,14 @@ TEST_CASE("Wide") {
CHECK(0 == strcmp("\U0001F90C", cell_extended_gcluster(n_, &c)));
CHECK(0 < ncplane_putc_yx(n_, 0, 0, &c));
CHECK(0 == notcurses_render(nc_));
uint32_t attrword;
uint16_t stylemask;
uint64_t channels;
auto egc = notcurses_at_yx(nc_, 0, 0, &attrword, &channels);
auto egc = notcurses_at_yx(nc_, 0, 0, &stylemask, &channels);
REQUIRE(nullptr != egc);
CHECK(4 == strlen(egc));
CHECK(0 == strcmp("\U0001F90C", egc));
free(egc);
CHECK(NCSTYLE_MASK == attrword);
CHECK(NCSTYLE_MASK == stylemask);
}
CHECK(0 == notcurses_stop(nc_));