mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
ncplane_putegc_yx() copies directly as opposed to going through putc() #797
This commit is contained in:
parent
0767aaec01
commit
97571e86af
15
USAGE.md
15
USAGE.md
@ -1626,6 +1626,21 @@ void cell_release(struct ncplane* n, cell* c);
|
|||||||
#define NCSTYLE_PROTECT 0x00010000ul
|
#define NCSTYLE_PROTECT 0x00010000ul
|
||||||
#define NCSTYLE_ITALIC 0x01000000ul
|
#define NCSTYLE_ITALIC 0x01000000ul
|
||||||
|
|
||||||
|
// copy the UTF8-encoded EGC out of the cell, whether simple or complex. the
|
||||||
|
// result is not tied to the ncplane, and persists across erases / destruction.
|
||||||
|
static inline char*
|
||||||
|
cell_strdup(const struct ncplane* n, const cell* c){
|
||||||
|
char* ret;
|
||||||
|
if(cell_simple_p(c)){
|
||||||
|
if( (ret = (char*)malloc(2)) ){ // cast is here for C++ clients
|
||||||
|
ret[0] = c->gcluster;
|
||||||
|
ret[1] = '\0';
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
ret = strdup(cell_extended_gcluster(n, c));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the specified style bits for the cell 'c', whether they're actively
|
// Set the specified style bits for the cell 'c', whether they're actively
|
||||||
// supported or not.
|
// supported or not.
|
||||||
|
@ -729,7 +729,8 @@ cell_simple_p(const cell* c){
|
|||||||
// is invalidated by any further operation on the plane 'n', so...watch out!
|
// is invalidated by any further operation on the plane 'n', so...watch out!
|
||||||
API const char* cell_extended_gcluster(const struct ncplane* n, const cell* c);
|
API const char* cell_extended_gcluster(const struct ncplane* n, const cell* c);
|
||||||
|
|
||||||
// Extract the EGC from 'c' as a nul-terminated string.
|
// copy the UTF8-encoded EGC out of the cell, whether simple or complex. the
|
||||||
|
// result is not tied to the ncplane, and persists across erases / destruction.
|
||||||
static inline char*
|
static inline char*
|
||||||
cell_strdup(const struct ncplane* n, const cell* c){
|
cell_strdup(const struct ncplane* n, const cell* c){
|
||||||
char* ret;
|
char* ret;
|
||||||
|
@ -410,13 +410,6 @@ pool_egc_copy(const egcpool* e, const cell* c){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy the UTF8-encoded EGC out of the cell, whether simple or complex. the
|
|
||||||
// result is not tied to the ncplane, and persists across erases / destruction.
|
|
||||||
static inline char*
|
|
||||||
cell_egc_copy(const ncplane* n, const cell* c){
|
|
||||||
return pool_egc_copy(&n->pool, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For our first attempt, O(1) uniform conversion from 8-bit r/g/b down to
|
// For our first attempt, O(1) uniform conversion from 8-bit r/g/b down to
|
||||||
// ~2.4-bit 6x6x6 cube + greyscale (assumed on entry; I know no way to
|
// ~2.4-bit 6x6x6 cube + greyscale (assumed on entry; I know no way to
|
||||||
// even semi-portably recover the palette) proceeds via: map each 8-bit to
|
// even semi-portably recover the palette) proceeds via: map each 8-bit to
|
||||||
|
@ -1284,17 +1284,66 @@ int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ncplane_putegc_yx(ncplane* n, int y, int x, const char* gclust, int* sbytes){
|
int ncplane_putegc_yx(ncplane* n, int y, int x, const char* gclust, int* sbytes){
|
||||||
cell c = CELL_TRIVIAL_INITIALIZER;
|
int cols;
|
||||||
int primed = cell_prime(n, &c, gclust, n->attrword, n->channels);
|
int bytes = utf8_egc_len(gclust, &cols);
|
||||||
if(sbytes){
|
if(sbytes){
|
||||||
*sbytes = primed;
|
*sbytes = bytes;
|
||||||
}
|
}
|
||||||
if(primed < 0){
|
// if scrolling is enabled, check *before ncplane_cursor_move_yx()* whether
|
||||||
|
// we're past the end of the line, and move to the next line if so.
|
||||||
|
bool wide = cols > 1;
|
||||||
|
if(x == -1 && y == -1 && n->x + wide >= n->lenx){
|
||||||
|
if(!n->scrolling){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
scroll_down(n);
|
||||||
|
}
|
||||||
|
if(ncplane_cursor_move_yx(n, y, x)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int ret = ncplane_putc_yx(n, y, x, &c);
|
if(*gclust == '\n'){
|
||||||
cell_release(n, &c);
|
if(n->scrolling){
|
||||||
return ret;
|
scroll_down(n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// A wide character obliterates anything to its immediate right (and marks
|
||||||
|
// that cell as wide). Any character placed atop one half of a wide character
|
||||||
|
// obliterates the other half. Note that a wide char can thus obliterate two
|
||||||
|
// wide chars, totalling four columns.
|
||||||
|
cell* targ = ncplane_cell_ref_yx(n, n->y, n->x);
|
||||||
|
if(n->x > 0){
|
||||||
|
if(cell_double_wide_p(targ)){ // replaced cell is half of a wide char
|
||||||
|
if(targ->gcluster == 0){ // we're the right half
|
||||||
|
cell_obliterate(n, &n->fb[nfbcellidx(n, n->y, n->x - 1)]);
|
||||||
|
}else{
|
||||||
|
cell_obliterate(n, &n->fb[nfbcellidx(n, n->y, n->x + 1)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint64_t channels = n->channels & ~CELL_WIDEASIAN_MASK;
|
||||||
|
if(wide){
|
||||||
|
channels |= CELL_WIDEASIAN_MASK;
|
||||||
|
}
|
||||||
|
if(cell_prime(n, targ, gclust, n->attrword, channels) < 0){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(wide){ // must set our right wide, and check for further damage
|
||||||
|
if(n->x < n->lenx - 1){ // check to our right
|
||||||
|
cell* candidate = &n->fb[nfbcellidx(n, n->y, n->x + 1)];
|
||||||
|
if(n->x < n->lenx - 2){
|
||||||
|
if(cell_wide_left_p(candidate)){
|
||||||
|
cell_obliterate(n, &n->fb[nfbcellidx(n, n->y, n->x + 2)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell_obliterate(n, candidate);
|
||||||
|
cell_set_wide(candidate);
|
||||||
|
candidate->channels = channels;
|
||||||
|
candidate->attrword = n->attrword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n->x += cols;
|
||||||
|
return cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ncplane_putsimple_stainable(ncplane* n, char c){
|
int ncplane_putsimple_stainable(ncplane* n, char c){
|
||||||
@ -1867,7 +1916,7 @@ void ncplane_erase(ncplane* n){
|
|||||||
// we must preserve the background, but a pure cell_duplicate() would be
|
// 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 attrword
|
||||||
// and channels), and then reload.
|
// and channels), and then reload.
|
||||||
char* egc = cell_egc_copy(n, &n->basecell);
|
char* egc = cell_strdup(n, &n->basecell);
|
||||||
memset(n->fb, 0, sizeof(*n->fb) * n->lenx * n->leny);
|
memset(n->fb, 0, sizeof(*n->fb) * n->lenx * n->leny);
|
||||||
egcpool_dump(&n->pool);
|
egcpool_dump(&n->pool);
|
||||||
egcpool_init(&n->pool);
|
egcpool_init(&n->pool);
|
||||||
|
@ -284,7 +284,7 @@ TEST_CASE("Wide") {
|
|||||||
|
|
||||||
// should be wide char 1
|
// should be wide char 1
|
||||||
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 0, &c));
|
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 0, &c));
|
||||||
egc = cell_egc_copy(n_, &c);
|
egc = cell_strdup(n_, &c);
|
||||||
REQUIRE(egc);
|
REQUIRE(egc);
|
||||||
CHECK(!strcmp("\xe5\x85\xa8", egc));
|
CHECK(!strcmp("\xe5\x85\xa8", egc));
|
||||||
CHECK(cell_double_wide_p(&c));
|
CHECK(cell_double_wide_p(&c));
|
||||||
@ -297,7 +297,7 @@ TEST_CASE("Wide") {
|
|||||||
cell_init(&c);
|
cell_init(&c);
|
||||||
// should be wide char 1 right side
|
// should be wide char 1 right side
|
||||||
REQUIRE(0 == ncplane_at_yx_cell(n_, 0, 1, &c));
|
REQUIRE(0 == ncplane_at_yx_cell(n_, 0, 1, &c));
|
||||||
egc = cell_egc_copy(n_, &c);
|
egc = cell_strdup(n_, &c);
|
||||||
REQUIRE(egc);
|
REQUIRE(egc);
|
||||||
CHECK(!strcmp("", egc));
|
CHECK(!strcmp("", egc));
|
||||||
CHECK(cell_double_wide_p(&c));
|
CHECK(cell_double_wide_p(&c));
|
||||||
@ -311,7 +311,7 @@ TEST_CASE("Wide") {
|
|||||||
|
|
||||||
// should be wide char 2
|
// should be wide char 2
|
||||||
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 2, &c));
|
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 2, &c));
|
||||||
egc = cell_egc_copy(n_, &c);
|
egc = cell_strdup(n_, &c);
|
||||||
REQUIRE(egc);
|
REQUIRE(egc);
|
||||||
CHECK(!strcmp("\xe5\xbd\xa2", egc));
|
CHECK(!strcmp("\xe5\xbd\xa2", egc));
|
||||||
CHECK(cell_double_wide_p(&c));
|
CHECK(cell_double_wide_p(&c));
|
||||||
@ -324,7 +324,7 @@ TEST_CASE("Wide") {
|
|||||||
cell_init(&c);
|
cell_init(&c);
|
||||||
// should be wide char 2 right side
|
// should be wide char 2 right side
|
||||||
CHECK(0 == ncplane_at_yx_cell(n_, 0, 3, &c));
|
CHECK(0 == ncplane_at_yx_cell(n_, 0, 3, &c));
|
||||||
egc = cell_egc_copy(n_, &c);
|
egc = cell_strdup(n_, &c);
|
||||||
REQUIRE(egc);
|
REQUIRE(egc);
|
||||||
CHECK(!strcmp("", egc));
|
CHECK(!strcmp("", egc));
|
||||||
CHECK(cell_double_wide_p(&c));
|
CHECK(cell_double_wide_p(&c));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user