mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-02 09:40:15 +00:00
* improved alpha macros * demo: use new alpha macros * add ncplane_set_*_alpha() * explicitly set fg for uniblock * outro: background is a space #139 * distinct alpha channels for fg/bg #139 * rename 'background' cell to 'default' #142 * doc palette fades
This commit is contained in:
parent
582017a16a
commit
8bd8055f72
207
README.md
207
README.md
@ -63,7 +63,7 @@ Why use this non-standard library?
|
||||
* Thread safety, and efficient use in parallel programs, has been a design
|
||||
consideration from the beginning.
|
||||
|
||||
* A svelter design than that codified by X/Open.
|
||||
* A svelter design than that codified by X/Open:
|
||||
* Exported identifiers are prefixed to avoid common namespace collisions.
|
||||
* The library object exports a minimal set of symbols. Where reasonable,
|
||||
`static inline` header-only code is used. This facilitates compiler
|
||||
@ -202,6 +202,13 @@ Utility functions operating on the toplevel `notcurses` object include:
|
||||
// following a resize operation, but the cursor might have changed position.
|
||||
int notcurses_resize(struct notcurses* n, int* RESTRICT y, int* RESTRICT x);
|
||||
|
||||
// Return our current idea of the terminal dimensions in rows and cols.
|
||||
static inline void
|
||||
notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows,
|
||||
int* RESTRICT cols){
|
||||
ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
|
||||
}
|
||||
|
||||
// Refresh the physical screen to match what was last rendered (i.e., without
|
||||
// reflecting any changes since the last call to notcurses_render()). This is
|
||||
// primarily useful if the screen is externally corrupted.
|
||||
@ -376,14 +383,6 @@ int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny,
|
||||
// the standard plane.
|
||||
int ncplane_destroy(struct ncplane* ncp);
|
||||
|
||||
// Set the ncplane's background cell to this cell. It will be rendered anywhere
|
||||
// that the ncplane's gcluster is 0. The default background is all zeroes.
|
||||
// Erasing the ncplane does not eliminate the background.
|
||||
int ncplane_set_background(struct ncplane* ncp, const cell* c);
|
||||
|
||||
// Extract the ncplane's background cell into 'c'.
|
||||
int ncplane_background(struct ncplane* ncp, cell* c);
|
||||
|
||||
// Move this plane relative to the standard plane. It is an error to attempt to
|
||||
// move the standard plane.
|
||||
int ncplane_move_yx(struct ncplane* n, int y, int x);
|
||||
@ -391,6 +390,52 @@ int ncplane_move_yx(struct ncplane* n, int y, int x);
|
||||
// Get the origin of this plane relative to the standard plane.
|
||||
void ncplane_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x);
|
||||
|
||||
// Returns the dimensions of this ncplane.
|
||||
void ncplane_dim_yx(const struct ncplane* n, int* RESTRICT rows,
|
||||
int* RESTRICT cols);
|
||||
|
||||
// Erase every cell in the ncplane, resetting all attributes to normal, all
|
||||
// colors to the default color, and all cells to undrawn. All cells associated
|
||||
// with this ncplane are invalidated, and must not be used after the call,
|
||||
// excluding the default cell.
|
||||
void ncplane_erase(struct ncplane* n);
|
||||
|
||||
// Set the specified style bits for the ncplane 'n', whether they're actively
|
||||
// supported or not.
|
||||
void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
|
||||
|
||||
// Add the specified styles to the ncplane's existing spec.
|
||||
void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
|
||||
|
||||
// Remove the specified styles from the ncplane's existing spec.
|
||||
void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
|
||||
|
||||
// Return the current styling for this ncplane.
|
||||
unsigned ncplane_styles(const struct ncplane* n);
|
||||
|
||||
```
|
||||
|
||||
If a given cell's glyph is zero, or its foreground channel is fully transparent,
|
||||
it is considered to have no foreground. A _default_ cell can be chosen for the
|
||||
`ncplane`, to be consulted in this case. If the default cell's glyph is likewise
|
||||
zero (or its foreground channel fully transparent), the plane's foreground is
|
||||
not rendered. Note that the default cell, like every other cell, has its own
|
||||
foreground and background channels.
|
||||
|
||||
```c
|
||||
// Set the ncplane's default cell to this cell. If defined, it will be rendered
|
||||
// anywhere that the ncplane's gcluster is 0. Erasing the ncplane does not
|
||||
// reset the default cell; this function must instead be called with a zero c.
|
||||
int ncplane_set_default(struct ncplane* ncp, const cell* c);
|
||||
|
||||
// Extract the ncplane's default cell into 'c'.
|
||||
int ncplane_default(struct ncplane* ncp, cell* c);
|
||||
```
|
||||
|
||||
`ncplane`s are completely ordered along an imaginary z-axis. Newly-created
|
||||
`ncplane`s are on the top of the stack. They can be freely reordered.
|
||||
|
||||
```c
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it at the top or bottom.
|
||||
int ncplane_move_top(struct ncplane* n);
|
||||
int ncplane_move_bottom(struct ncplane* n);
|
||||
@ -400,7 +445,13 @@ int ncplane_move_below(struct ncplane* RESTRICT n, struct ncplane* RESTRICT belo
|
||||
|
||||
// Splice ncplane 'n' out of the z-buffer, and reinsert it above 'above'.
|
||||
int ncplane_move_above(struct ncplane* RESTRICT n, struct ncplane* RESTRICT above);
|
||||
```
|
||||
|
||||
Each plane holds a user pointer which can be retrieved and set (or ignored). In
|
||||
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);
|
||||
@ -411,18 +462,14 @@ int ncplane_at_cursor(struct ncplane* n, cell* c);
|
||||
void* ncplane_set_userptr(struct ncplane* n, void* opaque);
|
||||
void* ncplane_userptr(struct ncplane* n);
|
||||
const void* ncplane_userptr_const(const struct ncplane* n);
|
||||
```
|
||||
|
||||
// Returns the dimensions of this ncplane.
|
||||
void ncplane_dim_yx(const struct ncplane* n, int* RESTRICT rows,
|
||||
int* RESTRICT cols);
|
||||
|
||||
// Return our current idea of the terminal dimensions in rows and cols.
|
||||
static inline void
|
||||
notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows,
|
||||
int* RESTRICT cols){
|
||||
ncplane_dim_yx(notcurses_stdplane_const(n), rows, cols);
|
||||
}
|
||||
All output is to `ncplane`s. There is no cost in moving the cursor around the
|
||||
virtual framebuffer. Output that's never rendered still has some memory transfer
|
||||
cost as the virtual framebuffer is prepared, but new data overwrites it in
|
||||
memory.
|
||||
|
||||
```c
|
||||
// Move the cursor to the specified position (the cursor needn't be visible).
|
||||
// Returns -1 on error, including negative parameters, or ones exceeding the
|
||||
// plane's dimensions.
|
||||
@ -569,8 +616,13 @@ ncplane_vprintf_yx(struct ncplane* n, int y, int x, const char* format, va_list
|
||||
}
|
||||
return ncplane_vprintf(n, format, ap);
|
||||
}
|
||||
```
|
||||
|
||||
Lines and boxes can be drawn, interpolating their colors between their two
|
||||
endpoints. For a line of a single color, be sure to specify the same channels
|
||||
on both sides. Boxes allow fairly detailed specification of how they're drawn.
|
||||
|
||||
```c
|
||||
// Draw horizontal or vertical lines using the specified cell, starting at the
|
||||
// current cursor position. The cursor will end at the cell following the last
|
||||
// cell output (even, perhaps counter-intuitively, when drawing vertical
|
||||
@ -696,25 +748,11 @@ ncplane_double_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels,
|
||||
return ncplane_double_box(n, attr, channels, y + ylen - 1,
|
||||
x + xlen - 1, ctlword);
|
||||
}
|
||||
```
|
||||
|
||||
// Erase every cell in the ncplane, resetting all attributes to normal, all
|
||||
// colors to the default color, and all cells to undrawn. All cells associated
|
||||
// with this ncplane are invalidated, and must not be used after the call.
|
||||
void ncplane_erase(struct ncplane* n);
|
||||
|
||||
// Set the specified style bits for the ncplane 'n', whether they're actively
|
||||
// supported or not.
|
||||
void ncplane_styles_set(struct ncplane* n, unsigned stylebits);
|
||||
|
||||
// Add the specified styles to the ncplane's existing spec.
|
||||
void ncplane_styles_on(struct ncplane* n, unsigned stylebits);
|
||||
|
||||
// Remove the specified styles from the ncplane's existing spec.
|
||||
void ncplane_styles_off(struct ncplane* n, unsigned stylebits);
|
||||
|
||||
// Return the current styling for this ncplane.
|
||||
unsigned ncplane_styles(const struct ncplane* n);
|
||||
My 14 year-old self would never forgive me if we didn't have sweet palette fades.
|
||||
|
||||
```c
|
||||
// Fade the ncplane out over the provided time, calling the specified function
|
||||
// when done. Requires a terminal which supports direct color, or at least
|
||||
// palette modification (if the terminal uses a palette, our ability to fade
|
||||
@ -791,6 +829,10 @@ ncplane_get_bg_alpha(const struct ncplane* nc){
|
||||
return channels_get_bg_alpha(ncplane_get_channels(nc));
|
||||
}
|
||||
|
||||
// Set the alpha parameters for ncplane 'n'.
|
||||
int ncplane_set_fg_alpha(struct ncplane* n, int alpha);
|
||||
int ncplane_set_bg_alpha(struct ncplane* n, int alpha);
|
||||
|
||||
// Extract 24 bits of foreground RGB from 'n', split into subcomponents.
|
||||
static inline unsigned
|
||||
ncplane_get_fg_rgb(const struct ncplane* n, unsigned* r, unsigned* g, unsigned*
|
||||
@ -873,6 +915,16 @@ typedef struct cell {
|
||||
// "not default color" bit is set, any color you load will be ignored.
|
||||
uint64_t channels; // + 8b == 16b
|
||||
} cell;
|
||||
|
||||
#define CELL_WIDEASIAN_MASK 0x8000000080000000ull
|
||||
#define CELL_FGDEFAULT_MASK 0x4000000000000000ull
|
||||
#define CELL_FG_MASK 0x00ffffff00000000ull
|
||||
#define CELL_BGDEFAULT_MASK 0x0000000040000000ull
|
||||
#define CELL_BG_MASK 0x0000000000ffffffull
|
||||
#define CELL_ALPHA_MASK 0x0000000030000000ull
|
||||
#define CELL_ALPHA_SHIFT 28u
|
||||
#define CELL_ALPHA_TRANS 3
|
||||
#define CELL_ALPHA_OPAQUE 0
|
||||
```
|
||||
|
||||
`cell`s must be initialized with `CELL_TRIVIAL_INITIALIZER` or `cell_init()`
|
||||
@ -1104,6 +1156,27 @@ cell_set_bg_rgb(cell* cl, int r, int g, int b){
|
||||
return channels_set_bg_rgb(&cl->channels, r, g, b);
|
||||
}
|
||||
|
||||
// Same, but with rgb assembled into a channel (i.e. lower 24 bits).
|
||||
static inline int
|
||||
cell_set_fg(cell* c, uint32_t channel){
|
||||
return channels_set_fg(&c->channels, channel);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cell_set_bg(cell* c, uint32_t channel){
|
||||
return channels_set_bg(&c->channels, channel);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Is the foreground using the "default foreground color"?
|
||||
static inline bool
|
||||
cell_fg_default_p(const cell* cl){
|
||||
@ -1117,6 +1190,19 @@ static inline bool
|
||||
cell_bg_default_p(const cell* cl){
|
||||
return channels_bg_default_p(cl->channels);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Multimedia
|
||||
@ -1217,19 +1303,29 @@ channel_set_rgb(unsigned* channel, int r, int g, int b){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Same, but provide an assembled, packed 24 bits of rgb.
|
||||
static inline int
|
||||
channel_set(unsigned* channel, unsigned rgb){
|
||||
if(rgb > 0xffffffu){
|
||||
return -1;
|
||||
}
|
||||
*channel = (*channel & ~CELL_BG_MASK) | CELL_BGDEFAULT_MASK | rgb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract the 2-bit alpha component from a 32-bit channel.
|
||||
static inline unsigned
|
||||
channel_get_alpha(unsigned channel){
|
||||
return (channel & CELL_BGALPHA_MASK) >> 28u;
|
||||
return (channel & CELL_ALPHA_MASK) >> CELL_ALPHA_SHIFT;
|
||||
}
|
||||
|
||||
// Set the 2-bit alpha component of the 32-bit channel.
|
||||
static inline int
|
||||
channel_set_alpha(unsigned* channel, int alpha){
|
||||
if(alpha < 0 || alpha > 3){
|
||||
if(alpha < CELL_ALPHA_OPAQUE || alpha > CELL_ALPHA_TRANS){
|
||||
return -1;
|
||||
}
|
||||
*channel = (alpha << 28u) | (*channel & ~CELL_BGALPHA_MASK);
|
||||
*channel = (alpha << CELL_ALPHA_SHIFT) | (*channel & ~CELL_ALPHA_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1317,6 +1413,27 @@ channels_set_bg_rgb(uint64_t* channels, int r, int g, int b){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Same, but set an assembled 24 bits of rgb at once.
|
||||
static inline int
|
||||
channels_set_fg(uint64_t* channels, unsigned rgb){
|
||||
unsigned channel = channels_get_fchannel(*channels);
|
||||
if(channel_set(&channel, rgb) < 0){
|
||||
return -1;
|
||||
}
|
||||
*channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
channels_set_bg(uint64_t* channels, unsigned rgb){
|
||||
unsigned channel = channels_get_bchannel(*channels);
|
||||
if(channel_set(&channel, rgb) < 0){
|
||||
return -1;
|
||||
}
|
||||
*channels = (*channels & 0xffffffff00000000llu) | channel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the 2-bit alpha component of the foreground channel.
|
||||
static inline int
|
||||
channels_set_fg_alpha(uint64_t* channels, int alpha){
|
||||
@ -1375,6 +1492,13 @@ channels_set_bg_default(uint64_t* channels){
|
||||
|
||||
### Perf
|
||||
|
||||
Rendering performance can be very roughly categorized as inversely proportional
|
||||
to the product of:
|
||||
* color changes across the rendered screen,
|
||||
* planar depth before an opaque glyph and background are locked in,
|
||||
* number of UTF-8 bytes composing the rendered glyphs, and
|
||||
* screen geometry
|
||||
|
||||
notcurses tracks statistics across its operation, and a snapshot can be
|
||||
acquired using the `notcurses_stats()` function. This function cannot fail.
|
||||
|
||||
@ -1414,11 +1538,6 @@ cursor is updated based on the width of the output. Along the way, notcurses
|
||||
attempts to minimize total amount of data written by eliding unnecessary color
|
||||
and style specifications, and moving the cursor over large unchanged areas.
|
||||
|
||||
The worst case input frame (in terms of output size) is one whose colors change
|
||||
from coordinate to coordinate, uses multiple combining characters within each
|
||||
grapheme cluster, and has a large geometry. Peculiarities of the terminal
|
||||
make it impossible to comment more meaningfully regarding delay.
|
||||
|
||||
Using the "default color" as only one of the foreground or background requires
|
||||
emitting the `op` escape followed by the appropriate escape for changing the
|
||||
fore- or background (since `op` changes both at once). If you're printing full
|
||||
|
@ -311,13 +311,13 @@ API int ncplane_resize(struct ncplane* n, int keepy, int keepx, int keepleny,
|
||||
// the standard plane.
|
||||
API int ncplane_destroy(struct ncplane* ncp);
|
||||
|
||||
// Set the ncplane's background cell to this cell. It will be rendered anywhere
|
||||
// that the ncplane's gcluster is 0. The default background is all zeroes.
|
||||
// Erasing the ncplane does not eliminate the background.
|
||||
API int ncplane_set_background(struct ncplane* ncp, const cell* c);
|
||||
// Set the ncplane's default cell to this cell. If defined, it will be rendered
|
||||
// anywhere that the ncplane's gcluster is 0. Erasing the ncplane does not
|
||||
// reset the default cell; this function must instead be called with a zero c.
|
||||
API int ncplane_set_default(struct ncplane* ncp, const cell* c);
|
||||
|
||||
// Extract the ncplane's background cell into 'c'.
|
||||
API int ncplane_background(struct ncplane* ncp, cell* c);
|
||||
// Extract the ncplane's default cell into 'c'.
|
||||
API int ncplane_default(struct ncplane* ncp, cell* c);
|
||||
|
||||
// Move this plane relative to the standard plane. It is an error to attempt to
|
||||
// move the standard plane.
|
||||
@ -588,16 +588,19 @@ ncplane_box_sized(struct ncplane* n, const cell* ul, const cell* ur,
|
||||
|
||||
// Erase every cell in the ncplane, resetting all attributes to normal, all
|
||||
// colors to the default color, and all cells to undrawn. All cells associated
|
||||
// with this ncplane is invalidated, and must not be used after the call.
|
||||
// with this ncplane is invalidated, and must not be used after the call,
|
||||
// excluding the default cell.
|
||||
API void ncplane_erase(struct ncplane* n);
|
||||
|
||||
#define CELL_WIDEASIAN_MASK 0x8000000000000000ull
|
||||
#define CELL_WIDEASIAN_MASK 0x8000000080000000ull
|
||||
#define CELL_FGDEFAULT_MASK 0x4000000000000000ull
|
||||
#define CELL_FGALPHA_MASK 0x3000000000000000ull
|
||||
#define CELL_FG_MASK 0x00ffffff00000000ull
|
||||
#define CELL_BGDEFAULT_MASK 0x0000000040000000ull
|
||||
#define CELL_BGALPHA_MASK 0x0000000030000000ull
|
||||
#define CELL_BG_MASK 0x0000000000ffffffull
|
||||
#define CELL_ALPHA_MASK 0x0000000030000000ull
|
||||
#define CELL_ALPHA_SHIFT 28u
|
||||
#define CELL_ALPHA_TRANS 3
|
||||
#define CELL_ALPHA_OPAQUE 0
|
||||
|
||||
// These lowest-level functions manipulate a 64-bit channel encoding directly.
|
||||
// Users will typically manipulate ncplane and cell channels through those APIs,
|
||||
@ -647,19 +650,29 @@ channel_set_rgb(unsigned* channel, int r, int g, int b){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Same, but provide an assembled, packed 24 bits of rgb.
|
||||
static inline int
|
||||
channel_set(unsigned* channel, unsigned rgb){
|
||||
if(rgb > 0xffffffu){
|
||||
return -1;
|
||||
}
|
||||
*channel = (*channel & ~CELL_BG_MASK) | CELL_BGDEFAULT_MASK | rgb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract the 2-bit alpha component from a 32-bit channel.
|
||||
static inline unsigned
|
||||
channel_get_alpha(unsigned channel){
|
||||
return (channel & CELL_BGALPHA_MASK) >> 28u;
|
||||
return (channel & CELL_ALPHA_MASK) >> CELL_ALPHA_SHIFT;
|
||||
}
|
||||
|
||||
// Set the 2-bit alpha component of the 32-bit channel.
|
||||
static inline int
|
||||
channel_set_alpha(unsigned* channel, int alpha){
|
||||
if(alpha < 0 || alpha > 3){
|
||||
if(alpha < CELL_ALPHA_OPAQUE || alpha > CELL_ALPHA_TRANS){
|
||||
return -1;
|
||||
}
|
||||
*channel = (alpha << 28u) | (*channel & ~CELL_BGALPHA_MASK);
|
||||
*channel = (alpha << CELL_ALPHA_SHIFT) | (*channel & ~CELL_ALPHA_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -747,6 +760,27 @@ channels_set_bg_rgb(uint64_t* channels, int r, int g, int b){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Same, but set an assembled 24 bits of rgb at once.
|
||||
static inline int
|
||||
channels_set_fg(uint64_t* channels, unsigned rgb){
|
||||
unsigned channel = channels_get_fchannel(*channels);
|
||||
if(channel_set(&channel, rgb) < 0){
|
||||
return -1;
|
||||
}
|
||||
*channels = ((uint64_t)channel << 32llu) | (*channels & 0xffffffffllu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
channels_set_bg(uint64_t* channels, unsigned rgb){
|
||||
unsigned channel = channels_get_bchannel(*channels);
|
||||
if(channel_set(&channel, rgb) < 0){
|
||||
return -1;
|
||||
}
|
||||
*channels = (*channels & 0xffffffff00000000llu) | channel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the 2-bit alpha component of the foreground channel.
|
||||
static inline int
|
||||
channels_set_fg_alpha(uint64_t* channels, int alpha){
|
||||
@ -863,6 +897,17 @@ cell_set_bg_rgb(cell* cl, int r, int g, int b){
|
||||
return channels_set_bg_rgb(&cl->channels, r, g, b);
|
||||
}
|
||||
|
||||
// Same, but with rgb assembled into a channel (i.e. lower 24 bits).
|
||||
static inline int
|
||||
cell_set_fg(cell* c, uint32_t channel){
|
||||
return channels_set_fg(&c->channels, channel);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cell_set_bg(cell* c, uint32_t channel){
|
||||
return channels_set_bg(&c->channels, channel);
|
||||
}
|
||||
|
||||
// Is the foreground using the "default foreground color"?
|
||||
static inline bool
|
||||
cell_fg_default_p(const cell* cl){
|
||||
@ -938,7 +983,7 @@ ncplane_get_bg_rgb(const struct ncplane* n, unsigned* r, unsigned* g, unsigned*
|
||||
API int ncplane_set_fg_rgb(struct ncplane* n, int r, int g, int b);
|
||||
API int ncplane_set_bg_rgb(struct ncplane* n, int r, int g, int b);
|
||||
|
||||
// Same, but with rgb assembled into a channel (i.e. lower 32 bits).
|
||||
// Same, but with rgb assembled into a channel (i.e. lower 24 bits).
|
||||
API void ncplane_set_fg(struct ncplane* n, uint32_t channel);
|
||||
API void ncplane_set_bg(struct ncplane* n, uint32_t channel);
|
||||
|
||||
@ -946,6 +991,10 @@ API void ncplane_set_bg(struct ncplane* n, uint32_t channel);
|
||||
API void ncplane_set_fg_default(struct ncplane* n);
|
||||
API void ncplane_set_bg_default(struct ncplane* n);
|
||||
|
||||
// Set the alpha parameters for ncplane 'n'.
|
||||
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);
|
||||
@ -1043,13 +1092,13 @@ cell_styles_off(cell* c, unsigned stylebits){
|
||||
c->attrword &= ~((stylebits & 0xffff) << CELL_STYLE_SHIFT);
|
||||
}
|
||||
|
||||
// use the default color for the foreground
|
||||
// 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
|
||||
// Use the default color for the background.
|
||||
static inline void
|
||||
cell_set_bg_default(cell* c){
|
||||
channels_set_bg_default(&c->channels);
|
||||
|
@ -107,8 +107,8 @@ static const char luigi3[] = "0000001111100000"
|
||||
static int
|
||||
draw_luigi(struct ncplane* n, const char* sprite){
|
||||
cell bgc = CELL_TRIVIAL_INITIALIZER;
|
||||
cell_set_bg_alpha(&bgc, 3);
|
||||
ncplane_set_background(n, &bgc);
|
||||
cell_set_bg_alpha(&bgc, CELL_ALPHA_TRANS);
|
||||
ncplane_set_default(n, &bgc);
|
||||
cell_release(n, &bgc);
|
||||
size_t s;
|
||||
int sbytes;
|
||||
|
@ -19,14 +19,15 @@ outro_message(struct notcurses* nc, int* rows, int* cols){
|
||||
if(on == NULL){
|
||||
return NULL;
|
||||
}
|
||||
cell bgcell = CELL_TRIVIAL_INITIALIZER;
|
||||
cell bgcell = CELL_SIMPLE_INITIALIZER(' ');
|
||||
channels_set_bg_rgb(&bgcell.channels, 0x58, 0x36, 0x58);
|
||||
ncplane_set_background(on, &bgcell);
|
||||
if(ncplane_set_default(on, &bgcell) < 0){
|
||||
return NULL;
|
||||
}
|
||||
ncplane_dim_yx(on, rows, cols);
|
||||
int ybase = 0;
|
||||
// bevel the upper corners
|
||||
uint64_t channel = 0;
|
||||
if(channels_set_bg_alpha(&channel, 3)){
|
||||
if(ncplane_set_bg_alpha(on, CELL_ALPHA_TRANS)){
|
||||
return NULL;
|
||||
}
|
||||
if(ncplane_cursor_move_yx(on, ybase, 0)){
|
||||
@ -60,6 +61,9 @@ outro_message(struct notcurses* nc, int* rows, int* cols){
|
||||
if(ncplane_set_bg_rgb(on, 0, 180, 180)){
|
||||
return NULL;
|
||||
}
|
||||
if(ncplane_set_bg_alpha(on, CELL_ALPHA_OPAQUE)){ // FIXME use intermediate
|
||||
return NULL;
|
||||
}
|
||||
if(ncplane_putstr_aligned(on, ++ybase, str0, NCALIGN_CENTER) < 0){
|
||||
return NULL;
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ panelreel_demo_core(struct notcurses* nc, int efd, tabletctx** tctxs){
|
||||
cell_set_fg_rgb(&popts.tabletattr, 19, 161, 14);
|
||||
cell_set_fg_rgb(&popts.borderattr, 136, 23, 152);
|
||||
cell_set_bg_rgb(&popts.borderattr, 0, 0, 0);
|
||||
if(channels_set_bg_alpha(&popts.bgchannel, 3)){
|
||||
if(channels_set_bg_alpha(&popts.bgchannel, CELL_ALPHA_TRANS)){
|
||||
return NULL;
|
||||
}
|
||||
struct ncplane* w = notcurses_stdplane(nc);
|
||||
|
@ -119,7 +119,7 @@ fill_chunk(struct ncplane* n, int idx){
|
||||
cell_init(&style);
|
||||
cell_set_fg_rgb(&style, r, g, b);
|
||||
cell_prime(n, &style, "█", 0, channels);
|
||||
ncplane_set_background(n, &style);
|
||||
ncplane_set_default(n, &style);
|
||||
cell_release(n, &style);
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,10 +23,16 @@ draw_block(struct ncplane* nn, uint32_t blockstart){
|
||||
cell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
|
||||
cell hl = CELL_TRIVIAL_INITIALIZER, vl = CELL_TRIVIAL_INITIALIZER;
|
||||
cells_rounded_box(nn, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl);
|
||||
cell_set_bg_alpha(&ul, 3);
|
||||
cell_set_bg_alpha(&ur, 3);
|
||||
cell_set_bg_alpha(&ll, 3);
|
||||
cell_set_bg_alpha(&lr, 3);
|
||||
cell_set_bg_alpha(&ul, CELL_ALPHA_TRANS);
|
||||
cell_set_bg_alpha(&ur, CELL_ALPHA_TRANS);
|
||||
cell_set_bg_alpha(&ll, CELL_ALPHA_TRANS);
|
||||
cell_set_bg_alpha(&lr, CELL_ALPHA_TRANS);
|
||||
cell_set_fg_rgb(&ll, 255, 255, 255);
|
||||
cell_set_fg_rgb(&lr, 255, 255, 255);
|
||||
cell_set_fg_rgb(&ul, 255, 255, 255);
|
||||
cell_set_fg_rgb(&ur, 255, 255, 255);
|
||||
cell_set_fg_rgb(&hl, 255, 255, 255);
|
||||
cell_set_fg_rgb(&vl, 255, 255, 255);
|
||||
cell_set_bg_rgb(&hl, 0, 0, 0);
|
||||
cell_set_bg_rgb(&vl, 0, 0, 0);
|
||||
if(ncplane_box_sized(nn, &ul, &ur, &ll, &lr, &hl, &vl,
|
||||
|
@ -283,9 +283,8 @@ message(struct ncplane* n, int maxy, int maxx, int num, int total,
|
||||
int bytes_out, int egs_out, int cols_out){
|
||||
cell c = CELL_TRIVIAL_INITIALIZER;
|
||||
cell_load(n, &c, " ");
|
||||
cell_set_fg_alpha(&c, 3);
|
||||
cell_set_bg_alpha(&c, 3);
|
||||
ncplane_set_background(n, &c);
|
||||
cell_set_bg_alpha(&c, CELL_ALPHA_TRANS);
|
||||
ncplane_set_default(n, &c);
|
||||
cell_release(n, &c);
|
||||
uint64_t channels = 0;
|
||||
ncplane_set_fg_rgb(n, 64, 128, 240);
|
||||
|
@ -50,7 +50,7 @@ typedef struct ncplane {
|
||||
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 background; // cell written anywhere that fb[i].gcluster == 0
|
||||
cell defcell; // cell written anywhere that fb[i].gcluster == 0
|
||||
struct notcurses* nc; // notcurses object of which we are a part
|
||||
} ncplane;
|
||||
|
||||
|
@ -347,7 +347,7 @@ ncplane_create(notcurses* nc, int rows, int cols, int yoff, int xoff){
|
||||
p->z = nc->top;
|
||||
nc->top = p;
|
||||
p->nc = nc;
|
||||
cell_init(&p->background);
|
||||
cell_init(&p->defcell);
|
||||
nc->stats.fbbytes += fbsize;
|
||||
return p;
|
||||
}
|
||||
@ -773,6 +773,8 @@ int notcurses_stop(notcurses* nc){
|
||||
int ret = 0;
|
||||
if(nc){
|
||||
drop_signals(nc);
|
||||
// FIXME these can fail if we stop in the middle of a rendering operation.
|
||||
// turn the fd back to blocking, perhaps?
|
||||
if(nc->rmcup && term_emit("rmcup", nc->rmcup, nc->ttyfp, true)){
|
||||
ret = -1;
|
||||
}
|
||||
@ -851,20 +853,28 @@ int ncplane_set_fg_rgb(ncplane* n, int r, int g, int b){
|
||||
return channels_set_fg_rgb(&n->channels, r, g, b);
|
||||
}
|
||||
|
||||
void ncplane_set_fg(ncplane* n, uint32_t halfchannel){
|
||||
n->channels = ((uint64_t)halfchannel << 32ul) | (n->channels & 0xffffffffull);
|
||||
void ncplane_set_fg(ncplane* n, uint32_t channel){
|
||||
n->channels = ((uint64_t)channel << 32ul) | (n->channels & 0xffffffffull);
|
||||
}
|
||||
|
||||
void ncplane_set_bg(ncplane* n, uint32_t halfchannel){
|
||||
n->channels = (n->channels & 0xffffffff00000000ull) | halfchannel;
|
||||
void ncplane_set_bg(ncplane* n, uint32_t channel){
|
||||
n->channels = (n->channels & 0xffffffff00000000ull) | channel;
|
||||
}
|
||||
|
||||
int ncplane_set_background(ncplane* ncp, const cell* c){
|
||||
return cell_duplicate(ncp, &ncp->background, c);
|
||||
int ncplane_set_fg_alpha(ncplane* n, int alpha){
|
||||
return channels_set_fg_alpha(&n->channels, alpha);
|
||||
}
|
||||
|
||||
int ncplane_background(ncplane* ncp, cell* c){
|
||||
return cell_duplicate(ncp, c, &ncp->background);
|
||||
int ncplane_set_bg_alpha(ncplane *n, int alpha){
|
||||
return channels_set_bg_alpha(&n->channels, alpha);
|
||||
}
|
||||
|
||||
int ncplane_set_default(ncplane* ncp, const cell* c){
|
||||
return cell_duplicate(ncp, &ncp->defcell, c);
|
||||
}
|
||||
|
||||
int ncplane_default(ncplane* ncp, cell* c){
|
||||
return cell_duplicate(ncp, c, &ncp->defcell);
|
||||
}
|
||||
|
||||
// 3 for foreground, 4 for background, ugh FIXME
|
||||
@ -1052,10 +1062,26 @@ term_setstyles(const notcurses* nc, FILE* out, uint32_t* curattr, const cell* c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// find the topmost cell for this coordinate
|
||||
static const cell*
|
||||
visible_cell(int y, int x, ncplane** retp){
|
||||
ncplane* p = *retp;
|
||||
// Find the topmost cell for this coordinate by walking down the z-buffer,
|
||||
// looking for an intersecting ncplane. Once we've found one, check it for
|
||||
// transparency in either the back- or foreground. If the alpha channel is
|
||||
// active, keep descending and blending until we hit opacity, or bedrock. We
|
||||
// recurse to find opacity, and blend the result into what we have. The
|
||||
// 'findfore' and 'findback' bools control our recursion--there's no point in
|
||||
// going further down when a color is locked in, so don't (for instance) recurse
|
||||
// further when we have a transparent foreground and opaque background atop an
|
||||
// opaque foreground and transparent background. The cell we ultimately return
|
||||
// (a const ref to 'c') is backed by '*retp' via rawdog copy; the caller must
|
||||
// not call cell_release() upon it, nor use it beyond the scope of the render.
|
||||
//
|
||||
// So, as we go down, we find planes which can have impact on the result. Once
|
||||
// we've locked the result in (base case), write the deep values we have to 'c'.
|
||||
// Then, as we come back up, blend them as appropriate. The actual glyph is
|
||||
// whichever one occurs at the top with a non-transparent α (α < 3). To effect
|
||||
// tail recursion, though, we instead write first, and then recurse, blending
|
||||
// as we descend. α <= 0 is opaque. α >= 3 is fully transparent.
|
||||
static ncplane*
|
||||
dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha){
|
||||
while(p){
|
||||
// where in the plane this coordinate would be, based off absy/absx. the
|
||||
// true origin is 0,0, so abs=2,2 means coordinate 3,3 would be 1,1, while
|
||||
@ -1064,33 +1090,52 @@ visible_cell(int y, int x, ncplane** retp){
|
||||
poffy = y - p->absy;
|
||||
poffx = x - p->absx;
|
||||
if(poffy < p->leny && poffy >= 0){
|
||||
if(poffx < p->lenx && poffx >= 0){
|
||||
*retp = p;
|
||||
if(poffx < p->lenx && poffx >= 0){ // p is valid for this y, x
|
||||
const cell* vis = &p->fb[fbcellidx(p, poffy, poffx)];
|
||||
// if we never loaded any content into the cell (or obliterated it by
|
||||
// writing in a zero), use the plane's background cell.
|
||||
if(vis->gcluster == 0){
|
||||
vis = &p->background;
|
||||
vis = &p->defcell;
|
||||
}
|
||||
// FIXME do this more rigorously, PoC
|
||||
if(cell_get_fg_alpha(vis) || cell_get_bg_alpha(vis)){
|
||||
*retp = p->z;
|
||||
const cell* trans = visible_cell(y, x, retp);
|
||||
if(trans){
|
||||
vis = trans;
|
||||
}else{
|
||||
*retp = p;
|
||||
bool lockedglyph = false;
|
||||
int nalpha;
|
||||
if(falpha > 0 && (nalpha = cell_get_fg_alpha(vis)) < CELL_ALPHA_TRANS){
|
||||
if(c->gcluster == 0){ // never write fully trans glyphs, never replace
|
||||
if( (c->gcluster = vis->gcluster) ){ // index copy only
|
||||
lockedglyph = true; // must return this ncplane for this glyph
|
||||
c->attrword = vis->attrword;
|
||||
cell_set_fg(c, cell_get_fg(vis)); // FIXME blend it in
|
||||
falpha -= (CELL_ALPHA_TRANS - nalpha); // FIXME blend it in
|
||||
}
|
||||
}
|
||||
return vis;
|
||||
}
|
||||
if(balpha > 0 && (nalpha = cell_get_bg_alpha(vis)) < CELL_ALPHA_TRANS){
|
||||
cell_set_bg(c, cell_get_bg(vis)); // FIXME blend it in
|
||||
balpha -= (CELL_ALPHA_TRANS - nalpha);
|
||||
}
|
||||
if((falpha > 0 || balpha > 0) && p->z){ // we must go further!
|
||||
ncplane* cand = dig_visible_cell(c, y, x, p->z, falpha, balpha);
|
||||
if(!lockedglyph && cand){
|
||||
p = cand;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
p = p->z;
|
||||
}
|
||||
// should never happen for valid y, x thanks to the stdscreen
|
||||
// should never happen for valid y, x thanks to the stdplane. you fucked up!
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline ncplane*
|
||||
visible_cell(cell* c, int y, int x, ncplane* n){
|
||||
cell_init(c);
|
||||
return dig_visible_cell(c, y, x, n, CELL_ALPHA_TRANS, CELL_ALPHA_TRANS);
|
||||
}
|
||||
|
||||
// Call with c->gcluster == 3, falpha == 3, balpha == 0, *retp == topplane.
|
||||
|
||||
// 'n' ends up above 'above'
|
||||
int ncplane_move_above(ncplane* restrict n, ncplane* restrict above){
|
||||
ncplane** an = find_above_ncplane(n);
|
||||
@ -1215,21 +1260,20 @@ notcurses_render_internal(notcurses* nc){
|
||||
term_emit("cup", tiparm(nc->cup, y, 0), out, false);
|
||||
for(x = 0 ; x < nc->stdscr->lenx ; ++x){
|
||||
unsigned r, g, b, br, bg, bb;
|
||||
ncplane* p = nc->top;
|
||||
const cell* c = visible_cell(y, x, &p);
|
||||
if(c == NULL){
|
||||
continue; // shrug?
|
||||
}
|
||||
ncplane* p;
|
||||
cell c; // no need to initialize
|
||||
p = visible_cell(&c, y, x, nc->top);
|
||||
assert(p);
|
||||
// don't try to print a wide character on the last column; it'll instead
|
||||
// be printed on the next line. they probably shouldn't be admitted, but
|
||||
// we can end up with one due to a resize.
|
||||
if((x + 1 >= nc->stdscr->lenx && cell_double_wide_p(c))){
|
||||
if((x + 1 >= nc->stdscr->lenx && cell_double_wide_p(&c))){
|
||||
continue;
|
||||
}
|
||||
// set the style. this can change the color back to the default; if it
|
||||
// does, we need update our elision possibilities.
|
||||
bool normalized;
|
||||
term_setstyles(nc, out, &curattr, c, &normalized);
|
||||
term_setstyles(nc, out, &curattr, &c, &normalized);
|
||||
if(normalized){
|
||||
defaultelidable = true;
|
||||
bgelidable = false;
|
||||
@ -1241,7 +1285,7 @@ notcurses_render_internal(notcurses* nc){
|
||||
// then a turnon for whichever aren't default.
|
||||
|
||||
// we can elide the default set iff the previous used both defaults
|
||||
if(cell_fg_default_p(c) || cell_bg_default_p(c)){
|
||||
if(cell_fg_default_p(&c) || cell_bg_default_p(&c)){
|
||||
if(!defaultelidable){
|
||||
++nc->stats.defaultemissions;
|
||||
term_emit("op", nc->op, out, false);
|
||||
@ -1255,8 +1299,8 @@ notcurses_render_internal(notcurses* nc){
|
||||
}
|
||||
|
||||
// we can elide the foreground set iff the previous used fg and matched
|
||||
if(!cell_fg_default_p(c)){
|
||||
cell_get_fg_rgb(c, &r, &g, &b);
|
||||
if(!cell_fg_default_p(&c)){
|
||||
cell_get_fg_rgb(&c, &r, &g, &b);
|
||||
if(fgelidable && lastr == r && lastg == g && lastb == b){
|
||||
++nc->stats.fgelisions;
|
||||
}else{
|
||||
@ -1267,8 +1311,8 @@ notcurses_render_internal(notcurses* nc){
|
||||
lastr = r; lastg = g; lastb = b;
|
||||
defaultelidable = false;
|
||||
}
|
||||
if(!cell_bg_default_p(c)){
|
||||
cell_get_bg_rgb(c, &br, &bg, &bb);
|
||||
if(!cell_bg_default_p(&c)){
|
||||
cell_get_bg_rgb(&c, &br, &bg, &bb);
|
||||
if(bgelidable && lastbr == br && lastbg == bg && lastbb == bb){
|
||||
++nc->stats.bgelisions;
|
||||
}else{
|
||||
@ -1279,11 +1323,11 @@ notcurses_render_internal(notcurses* nc){
|
||||
lastbr = br; lastbg = bg; lastbb = bb;
|
||||
defaultelidable = false;
|
||||
}
|
||||
term_putc(out, p, c);
|
||||
if(cell_double_wide_p(c)){
|
||||
// fprintf(stderr, "[%02d/%02d] 0x%02x 0x%02x 0x%02x %p\n", y, x, r, g, b, p);
|
||||
term_putc(out, p, &c);
|
||||
if(cell_double_wide_p(&c)){
|
||||
++x;
|
||||
}
|
||||
//fprintf(stderr, "[%02d/%02d]\n", y, x);
|
||||
}
|
||||
}
|
||||
ret |= fclose(out);
|
||||
@ -1378,10 +1422,11 @@ int cell_duplicate(ncplane* n, cell* targ, const cell* c){
|
||||
}
|
||||
|
||||
int ncplane_putc(ncplane* n, const cell* c){
|
||||
ncplane_lock(n);
|
||||
if(cursor_invalid_p(n)){
|
||||
ncplane_unlock(n);
|
||||
return -1;
|
||||
}
|
||||
ncplane_lock(n);
|
||||
cell* targ = &n->fb[fbcellidx(n, n->y, n->x)];
|
||||
if(cell_duplicate(n, targ, c) < 0){
|
||||
ncplane_unlock(n);
|
||||
@ -1830,11 +1875,11 @@ 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
|
||||
// and channels), and then reload.
|
||||
char* egc = cell_egc_copy(n, &n->background);
|
||||
char* egc = cell_egc_copy(n, &n->defcell);
|
||||
memset(n->fb, 0, sizeof(*n->fb) * n->lenx * n->leny);
|
||||
egcpool_dump(&n->pool);
|
||||
egcpool_init(&n->pool);
|
||||
cell_load(n, &n->background, egc);
|
||||
cell_load(n, &n->defcell, egc);
|
||||
free(egc);
|
||||
ncplane_unlock(n);
|
||||
}
|
||||
@ -1948,7 +1993,7 @@ alloc_ncplane_palette(ncplane* n, planepalette* pp){
|
||||
}
|
||||
}
|
||||
// FIXME factor this duplication out
|
||||
channels = n->background.channels;
|
||||
channels = n->defcell.channels;
|
||||
pp->channels[y * pp->cols] = channels;
|
||||
channels_get_fg_rgb(channels, &r, &g, &b);
|
||||
if(r > pp->maxr){
|
||||
@ -2098,20 +2143,20 @@ int ncplane_fadeout(ncplane* n, const struct timespec* ts){
|
||||
}
|
||||
}
|
||||
}
|
||||
cell* c = &n->background;
|
||||
cell* c = &n->defcell;
|
||||
if(!cell_fg_default_p(c)){
|
||||
channels_get_fg_rgb(pp.channels[pp.cols * y], &r, &g, &b);
|
||||
r = r * (maxsteps - iter) / maxsteps;
|
||||
g = g * (maxsteps - iter) / maxsteps;
|
||||
b = b * (maxsteps - iter) / maxsteps;
|
||||
cell_set_fg_rgb(&n->background, r, g, b);
|
||||
cell_set_fg_rgb(&n->defcell, r, g, b);
|
||||
}
|
||||
if(!cell_bg_default_p(c)){
|
||||
channels_get_bg_rgb(pp.channels[pp.cols * y], &br, &bg, &bb);
|
||||
br = br * (maxsteps - iter) / maxsteps;
|
||||
bg = bg * (maxsteps - iter) / maxsteps;
|
||||
bb = bb * (maxsteps - iter) / maxsteps;
|
||||
cell_set_bg_rgb(&n->background, br, bg, bb);
|
||||
cell_set_bg_rgb(&n->defcell, br, bg, bb);
|
||||
}
|
||||
notcurses_render(n->nc);
|
||||
uint64_t nextwake = (iter + 1) * nanosecs_step + startns;
|
||||
|
@ -598,7 +598,7 @@ panelreel* panelreel_create(ncplane* w, const panelreel_options* popts, int efd)
|
||||
}
|
||||
cell bgc = CELL_TRIVIAL_INITIALIZER;
|
||||
bgc.channels = popts->bgchannel;
|
||||
ncplane_set_background(pr->p, &bgc);
|
||||
ncplane_set_default(pr->p, &bgc);
|
||||
cell_release(pr->p, &bgc);
|
||||
if(panelreel_redraw(pr)){
|
||||
ncplane_destroy(pr->p);
|
||||
|
@ -41,7 +41,7 @@ TEST_F(CellTest, SetItalic) {
|
||||
cell_styles_set(&c, CELL_STYLE_ITALIC);
|
||||
ASSERT_EQ(1, cell_load(n_, &c, "i"));
|
||||
cell_set_fg_rgb(&c, 255, 255, 255);
|
||||
ncplane_set_background(n_, &c);
|
||||
ncplane_set_default(n_, &c);
|
||||
cell_release(n_, &c);
|
||||
EXPECT_EQ(0, notcurses_render(nc_));
|
||||
cell_styles_off(&c, CELL_STYLE_ITALIC);
|
||||
@ -55,7 +55,7 @@ TEST_F(CellTest, SetBold) {
|
||||
cell_styles_set(&c, CELL_STYLE_BOLD);
|
||||
ASSERT_EQ(1, cell_load(n_, &c, "b"));
|
||||
cell_set_fg_rgb(&c, 255, 255, 255);
|
||||
ncplane_set_background(n_, &c);
|
||||
ncplane_set_default(n_, &c);
|
||||
cell_release(n_, &c);
|
||||
EXPECT_EQ(0, notcurses_render(nc_));
|
||||
cell_styles_off(&c, CELL_STYLE_BOLD);
|
||||
@ -69,7 +69,7 @@ TEST_F(CellTest, SetUnderline) {
|
||||
cell_styles_set(&c, CELL_STYLE_UNDERLINE);
|
||||
ASSERT_EQ(1, cell_load(n_, &c, "u"));
|
||||
cell_set_fg_rgb(&c, 255, 255, 255);
|
||||
ncplane_set_background(n_, &c);
|
||||
ncplane_set_default(n_, &c);
|
||||
cell_release(n_, &c);
|
||||
EXPECT_EQ(0, notcurses_render(nc_));
|
||||
cell_styles_off(&c, CELL_STYLE_UNDERLINE);
|
||||
|
Loading…
Reference in New Issue
Block a user