You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
10 KiB
C++
261 lines
10 KiB
C++
#include "main.h"
|
|
|
|
// These tests address cases where box characters on two overlapping planes
|
|
// interact in non-trivial ways. A simple example is a U2580 UPPER HALF BLOCK
|
|
// (▀) with a white foreground and transparent background, above a U2584 LOWER
|
|
// HALF BLOCK (▄) with a white foreground and transparent background. One might
|
|
// expect the result to be an entirely white cell, but by typical Notcurses
|
|
// rendering rules, we would instead get a white upper half and transparent
|
|
// lower half:
|
|
//
|
|
// - after first cell, glyph is locked U2584, fg is locked white, bg transparent
|
|
// - second cell can't override glyph nor fg, and background remains transparent
|
|
//
|
|
// we will instead special-case block-drawing characters.
|
|
// see https://github.com/dankamongmen/notcurses/issues/1068
|
|
TEST_CASE("Stacking") {
|
|
auto nc_ = testing_notcurses();
|
|
if(!nc_){
|
|
return;
|
|
}
|
|
if(!notcurses_canutf8(nc_)){
|
|
CHECK(0 == notcurses_stop(nc_));
|
|
return;
|
|
}
|
|
unsigned dimy, dimx;
|
|
struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
|
|
REQUIRE(nullptr != n_);
|
|
|
|
// whenever the foreground matches the background (using RGB color, *not*
|
|
// default colors not palette-indexed color), we ought emit a space with the
|
|
// specified background, or a full block with the specified foreground (only
|
|
// if UTF8 is available). default colors must not be merged (palette-indexed
|
|
// could be, but it's pointless). the transformation must only take place at
|
|
// raster time--the original output must be recoverable from the plane.
|
|
SUBCASE("FgMatchesBgRGB") {
|
|
// first we write an a with the desired background, but a distinct
|
|
// foreground. then we write an a with the two matching (via RGB).
|
|
// this ought generate a space with the desired background on the
|
|
// second cell.
|
|
ncplane_set_fg_default(n_);
|
|
CHECK(0 == ncplane_set_bg_rgb(n_, 0x808080));
|
|
CHECK(1 == ncplane_putchar(n_, 'a'));
|
|
CHECK(0 == ncplane_set_fg_rgb(n_, 0x808080));
|
|
CHECK(1 == ncplane_putchar(n_, 'a')); // ought become a space
|
|
// now we write an x with the desired foreground, but a distinct
|
|
// background. then we write an x with the two matching. this ought
|
|
// generate a full block with the desired foreground if UTF8 is
|
|
// available, and a space with the desired background otherwise.
|
|
ncplane_set_bg_default(n_);
|
|
CHECK(1 == ncplane_putchar(n_, 'x'));
|
|
CHECK(0 == ncplane_set_bg_rgb(n_, 0x808080));
|
|
CHECK(1 == ncplane_putchar(n_, 'x')); // ought become a space/block
|
|
CHECK(0 == notcurses_render(nc_));
|
|
// now we check the output. the plane ought have the characters as written,
|
|
// but we ought have rasterized the optimal forms.
|
|
uint64_t channels;
|
|
auto pblit = ncplane_at_yx(n_, 0, 1, nullptr, &channels);
|
|
CHECK(0 == strcmp("a", pblit));
|
|
CHECK(0x808080 == ncchannels_bg_rgb(channels));
|
|
CHECK(0x808080 == ncchannels_fg_rgb(channels));
|
|
free(pblit);
|
|
pblit = ncplane_at_yx(n_, 0, 3, nullptr, &channels);
|
|
CHECK(0 == strcmp("x", pblit));
|
|
CHECK(0x808080 == ncchannels_bg_rgb(channels));
|
|
CHECK(0x808080 == ncchannels_fg_rgb(channels));
|
|
free(pblit);
|
|
auto rblit = notcurses_at_yx(nc_, 0, 1, nullptr, &channels);
|
|
CHECK(0 == strcmp(" ", rblit));
|
|
CHECK(0x808080 == ncchannels_bg_rgb(channels));
|
|
free(rblit);
|
|
rblit = notcurses_at_yx(nc_, 0, 3, nullptr, &channels);
|
|
if(notcurses_canutf8(nc_)){
|
|
CHECK(0x808080 == ncchannels_fg_rgb(channels));
|
|
// FIXME we're not yet this advanced, and use space instead
|
|
// CHECK(0 == strcmp(u8"\u2588", rblit));
|
|
CHECK(0 == strcmp(u8" ", rblit));
|
|
}else{
|
|
CHECK(0 == strcmp(" ", rblit));
|
|
CHECK(0x808080 == ncchannels_bg_rgb(channels));
|
|
}
|
|
free(rblit);
|
|
}
|
|
|
|
SUBCASE("LowerAtopUpperWhite") {
|
|
struct ncplane_options opts = {
|
|
.y = 0, .x = 0, .rows = 1, .cols = 1,
|
|
.userptr = nullptr, .name = "top",
|
|
.resizecb = nullptr,
|
|
.flags = 0,
|
|
.margin_b = 0, .margin_r = 0,
|
|
};
|
|
auto top = ncplane_create(n_, &opts);
|
|
REQUIRE(nullptr != top);
|
|
// create an ncvisual of 2 rows, 1 column, with the bottom 0xffffff
|
|
const uint32_t topv[] = {htole(0), htole(0xffffffff)};
|
|
auto ncv = ncvisual_from_rgba(topv, 2, 4, 1);
|
|
REQUIRE(nullptr != ncv);
|
|
struct ncvisual_options vopts = {
|
|
.n = top, .scaling = NCSCALE_NONE, .y = 0, .x = 0, .begy = 0, .begx = 0,
|
|
.leny = 2, .lenx = 1, .blitter = NCBLIT_2x1, .flags = 0,
|
|
.transcolor = 0, .pxoffy = 0, .pxoffx = 0,
|
|
};
|
|
CHECK(top == ncvisual_blit(nc_, ncv, &vopts));
|
|
ncvisual_destroy(ncv);
|
|
|
|
// create an ncvisual of 2 rows, 1 column, with the top 0xffffff
|
|
const uint32_t botv[] = {htole(0xffffffff), htole(0)};
|
|
ncv = ncvisual_from_rgba(botv, 2, 4, 1);
|
|
REQUIRE(nullptr != ncv);
|
|
vopts.n = n_;
|
|
vopts.flags |= NCVISUAL_OPTION_CHILDPLANE;
|
|
auto newn = ncvisual_blit(nc_, ncv, &vopts);
|
|
REQUIRE(nullptr != newn);
|
|
ncvisual_destroy(ncv);
|
|
ncplane_move_below(newn, top);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
uint64_t channels;
|
|
auto egc = notcurses_at_yx(nc_, 0, 0, nullptr, &channels);
|
|
REQUIRE(nullptr != egc);
|
|
CHECK(0 == strcmp(u8" ", egc));
|
|
free(egc);
|
|
CHECK(0xffffff == ncchannels_fg_rgb(channels));
|
|
CHECK(0xffffff == ncchannels_bg_rgb(channels));
|
|
CHECK(0 == ncplane_destroy(top));
|
|
CHECK(0 == ncplane_destroy(newn));
|
|
}
|
|
|
|
SUBCASE("UpperAtopLowerWhite") {
|
|
struct ncplane_options opts = {
|
|
0, 0, 1, 1, nullptr, "top", nullptr, 0, 0, 0,
|
|
};
|
|
auto top = ncplane_create(n_, &opts);
|
|
REQUIRE(nullptr != top);
|
|
// create an ncvisual of 2 rows, 1 column, with the top 0xffffff
|
|
const uint32_t topv[] = {htole(0xffffffff), htole(0)};
|
|
auto ncv = ncvisual_from_rgba(topv, 2, 4, 1);
|
|
REQUIRE(nullptr != ncv);
|
|
struct ncvisual_options vopts = {
|
|
.n = top, .scaling = NCSCALE_NONE, .y = 0, .x = 0, .begy = 0, .begx = 0,
|
|
.leny = 2, .lenx = 1, .blitter = NCBLIT_2x1, .flags = 0,
|
|
.transcolor = 0, .pxoffy = 0, .pxoffx = 0,
|
|
};
|
|
CHECK(top == ncvisual_blit(nc_, ncv, &vopts));
|
|
ncvisual_destroy(ncv);
|
|
|
|
// create an ncvisual of 2 rows, 1 column, with the bottom 0xffffff
|
|
const uint32_t botv[] = {htole(0), htole(0xffffffff)};
|
|
ncv = ncvisual_from_rgba(botv, 2, 4, 1);
|
|
REQUIRE(nullptr != ncv);
|
|
vopts.n = n_;
|
|
vopts.flags |= NCVISUAL_OPTION_CHILDPLANE;
|
|
auto newn = ncvisual_blit(nc_, ncv, &vopts);
|
|
REQUIRE(nullptr != newn);
|
|
ncvisual_destroy(ncv);
|
|
ncplane_move_below(newn, top);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
uint64_t channels;
|
|
auto egc = notcurses_at_yx(nc_, 0, 0, nullptr, &channels);
|
|
REQUIRE(nullptr != egc);
|
|
CHECK(0 == strcmp(u8" ", egc));
|
|
free(egc);
|
|
CHECK(0xffffff == ncchannels_fg_rgb(channels));
|
|
CHECK(0xffffff == ncchannels_bg_rgb(channels));
|
|
CHECK(0 == ncplane_destroy(top));
|
|
CHECK(0 == ncplane_destroy(newn));
|
|
}
|
|
|
|
SUBCASE("StackedQuadHalves") {
|
|
if(notcurses_canquadrant(nc_)){
|
|
struct ncplane_options opts = {
|
|
0, 0, 1, 1, nullptr, "top", nullptr, 0, 0, 0,
|
|
};
|
|
auto top = ncplane_create(n_, &opts);
|
|
REQUIRE(nullptr != top);
|
|
// create an ncvisual of 2 rows, 2 columns, with the top 0xffffff
|
|
const uint32_t topv[] = {htole(0xff00ff00), htole(0xff00ff00), htole(0), htole(0)};
|
|
auto ncv = ncvisual_from_rgba(topv, 2, 8, 2);
|
|
REQUIRE(nullptr != ncv);
|
|
struct ncvisual_options vopts = {
|
|
.n = top, .scaling = NCSCALE_NONE, .y = 0, .x = 0, .begy = 0, .begx = 0,
|
|
.leny = 2, .lenx = 2, .blitter = NCBLIT_2x2, .flags = 0,
|
|
.transcolor = 0, .pxoffy = 0, .pxoffx = 0,
|
|
};
|
|
CHECK(top == ncvisual_blit(nc_, ncv, &vopts));
|
|
ncvisual_destroy(ncv);
|
|
|
|
// create an ncvisual of 2 rows, 2 columns, with the bottom 0xffffff
|
|
const uint32_t botv[] = {htole(0), htole(0), htole(0xff00ff00), htole(0xff00ff00)};
|
|
ncv = ncvisual_from_rgba(botv, 2, 8, 2);
|
|
REQUIRE(nullptr != ncv);
|
|
vopts.n = n_;
|
|
vopts.flags = NCVISUAL_OPTION_CHILDPLANE;
|
|
auto newn = ncvisual_blit(nc_, ncv, &vopts);
|
|
REQUIRE(nullptr != newn);
|
|
ncvisual_destroy(ncv);
|
|
ncplane_move_below(newn, top);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
uint64_t channels;
|
|
auto egc = notcurses_at_yx(nc_, 0, 0, nullptr, &channels);
|
|
REQUIRE(nullptr != egc);
|
|
CHECK(0 == strcmp(u8" ", egc));
|
|
free(egc);
|
|
CHECK(0x00ff00 == ncchannels_fg_rgb(channels));
|
|
CHECK(0x00ff00 == ncchannels_bg_rgb(channels));
|
|
CHECK(0 == ncplane_destroy(top));
|
|
CHECK(0 == ncplane_destroy(newn));
|
|
}
|
|
}
|
|
|
|
SUBCASE("StackedQuadCrossed") {
|
|
if(notcurses_canquadrant(nc_)){
|
|
ncplane_erase(n_);
|
|
notcurses_refresh(nc_, nullptr, nullptr);
|
|
struct ncplane_options opts = {
|
|
0, 0, 1, 1, nullptr, "top", nullptr, 0, 0, 0,
|
|
};
|
|
auto top = ncplane_create(n_, &opts);
|
|
REQUIRE(nullptr != top);
|
|
// create an ncvisual of 2 rows, 2 columns, with the tl, br 0xffffff
|
|
const uint32_t topv[] = {htole(0xffffffff), htole(0), htole(0), htole(0xffffffff)};
|
|
auto ncv = ncvisual_from_rgba(topv, 2, 8, 2);
|
|
REQUIRE(nullptr != ncv);
|
|
struct ncvisual_options vopts = {
|
|
.n = top, .scaling = NCSCALE_NONE, .y = 0, .x = 0, .begy = 0, .begx = 0,
|
|
.leny = 2, .lenx = 2, .blitter = NCBLIT_2x2, .flags = 0,
|
|
.transcolor = 0, .pxoffy = 0, .pxoffx = 0,
|
|
};
|
|
CHECK(top == ncvisual_blit(nc_, ncv, &vopts));
|
|
ncvisual_destroy(ncv);
|
|
|
|
// create an ncvisual of 2 rows, 2 columns, with the tr, bl 0xffffff
|
|
const uint32_t botv[] = {htole(0), htole(0xffffffff), htole(0xffffffff), htole(0)};
|
|
ncv = ncvisual_from_rgba(botv, 2, 8, 2);
|
|
REQUIRE(nullptr != ncv);
|
|
vopts.n = n_;
|
|
vopts.flags = NCVISUAL_OPTION_CHILDPLANE;
|
|
auto newn = ncvisual_blit(nc_, ncv, &vopts);
|
|
REQUIRE(nullptr != newn);
|
|
ncvisual_destroy(ncv);
|
|
ncplane_move_below(newn, top);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
uint64_t channels;
|
|
auto egc = notcurses_at_yx(nc_, 0, 0, nullptr, &channels);
|
|
REQUIRE(nullptr != egc);
|
|
CHECK(0 == strcmp(u8" ", egc)); // quadrant upper left and lower right
|
|
free(egc);
|
|
CHECK(0xffffff == ncchannels_fg_rgb(channels));
|
|
CHECK(0xffffff == ncchannels_bg_rgb(channels));
|
|
CHECK(0 == ncplane_destroy(top));
|
|
CHECK(0 == ncplane_destroy(newn));
|
|
}
|
|
}
|
|
|
|
// common teardown
|
|
CHECK(0 == notcurses_stop(nc_));
|
|
}
|