|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
|
|
void BoxPermutationsRounded(struct notcurses* nc, struct ncplane* n, unsigned edges) {
|
|
|
|
|
unsigned dimx, dimy;
|
|
|
|
|
ncplane_dim_yx(n, &dimy, &dimx);
|
|
|
|
|
REQUIRE(2 < dimy);
|
|
|
|
|
REQUIRE(47 < dimx);
|
|
|
|
|
// we'll try all 16 boxmasks in 3x3 configurations in a 1x16 map
|
|
|
|
|
unsigned boxmask = edges << NCBOXCORNER_SHIFT;
|
|
|
|
|
for(auto x0 = 0 ; x0 < 16 ; ++x0){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n, 0, x0 * 3));
|
|
|
|
|
CHECK(0 == ncplane_rounded_box_sized(n, 0, 0, 3, 3, boxmask));
|
|
|
|
|
++boxmask;
|
|
|
|
|
}
|
|
|
|
|
CHECK(0 == notcurses_render(nc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_CASE("Plane") {
|
|
|
|
|
auto nc_ = testing_notcurses();
|
|
|
|
|
if(!nc_){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(!notcurses_canutf8(nc_)){
|
|
|
|
|
CHECK(0 == notcurses_stop(nc_));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
struct ncplane* n_ = notcurses_stdplane(nc_);
|
|
|
|
|
REQUIRE(n_);
|
|
|
|
|
|
|
|
|
|
// Starting position ought be 0, 0 (the origin)
|
|
|
|
|
SUBCASE("StdPlanePosition") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(0 == x);
|
|
|
|
|
CHECK(0 == y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dimensions of the standard plane ought be the same as those of the context
|
|
|
|
|
SUBCASE("StdPlaneDimensions") {
|
|
|
|
|
unsigned cols, rows;
|
|
|
|
|
notcurses_term_dim_yx(nc_, &rows, &cols);
|
|
|
|
|
unsigned ncols, nrows;
|
|
|
|
|
ncplane_dim_yx(n_, &nrows, &ncols);
|
|
|
|
|
CHECK(rows == nrows);
|
|
|
|
|
CHECK(cols == ncols);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify that we can move to all four coordinates of the standard plane
|
|
|
|
|
SUBCASE("MoveStdPlaneDimensions") {
|
|
|
|
|
unsigned cols, rows;
|
|
|
|
|
notcurses_term_dim_yx(nc_, &rows, &cols);
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(y == 0);
|
|
|
|
|
CHECK(x == 0);
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, rows - 1, 0));
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(y == rows - 1);
|
|
|
|
|
CHECK(x == 0);
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, rows - 1, cols - 1));
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(y == rows - 1);
|
|
|
|
|
CHECK(x == cols - 1);
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 0, cols - 1));
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(y == 0);
|
|
|
|
|
CHECK(x == cols - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify that we can move to all four coordinates of the standard plane
|
|
|
|
|
SUBCASE("MoveBeyondPlaneFails") {
|
|
|
|
|
unsigned cols, rows;
|
|
|
|
|
notcurses_term_dim_yx(nc_, &rows, &cols);
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, -2, 0));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, -2, -2));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, 0, -2));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, rows - 1, -2));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, rows, 0));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, rows + 1, 0));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, rows, cols));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, -2, cols - 1));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, 0, cols));
|
|
|
|
|
CHECK(0 > ncplane_cursor_move_yx(n_, 0, cols + 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("SetPlaneRGB") {
|
|
|
|
|
CHECK(0 == ncplane_set_fg_rgb8(n_, 0, 0, 0));
|
|
|
|
|
CHECK(0 == ncplane_set_fg_rgb8(n_, 255, 255, 255));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("RejectBadRGB") {
|
|
|
|
|
CHECK(0 > ncplane_set_fg_rgb8(n_, -1, 0, 0));
|
|
|
|
|
CHECK(0 > ncplane_set_fg_rgb8(n_, 0, -1, 0));
|
|
|
|
|
CHECK(0 > ncplane_set_fg_rgb8(n_, 0, 0, -1));
|
|
|
|
|
CHECK(0 > ncplane_set_fg_rgb8(n_, -1, -1, -1));
|
|
|
|
|
CHECK(0 > ncplane_set_fg_rgb8(n_, 256, 255, 255));
|
|
|
|
|
CHECK(0 > ncplane_set_fg_rgb8(n_, 255, 256, 255));
|
|
|
|
|
CHECK(0 > ncplane_set_fg_rgb8(n_, 255, 255, 256));
|
|
|
|
|
CHECK(0 > ncplane_set_fg_rgb8(n_, 256, 256, 256));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("StandardPlaneChild") {
|
|
|
|
|
struct ncplane_options nopts{};
|
|
|
|
|
nopts.rows = ncplane_dim_y(n_);
|
|
|
|
|
nopts.cols = ncplane_dim_x(n_);
|
|
|
|
|
auto n = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(nullptr != n);
|
|
|
|
|
CHECK(ncplane_dim_y(n) == ncplane_dim_y(n_));
|
|
|
|
|
CHECK(ncplane_dim_x(n) == ncplane_dim_x(n_));
|
|
|
|
|
CHECK(0 == ncplane_destroy(n));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify we can emit a NUL character, and it advances the cursor after
|
|
|
|
|
// wiping out whatever we printed it atop.
|
|
|
|
|
SUBCASE("EmitNULCell") {
|
|
|
|
|
nccell c = CELL_CHAR_INITIALIZER('a');
|
|
|
|
|
CHECK(0 < ncplane_putc_yx(n_, 0, 0, &c));
|
|
|
|
|
auto egc = ncplane_at_yx(n_, 0, 0, nullptr, nullptr);
|
|
|
|
|
CHECK(0 == strcmp("a", egc));
|
|
|
|
|
free(egc);
|
|
|
|
|
unsigned y, x;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(0 == y);
|
|
|
|
|
CHECK(1 == x);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
c = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
CHECK(0 < ncplane_putc_yx(n_, 0, 0, &c));
|
|
|
|
|
egc = ncplane_at_yx(n_, 0, 0, nullptr, nullptr);
|
|
|
|
|
CHECK(0 == strcmp("", egc));
|
|
|
|
|
free(egc);
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(0 == y);
|
|
|
|
|
CHECK(1 == x);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify we can emit a multibyte character, and it advances the cursor
|
|
|
|
|
SUBCASE("EmitCell") {
|
|
|
|
|
const char cchar[] = "✔";
|
|
|
|
|
nccell c{};
|
|
|
|
|
CHECK(strlen(cchar) == nccell_load(n_, &c, cchar));
|
|
|
|
|
CHECK(0 < ncplane_putc(n_, &c));
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(0 == y);
|
|
|
|
|
CHECK(1 == x);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify we can emit a wchar_t, and it advances the cursor
|
|
|
|
|
SUBCASE("EmitWcharT") {
|
|
|
|
|
const wchar_t* w = L"✔";
|
|
|
|
|
CHECK(0 < ncplane_putwegc(n_, w, nullptr));
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(0 == y);
|
|
|
|
|
CHECK(1 == x);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify we can emit a multibyte string, and it advances the cursor
|
|
|
|
|
SUBCASE("EmitStr") {
|
|
|
|
|
const char* ss[] = { "Σιβυλλα τι θελεις;",
|
|
|
|
|
" respondebat illa:",
|
|
|
|
|
" αποθανειν θελω.", NULL };
|
|
|
|
|
for(const char** s = ss ; *s ; ++s){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, s - ss, 0));
|
|
|
|
|
int wrote = ncplane_putstr(n_, *s);
|
|
|
|
|
CHECK(ncstrwidth(*s) == wrote);
|
|
|
|
|
}
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(2 == y);
|
|
|
|
|
CHECK(10 <= x);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify we can emit a wide string, and it advances the cursor
|
|
|
|
|
SUBCASE("EmitWideStr") {
|
|
|
|
|
const wchar_t* ss[] = { L"Σιβυλλα τι θελεις;",
|
|
|
|
|
L" respondebat illa:",
|
|
|
|
|
L" αποθανειν θελω.", NULL };
|
|
|
|
|
for(const wchar_t** s = ss ; *s ; ++s){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, s - ss, 0));
|
|
|
|
|
int wrote = ncplane_putwstr(n_, *s);
|
|
|
|
|
CHECK(0 < wrote);
|
|
|
|
|
}
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(2 == y);
|
|
|
|
|
CHECK(10 <= x);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// some aren't yet proper wcwidth() on ubuntu FIXME
|
|
|
|
|
//"🐯🐰🐱🐲🐳🐴🐵🐶🐷🐹🐺🐻🐼🦉🐊🦕🦖🐬🐙🦠🦀";
|
|
|
|
|
SUBCASE("EmitEmojiStr") {
|
|
|
|
|
const wchar_t e[] =
|
|
|
|
|
L"🍺🚬🌿💉💊🔫💣🤜🤛🐌🐎🐑🐒🐔🐗🐘🐙🐚"
|
|
|
|
|
"🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐫🐬🐭🐮";
|
|
|
|
|
CHECK(!ncplane_set_scrolling(n_, true));
|
|
|
|
|
int wrote = ncplane_putwstr(n_, e);
|
|
|
|
|
CHECK(0 < wrote);
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK_LE(0, y);
|
|
|
|
|
CHECK(1 <= x); // FIXME tighten in on this
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("HorizontalLines") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_dim_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(0 < y);
|
|
|
|
|
REQUIRE(0 < x);
|
|
|
|
|
nccell c{};
|
|
|
|
|
nccell_load(n_, &c, "-");
|
|
|
|
|
for(unsigned yidx = 0 ; yidx < y ; ++yidx){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, yidx, 1));
|
|
|
|
|
CHECK(x - 2 == ncplane_hline(n_, &c, x - 2));
|
|
|
|
|
unsigned posx, posy;
|
|
|
|
|
ncplane_cursor_yx(n_, &posy, &posx);
|
|
|
|
|
CHECK(yidx == posy);
|
|
|
|
|
CHECK(x - 1 == posx);
|
|
|
|
|
}
|
|
|
|
|
nccell_release(n_, &c);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("VerticalLines") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_dim_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(0 < y);
|
|
|
|
|
REQUIRE(0 < x);
|
|
|
|
|
nccell c{};
|
|
|
|
|
nccell_load(n_, &c, "|");
|
|
|
|
|
for(unsigned xidx = 1 ; xidx < x - 1 ; ++xidx){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 1, xidx));
|
|
|
|
|
CHECK(y - 2 == ncplane_vline(n_, &c, y - 2));
|
|
|
|
|
unsigned posx, posy;
|
|
|
|
|
ncplane_cursor_yx(n_, &posy, &posx);
|
|
|
|
|
CHECK(y - 2 == posy);
|
|
|
|
|
CHECK(xidx == posx - 1);
|
|
|
|
|
}
|
|
|
|
|
nccell_release(n_, &c);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// reject attempts to draw boxes beyond the boundaries of the ncplane
|
|
|
|
|
SUBCASE("BadlyPlacedBoxen") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_dim_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(2 < y);
|
|
|
|
|
REQUIRE(2 < x);
|
|
|
|
|
nccell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
|
|
|
|
|
REQUIRE(0 == nccells_rounded_box(n_, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl));
|
|
|
|
|
CHECK_GT(0, ncplane_box(n_, &ul, &ur, &ll, &lr, &hl, &vl, y + 1, x + 1, 0));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 1, 0));
|
|
|
|
|
CHECK_GT(0, ncplane_box(n_, &ul, &ur, &ll, &lr, &hl, &vl, y, x, 0));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 0, 1));
|
|
|
|
|
CHECK_GT(0, ncplane_box(n_, &ul, &ur, &ll, &lr, &hl, &vl, y, x, 0));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y - 1, x - 1));
|
|
|
|
|
CHECK_GT(0, ncplane_box(n_, &ul, &ur, &ll, &lr, &hl, &vl, 2, 2, 0));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y - 2, x - 1));
|
|
|
|
|
CHECK_GT(0, ncplane_box(n_, &ul, &ur, &ll, &lr, &hl, &vl, 2, 2, 0));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y - 1, x - 2));
|
|
|
|
|
CHECK_GT(0, ncplane_box(n_, &ul, &ur, &ll, &lr, &hl, &vl, 2, 2, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoxPermutationsRoundedZeroEdges") {
|
|
|
|
|
BoxPermutationsRounded(nc_, n_, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoxPermutationsRoundedOneEdges") {
|
|
|
|
|
BoxPermutationsRounded(nc_, n_, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoxPermutationsRoundedTwoEdges") {
|
|
|
|
|
BoxPermutationsRounded(nc_, n_, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoxPermutationsRoundedThreeEdges") {
|
|
|
|
|
BoxPermutationsRounded(nc_, n_, 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoxPermutationsDouble") {
|
|
|
|
|
unsigned dimx, dimy;
|
|
|
|
|
ncplane_dim_yx(n_, &dimy, &dimx);
|
|
|
|
|
REQUIRE(2 < dimx);
|
|
|
|
|
REQUIRE(47 < dimx);
|
|
|
|
|
// we'll try all 16 boxmasks in 3x3 configurations in a 1x16 map
|
|
|
|
|
unsigned boxmask = 0;
|
|
|
|
|
for(auto x0 = 0 ; x0 < 16 ; ++x0){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 0, x0 * 3));
|
|
|
|
|
CHECK(0 == ncplane_double_box_sized(n_, 0, 0, 3, 3, boxmask));
|
|
|
|
|
++boxmask;
|
|
|
|
|
}
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("PerimeterRoundedBox") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_dim_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(2 < y);
|
|
|
|
|
REQUIRE(2 < x);
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
CHECK(0 == ncplane_rounded_box(n_, 0, 0, y - 1, x - 1, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("PerimeterRoundedBoxSized") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_dim_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(2 < y);
|
|
|
|
|
REQUIRE(2 < x);
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
CHECK(0 == ncplane_rounded_box_sized(n_, 0, 0, y, x, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("PerimeterDoubleBox") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_dim_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(2 < y);
|
|
|
|
|
REQUIRE(2 < x);
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
CHECK(0 == ncplane_double_box(n_, 0, 0, y - 1, x - 1, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("PerimeterDoubleBoxSized") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
ncplane_dim_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(2 < y);
|
|
|
|
|
REQUIRE(2 < x);
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
CHECK(0 == ncplane_double_box_sized(n_, 0, 0, y, x, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("EraseScreen") {
|
|
|
|
|
ncplane_erase(n_);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we're gonna run both a composed latin a with grave, and then a latin a with
|
|
|
|
|
// a combining nonspacing grave
|
|
|
|
|
SUBCASE("CellLoadCombining") {
|
|
|
|
|
const char* w1 = "à"; // U+00E0, U+0000 (c3 a0)
|
|
|
|
|
const char* w2 = "à"; // U+0061, U+0300, U+0000 (61 cc 80)
|
|
|
|
|
const char* w3 = "a"; // U+0061, U+0000 (61)
|
|
|
|
|
nccell cell1 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
nccell cell2 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
nccell cell3 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
auto u1 = nccell_load(n_, &cell1, w1);
|
|
|
|
|
auto u2 = nccell_load(n_, &cell2, w2);
|
|
|
|
|
auto u3 = nccell_load(n_, &cell3, w3);
|
|
|
|
|
REQUIRE(2 == u1);
|
|
|
|
|
REQUIRE(3 == u2);
|
|
|
|
|
REQUIRE(1 == u3);
|
|
|
|
|
nccell_release(n_, &cell1);
|
|
|
|
|
nccell_release(n_, &cell2);
|
|
|
|
|
nccell_release(n_, &cell3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("CellDuplicateCombining") {
|
|
|
|
|
const char* w1 = "à"; // U+00E0, U+0000 (c3 a0)
|
|
|
|
|
const char* w2 = "à"; // U+0061, U+0300, U+0000 (61 cc 80)
|
|
|
|
|
const char* w3 = "a"; // U+0061, U+0000 (61)
|
|
|
|
|
nccell cell1 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
nccell cell2 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
nccell cell3 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
auto u1 = nccell_load(n_, &cell1, w1);
|
|
|
|
|
auto u2 = nccell_load(n_, &cell2, w2);
|
|
|
|
|
auto u3 = nccell_load(n_, &cell3, w3);
|
|
|
|
|
REQUIRE(2 == u1);
|
|
|
|
|
REQUIRE(3 == u2);
|
|
|
|
|
REQUIRE(1 == u3);
|
|
|
|
|
nccell cell4 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
nccell cell5 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
nccell cell6 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
CHECK(0 == nccell_duplicate(n_, &cell4, &cell1));
|
|
|
|
|
CHECK(0 == nccell_duplicate(n_, &cell5, &cell2));
|
|
|
|
|
CHECK(0 == nccell_duplicate(n_, &cell6, &cell3));
|
|
|
|
|
nccell_release(n_, &cell1);
|
|
|
|
|
nccell_release(n_, &cell2);
|
|
|
|
|
nccell_release(n_, &cell3);
|
|
|
|
|
nccell_release(n_, &cell4);
|
|
|
|
|
nccell_release(n_, &cell5);
|
|
|
|
|
nccell_release(n_, &cell6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("CellMultiColumn") {
|
|
|
|
|
const char* w1 = "\xf0\x9f\x91\xa9"; // U+1F469 WOMAN
|
|
|
|
|
const char* w2 = "N";
|
|
|
|
|
nccell c1 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
nccell c2 = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
auto u1 = nccell_load(n_, &c1, w1);
|
|
|
|
|
auto u2 = nccell_load(n_, &c2, w2);
|
|
|
|
|
REQUIRE(0 < u1);
|
|
|
|
|
REQUIRE(0 < u2);
|
|
|
|
|
REQUIRE(strlen(w1) == u1);
|
|
|
|
|
REQUIRE(strlen(w2) == u2);
|
|
|
|
|
CHECK(ncstrwidth(w1) == 1 + nccell_double_wide_p(&c1));
|
|
|
|
|
CHECK_FALSE(nccell_double_wide_p(&c2));
|
|
|
|
|
nccell_release(n_, &c1);
|
|
|
|
|
nccell_release(n_, &c2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// verifies that the initial userptr is what we provided, that it is a nullptr
|
|
|
|
|
// for the standard plane, and that we can change it.
|
|
|
|
|
SUBCASE("UserPtr") {
|
|
|
|
|
CHECK(nullptr == ncplane_userptr(n_));
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
void* sentinel = &x;
|
|
|
|
|
notcurses_term_dim_yx(nc_, &y, &x);
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 0,
|
|
|
|
|
.x = 0,
|
|
|
|
|
.rows = y,
|
|
|
|
|
.cols = x,
|
|
|
|
|
.userptr = sentinel,
|
|
|
|
|
.name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ncp = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(ncp);
|
|
|
|
|
CHECK(&x == ncplane_userptr(ncp));
|
|
|
|
|
CHECK(sentinel == ncplane_set_userptr(ncp, nullptr));
|
|
|
|
|
CHECK(nullptr == ncplane_userptr(ncp));
|
|
|
|
|
sentinel = &y;
|
|
|
|
|
CHECK(nullptr == ncplane_set_userptr(ncp, sentinel));
|
|
|
|
|
CHECK(&y == ncplane_userptr(ncp));
|
|
|
|
|
CHECK(0 == ncplane_destroy(ncp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create a new plane, the same size as the terminal, and verify that it
|
|
|
|
|
// occupies the same dimensions as the standard plane.
|
|
|
|
|
SUBCASE("NewPlaneSameSize") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
notcurses_term_dim_yx(nc_, &y, &x);
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 0,
|
|
|
|
|
.x = 0,
|
|
|
|
|
.rows = y,
|
|
|
|
|
.cols = x,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ncp = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(ncp);
|
|
|
|
|
unsigned px, py;
|
|
|
|
|
ncplane_dim_yx(ncp, &py, &px);
|
|
|
|
|
CHECK(y == py);
|
|
|
|
|
CHECK(x == px);
|
|
|
|
|
unsigned sx, sy;
|
|
|
|
|
ncplane_dim_yx(n_, &sy, &sx);
|
|
|
|
|
CHECK(sy == py);
|
|
|
|
|
CHECK(sx == px);
|
|
|
|
|
CHECK(0 == ncplane_destroy(ncp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create a new plane, the same size as the terminal, and verify that it
|
|
|
|
|
// occupies the same dimensions as the standard plane, but on another pile.
|
|
|
|
|
SUBCASE("NewPileSameSize") {
|
|
|
|
|
unsigned x, y;
|
|
|
|
|
notcurses_term_dim_yx(nc_, &y, &x);
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 0,
|
|
|
|
|
.x = 0,
|
|
|
|
|
.rows = y,
|
|
|
|
|
.cols = x,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ncp = ncpile_create(nc_, &nopts);
|
|
|
|
|
REQUIRE(ncp);
|
|
|
|
|
unsigned px, py;
|
|
|
|
|
ncplane_dim_yx(ncp, &py, &px);
|
|
|
|
|
CHECK(y == py);
|
|
|
|
|
CHECK(x == px);
|
|
|
|
|
unsigned sx, sy;
|
|
|
|
|
ncplane_dim_yx(n_, &sy, &sx);
|
|
|
|
|
CHECK(sy == py);
|
|
|
|
|
CHECK(sx == px);
|
|
|
|
|
// ensure that the new plane is not on our zaxis
|
|
|
|
|
CHECK(notcurses_top(nc_) == n_);
|
|
|
|
|
CHECK(notcurses_bottom(nc_) == n_);
|
|
|
|
|
// ensure the new plane has null above and below, and is bound to itself
|
|
|
|
|
CHECK(ncplane_above(ncp) == nullptr);
|
|
|
|
|
CHECK(ncplane_below(ncp) == nullptr);
|
|
|
|
|
CHECK(ncplane_parent_const(ncp) == ncp);
|
|
|
|
|
CHECK(0 == ncplane_destroy(ncp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("ShrinkPlane") {
|
|
|
|
|
unsigned maxx, maxy;
|
|
|
|
|
int x = 0, y = 0;
|
|
|
|
|
notcurses_term_dim_yx(nc_, &maxy, &maxx);
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = y,
|
|
|
|
|
.x = x,
|
|
|
|
|
.rows = maxy,
|
|
|
|
|
.cols = maxx,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* newp = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(newp);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
while(y > 4 && x > 4){
|
|
|
|
|
maxx -= 2;
|
|
|
|
|
maxy -= 2;
|
|
|
|
|
++x;
|
|
|
|
|
++y;
|
|
|
|
|
REQUIRE(0 == ncplane_resize(newp, 1, 1, maxy, maxx, 1, 1, maxy, maxx));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
// FIXME check dims, pos
|
|
|
|
|
}
|
|
|
|
|
while(y > 4){
|
|
|
|
|
maxy -= 2;
|
|
|
|
|
++y;
|
|
|
|
|
REQUIRE(0 == ncplane_resize(newp, 1, 0, maxy, maxx, 1, 0, maxy, maxx));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
// FIXME check dims, pos
|
|
|
|
|
}
|
|
|
|
|
while(x > 4){
|
|
|
|
|
maxx -= 2;
|
|
|
|
|
++x;
|
|
|
|
|
REQUIRE(0 == ncplane_resize(newp, 0, 1, maxy, maxx, 0, 1, maxy, maxx));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
// FIXME check dims, pos
|
|
|
|
|
}
|
|
|
|
|
REQUIRE(0 == ncplane_resize(newp, 0, 0, 0, 0, 0, 0, 2, 2));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
// FIXME check dims, pos
|
|
|
|
|
REQUIRE(0 == ncplane_destroy(newp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("GrowPlane") {
|
|
|
|
|
unsigned maxx = 2, maxy = 2;
|
|
|
|
|
int x = 0, y = 0;
|
|
|
|
|
unsigned dimy, dimx;
|
|
|
|
|
notcurses_term_dim_yx(nc_, &dimy, &dimx);
|
|
|
|
|
x = dimx / 2 - 1;
|
|
|
|
|
y = dimy / 2 - 1;
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = y,
|
|
|
|
|
.x = x,
|
|
|
|
|
.rows = maxy,
|
|
|
|
|
.cols = maxx,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* newp = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(newp);
|
|
|
|
|
while(dimx - maxx > 4 && dimy - maxy > 4){
|
|
|
|
|
maxx += 2;
|
|
|
|
|
maxy += 2;
|
|
|
|
|
--x;
|
|
|
|
|
--y;
|
|
|
|
|
REQUIRE(0 == ncplane_resize(newp, 1, 1, maxy - 3, maxx - 3, 1, 1, maxy, maxx));
|
|
|
|
|
// FIXME check dims, pos
|
|
|
|
|
}
|
|
|
|
|
while(y < static_cast<int>(dimy)){
|
|
|
|
|
++maxy;
|
|
|
|
|
if(y){
|
|
|
|
|
++y;
|
|
|
|
|
}
|
|
|
|
|
REQUIRE(0 == ncplane_resize(newp, 1, 0, maxy - 2, maxx, 1, 0, maxy, maxx));
|
|
|
|
|
// FIXME check dims, pos
|
|
|
|
|
}
|
|
|
|
|
while(x < static_cast<int>(dimx)){
|
|
|
|
|
++maxx;
|
|
|
|
|
if(x){
|
|
|
|
|
++x;
|
|
|
|
|
}
|
|
|
|
|
REQUIRE(0 == ncplane_resize(newp, 0, 1, maxy, maxx - 2, 0, 1, maxy, maxx));
|
|
|
|
|
// FIXME check dims, pos
|
|
|
|
|
}
|
|
|
|
|
REQUIRE(0 == ncplane_resize(newp, 0, 0, 0, 0, 0, 0, dimy, dimx));
|
|
|
|
|
// FIXME check dims, pos
|
|
|
|
|
REQUIRE(0 == ncplane_destroy(newp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we ought be able to see what we're about to render, or have just rendered, or
|
|
|
|
|
// in any case whatever's in the virtual framebuffer for a plane
|
|
|
|
|
SUBCASE("PlaneAtCursorSimples"){
|
|
|
|
|
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_set_styles(n_, NCSCALE_NONE);
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
REQUIRE(0 < ncplane_putstr(n_, STR1));
|
|
|
|
|
nccell testcell = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
REQUIRE(0 == ncplane_at_cursor_cell(n_, &testcell)); // want nothing at the cursor
|
|
|
|
|
CHECK(0 == testcell.gcluster);
|
|
|
|
|
CHECK(0 == testcell.stylemask);
|
|
|
|
|
CHECK(0 == testcell.channels);
|
|
|
|
|
nccell_release(n_, &testcell);
|
|
|
|
|
unsigned dimy, dimx;
|
|
|
|
|
ncplane_dim_yx(n_, &dimy, &dimx);
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - strlen(STR2)));
|
|
|
|
|
REQUIRE(0 < ncplane_putstr(n_, STR2));
|
|
|
|
|
unsigned y, x;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(1 == y);
|
|
|
|
|
REQUIRE(dimx == x);
|
|
|
|
|
// this ought not print anything, since we're at the end of the row
|
|
|
|
|
REQUIRE(0 == ncplane_putstr(n_, STR3));
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell)); // want first char of STR1
|
|
|
|
|
CHECK(htole(STR1[0]) == testcell.gcluster);
|
|
|
|
|
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(htole(STR2[strlen(STR2) - 1]) == testcell.gcluster);
|
|
|
|
|
CHECK(0 == testcell.stylemask);
|
|
|
|
|
CHECK(0 == testcell.channels);
|
|
|
|
|
// FIXME maybe check all cells?
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ensure we read back what's expected for latinesque complex characters
|
|
|
|
|
SUBCASE("PlaneAtCursorComplex"){
|
|
|
|
|
const char STR1[] = "Σιβυλλα τι θελεις; respondebat illa:";
|
|
|
|
|
const char STR2[] = "αποθανειν θελω";
|
|
|
|
|
const char STR3[] = "Война и мир"; // just thrown in to complicate things
|
|
|
|
|
ncplane_set_styles(n_, NCSTYLE_NONE);
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
REQUIRE(0 < ncplane_putstr(n_, STR1));
|
|
|
|
|
nccell testcell = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
ncplane_at_cursor_cell(n_, &testcell); // should be nothing at the cursor
|
|
|
|
|
CHECK(0 == testcell.gcluster);
|
|
|
|
|
CHECK(0 == testcell.stylemask);
|
|
|
|
|
CHECK(0 == testcell.channels);
|
|
|
|
|
nccell_release(n_, &testcell);
|
|
|
|
|
unsigned dimy, dimx;
|
|
|
|
|
ncplane_dim_yx(n_, &dimy, &dimx);
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 1, dimx - mbstowcs(nullptr, STR2, 0)));
|
|
|
|
|
REQUIRE(0 < ncplane_putstr(n_, STR2));
|
|
|
|
|
unsigned y, x;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
REQUIRE(1 == y);
|
|
|
|
|
REQUIRE(dimx == x);
|
|
|
|
|
// this ought not print anything, since we're at the end of the row
|
|
|
|
|
REQUIRE(0 == ncplane_putstr(n_, STR3));
|
|
|
|
|
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
REQUIRE(0 < ncplane_at_cursor_cell(n_, &testcell)); // want first char of STR1
|
|
|
|
|
CHECK(!strcmp("Σ", nccell_extended_gcluster(n_, &testcell)));
|
|
|
|
|
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("α", nccell_extended_gcluster(n_, &testcell)));
|
|
|
|
|
CHECK(0 == testcell.stylemask);
|
|
|
|
|
CHECK(0 == testcell.channels);
|
|
|
|
|
// FIXME maybe check all cells?
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// test that we read back correct attrs/colors despite changing defaults
|
|
|
|
|
SUBCASE("PlaneAtCursorAttrs"){
|
|
|
|
|
const char STR1[] = "this was a world destroyer prod";
|
|
|
|
|
const char STR2[] = "not to mention dank";
|
|
|
|
|
const char STR3[] = "da chronic lives";
|
|
|
|
|
ncplane_set_styles(n_, NCSTYLE_BOLD);
|
|
|
|
|
REQUIRE(0 < ncplane_putstr_yx(n_, 0, 0, STR1));
|
|
|
|
|
unsigned y, x;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &x);
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y + 1, x - strlen(STR2)));
|
|
|
|
|
ncplane_on_styles(n_, NCSTYLE_ITALIC);
|
|
|
|
|
REQUIRE(0 < ncplane_putstr(n_, STR2));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y + 2, x - strlen(STR3)));
|
|
|
|
|
ncplane_off_styles(n_, NCSTYLE_BOLD);
|
|
|
|
|
REQUIRE(0 < ncplane_putstr(n_, STR3));
|
|
|
|
|
ncplane_off_styles(n_, NCSTYLE_ITALIC);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
unsigned newx;
|
|
|
|
|
ncplane_cursor_yx(n_, &y, &newx);
|
|
|
|
|
CHECK(newx == x);
|
|
|
|
|
nccell testcell = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y - 2, x - 1));
|
|
|
|
|
REQUIRE(1 == ncplane_at_cursor_cell(n_, &testcell));
|
|
|
|
|
CHECK(testcell.gcluster == htole(STR1[strlen(STR1) - 1]));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y - 1, x - 1));
|
|
|
|
|
REQUIRE(1 == ncplane_at_cursor_cell(n_, &testcell));
|
|
|
|
|
CHECK(testcell.gcluster == htole(STR2[strlen(STR2) - 1]));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y, x - 1));
|
|
|
|
|
REQUIRE(1 == ncplane_at_cursor_cell(n_, &testcell));
|
|
|
|
|
CHECK(testcell.gcluster == htole(STR3[strlen(STR3) - 1]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoxGradients") {
|
|
|
|
|
const auto sidesz = 5;
|
|
|
|
|
unsigned dimx, dimy;
|
|
|
|
|
ncplane_dim_yx(n_, &dimy, &dimx);
|
|
|
|
|
REQUIRE(20 < dimy);
|
|
|
|
|
REQUIRE(40 < dimx);
|
|
|
|
|
nccell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
|
|
|
|
|
REQUIRE(0 == nccells_double_box(n_, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&ul.channels, 255, 0, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&ur.channels, 0, 255, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&ll.channels, 0, 0, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&lr.channels, 255, 255, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&ul.channels, 0, 255, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&ur.channels, 255, 0, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&ll.channels, 255, 255, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&lr.channels, 0, 0, 0));
|
|
|
|
|
// we'll try all 16 gradmasks in sideszXsidesz configs in a 4x4 map
|
|
|
|
|
unsigned gradmask = 0;
|
|
|
|
|
for(auto y0 = 0 ; y0 < 4 ; ++y0){
|
|
|
|
|
for(auto x0 = 0 ; x0 < 4 ; ++x0){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y0 * sidesz, x0 * (sidesz + 1)));
|
|
|
|
|
CHECK(0 == ncplane_box_sized(n_, &ul, &ur, &ll, &lr, &hl, &vl,
|
|
|
|
|
sidesz, sidesz, gradmask << 4u));
|
|
|
|
|
++gradmask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
gradmask = 0;
|
|
|
|
|
for(auto y0 = 0 ; y0 < 4 ; ++y0){
|
|
|
|
|
for(auto x0 = 0 ; x0 < 4 ; ++x0){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y0 * sidesz, x0 * (sidesz + 1) + (4 * (sidesz + 1))));
|
|
|
|
|
CHECK(0 == ncplane_box_sized(n_, &ul, &ur, &ll, &lr, &hl, &vl,
|
|
|
|
|
sidesz, sidesz, gradmask << 4u));
|
|
|
|
|
++gradmask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoxSideColors") {
|
|
|
|
|
const auto sidesz = 5;
|
|
|
|
|
unsigned dimx, dimy;
|
|
|
|
|
ncplane_dim_yx(n_, &dimy, &dimx);
|
|
|
|
|
REQUIRE(20 < dimy);
|
|
|
|
|
REQUIRE(40 < dimx);
|
|
|
|
|
nccell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
|
|
|
|
|
REQUIRE(0 == nccells_rounded_box(n_, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl));
|
|
|
|
|
// we'll try all 16 boxmasks in sideszXsidesz configurations in a 4x4 map
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&ul.channels, 255, 0, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&ur.channels, 0, 255, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&ll.channels, 0, 0, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&lr.channels, 0, 0, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&ul.channels, 0, 255, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&ur.channels, 255, 0, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&ll.channels, 255, 255, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&lr.channels, 0, 0, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&hl.channels, 255, 0, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb8(&vl.channels, 255, 255, 255));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&hl.channels, 0, 255, 0));
|
|
|
|
|
CHECK(0 == ncchannels_set_bg_rgb8(&vl.channels, 0, 0, 0));
|
|
|
|
|
for(auto y0 = 0 ; y0 < 4 ; ++y0){
|
|
|
|
|
for(auto x0 = 0 ; x0 < 4 ; ++x0){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y0 * sidesz, x0 * (sidesz + 1)));
|
|
|
|
|
CHECK(0 == ncplane_box_sized(n_, &ul, &ur, &ll, &lr, &hl, &vl,
|
|
|
|
|
sidesz, sidesz, 0));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(auto y0 = 0 ; y0 < 4 ; ++y0){
|
|
|
|
|
for(auto x0 = 0 ; x0 < 4 ; ++x0){
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, y0 * sidesz, x0 * (sidesz + 1) + (4 * (sidesz + 1))));
|
|
|
|
|
CHECK(0 == ncplane_box_sized(n_, &ul, &ur, &ll, &lr, &hl, &vl,
|
|
|
|
|
sidesz, sidesz, 0));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("RightToLeft") {
|
|
|
|
|
// give us some room on both sides
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 1, 5));
|
|
|
|
|
CHECK(0 < ncplane_putegc(n_, "־", nullptr));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 3, 5));
|
|
|
|
|
CHECK(0 < ncplane_putstr(n_, "I write English + מילים בעברית together."));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 5, 5));
|
|
|
|
|
CHECK(0 < ncplane_putstr(n_, "|🔥|I have not yet ־ begun to hack|🔥|"));
|
|
|
|
|
#ifndef __APPLE__ // FIXME
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 7, 5));
|
|
|
|
|
CHECK(0 < ncplane_putstr(n_, "㉀㉁㉂㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌㉍㉎㉏㉐"));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 8, 5));
|
|
|
|
|
CHECK(0 < ncplane_putstr(n_, "㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟"));
|
|
|
|
|
#endif
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("NewPlaneOnRight") {
|
|
|
|
|
unsigned ncols, nrows;
|
|
|
|
|
ncplane_dim_yx(n_, &nrows, &ncols);
|
|
|
|
|
nccell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
|
|
|
|
|
int y, x;
|
|
|
|
|
ncplane_yx(n_, &y, &x);
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = y,
|
|
|
|
|
.x = static_cast<int>(ncols) - 3,
|
|
|
|
|
.rows = 2,
|
|
|
|
|
.cols = 2,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ncp = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(ncp);
|
|
|
|
|
REQUIRE(0 == nccells_rounded_box(ncp, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl));
|
|
|
|
|
CHECK(0 == ncplane_box(ncp, &ul, &ur, &ll, &lr, &hl, &vl, y + 1, x + 1, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
// FIXME verify with ncplane_at_cursor_cell()
|
|
|
|
|
CHECK(0 == ncplane_destroy(ncp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("MoveToLowerRight") {
|
|
|
|
|
unsigned ncols, nrows;
|
|
|
|
|
ncplane_dim_yx(n_, &nrows, &ncols);
|
|
|
|
|
nccell ul{}, ll{}, lr{}, ur{}, hl{}, vl{};
|
|
|
|
|
int y, x;
|
|
|
|
|
ncplane_yx(n_, &y, &x);
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = y,
|
|
|
|
|
.x = x,
|
|
|
|
|
.rows = 2,
|
|
|
|
|
.cols = 2,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ncp = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(ncp);
|
|
|
|
|
REQUIRE(0 == nccells_rounded_box(ncp, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl));
|
|
|
|
|
CHECK(0 == ncplane_box(ncp, &ul, &ur, &ll, &lr, &hl, &vl, y + 1, x + 1, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(0 == ncplane_move_yx(ncp, nrows - 3, ncols - 3));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(0 == ncplane_destroy(ncp));
|
|
|
|
|
// FIXME verify with ncplane_at_cursor_cell()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("Perimeter") {
|
|
|
|
|
nccell c = CELL_CHAR_INITIALIZER('X');
|
|
|
|
|
CHECK(0 == ncplane_perimeter(n_, &c, &c, &c, &c, &c, &c, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("EGCStained") {
|
|
|
|
|
nccell c = CELL_TRIVIAL_INITIALIZER;
|
|
|
|
|
CHECK(0 == ncplane_set_fg_rgb(n_, 0x444444));
|
|
|
|
|
CHECK(1 == ncplane_putegc(n_, "A", nullptr));
|
|
|
|
|
CHECK(0 == ncplane_set_fg_rgb(n_, 0x888888));
|
|
|
|
|
CHECK(1 == ncplane_putegc(n_, "B", nullptr));
|
|
|
|
|
CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
// EGC should change, but not the color
|
|
|
|
|
CHECK(0 == ncplane_set_fg_rgb(n_, 0x222222));
|
|
|
|
|
CHECK(1 == ncplane_putegc_stained(n_, "C", nullptr));
|
|
|
|
|
CHECK(1 == ncplane_putegc_stained(n_, "D", nullptr));
|
|
|
|
|
uint64_t channels = 0;
|
|
|
|
|
CHECK(1 == ncplane_at_yx_cell(n_, 0, 0, &c));
|
|
|
|
|
CHECK(cell_simple_p(&c));
|
|
|
|
|
CHECK(htole('C') == c.gcluster);
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb(&channels, 0x444444));
|
|
|
|
|
CHECK(channels == c.channels);
|
|
|
|
|
CHECK(1 == ncplane_at_yx_cell(n_, 0, 1, &c));
|
|
|
|
|
CHECK(cell_simple_p(&c));
|
|
|
|
|
CHECK(htole('D') == c.gcluster);
|
|
|
|
|
CHECK(0 == ncchannels_set_fg_rgb(&channels, 0x888888));
|
|
|
|
|
CHECK(channels == c.channels);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("MouseEvent") {
|
|
|
|
|
unsigned dimy, dimx;
|
|
|
|
|
notcurses_stddim_yx(nc_, &dimy, &dimx);
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 1,
|
|
|
|
|
.x = 1,
|
|
|
|
|
.rows = 2,
|
|
|
|
|
.cols = 2,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* n = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(n);
|
|
|
|
|
ncinput ni{};
|
|
|
|
|
ni.id = NCKEY_BUTTON1;
|
|
|
|
|
ni.evtype = ncinput::NCTYPE_RELEASE;
|
|
|
|
|
int total = 0;
|
|
|
|
|
for(ni.y = 0 ; ni.y < 5 ; ++ni.y){
|
|
|
|
|
for(ni.x = 0 ; ni.x < 5 ; ++ni.x){
|
|
|
|
|
int y = ni.y, x = ni.x;
|
|
|
|
|
bool p = ncplane_translate_abs(n, &y, &x);
|
|
|
|
|
if(ni.y >= 1 && ni.y <= 2 && ni.x >= 1 && ni.x <= 2){
|
|
|
|
|
CHECK(p);
|
|
|
|
|
}else{
|
|
|
|
|
CHECK(!p);
|
|
|
|
|
}
|
|
|
|
|
++total;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CHECK(25 == total); // make sure x/y never got changed
|
|
|
|
|
CHECK(0 == ncplane_destroy(n));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoundPlaneMoves") {
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 1,
|
|
|
|
|
.x = 1,
|
|
|
|
|
.rows = 2,
|
|
|
|
|
.cols = 2,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ndom = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(ndom);
|
|
|
|
|
struct ncplane* nsub = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(nsub);
|
|
|
|
|
int absy, absx;
|
|
|
|
|
ncplane_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(1 == absy); // actually at 2, 2
|
|
|
|
|
CHECK(1 == absx);
|
|
|
|
|
CHECK(0 == ncplane_move_yx(nsub, -1, -1));
|
|
|
|
|
ncplane_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(-1 == absy); // actually at 0, 0
|
|
|
|
|
CHECK(-1 == absx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("BoundToPlaneMoves") { // bound plane ought move along with plane
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 1,
|
|
|
|
|
.x = 1,
|
|
|
|
|
.rows = 2,
|
|
|
|
|
.cols = 2,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ndom = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(ndom);
|
|
|
|
|
struct ncplane* nsub = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(nsub);
|
|
|
|
|
int absy, absx;
|
|
|
|
|
ncplane_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(1 == absy); // actually at 2, 2
|
|
|
|
|
CHECK(1 == absx);
|
|
|
|
|
CHECK(0 == ncplane_move_yx(ndom, 0, 0));
|
|
|
|
|
ncplane_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(1 == absy);
|
|
|
|
|
CHECK(1 == absx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("UnboundPlaneMoves") { // unbound plane no longer gets pulled along
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 1,
|
|
|
|
|
.x = 1,
|
|
|
|
|
.rows = 2,
|
|
|
|
|
.cols = 2,
|
|
|
|
|
.userptr = nullptr,
|
|
|
|
|
.name = "ndom",
|
|
|
|
|
.resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ndom = ncplane_create(n_, &nopts);
|
|
|
|
|
CHECK(ncplane_pile(ndom) == ncplane_pile(n_));
|
|
|
|
|
REQUIRE(ndom);
|
|
|
|
|
nopts.name = "sub";
|
|
|
|
|
struct ncplane* nsub = ncplane_create(ndom, &nopts);
|
|
|
|
|
CHECK(ncplane_pile(nsub) == ncplane_pile(ndom));
|
|
|
|
|
REQUIRE(nsub);
|
|
|
|
|
int absy, absx;
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
ncplane_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(1 == absy); // relatively at 1, 1
|
|
|
|
|
CHECK(1 == absx);
|
|
|
|
|
ncplane_abs_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(2 == absy); // actually at 2, 2
|
|
|
|
|
CHECK(2 == absx);
|
|
|
|
|
ncplane_reparent(nsub, nsub);
|
|
|
|
|
CHECK(ncplane_pile(nsub) != ncplane_pile(ndom));
|
|
|
|
|
ncplane_abs_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(2 == absy); // now relatively at 1, 1
|
|
|
|
|
CHECK(2 == absx);
|
|
|
|
|
ncplane_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(2 == absy);
|
|
|
|
|
CHECK(2 == absx);
|
|
|
|
|
CHECK(0 == ncplane_move_yx(ndom, 0, 0));
|
|
|
|
|
ncplane_abs_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(2 == absy); // still at 1, 1
|
|
|
|
|
CHECK(2 == absx);
|
|
|
|
|
ncplane_yx(nsub, &absy, &absx);
|
|
|
|
|
CHECK(2 == absy);
|
|
|
|
|
CHECK(2 == absx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("NoReparentStdPlane") {
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 1,
|
|
|
|
|
.x = 1,
|
|
|
|
|
.rows = 2,
|
|
|
|
|
.cols = 2,
|
|
|
|
|
.userptr = nullptr, .name = nullptr, .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
struct ncplane* ndom = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(ndom);
|
|
|
|
|
CHECK(!ncplane_reparent(n_, ndom)); // can't reparent standard plane
|
|
|
|
|
CHECK(ncplane_reparent(ndom, n_)); // *can* reparent *to* standard plane
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("ReparentDeep") {
|
|
|
|
|
struct ncplane_options nopts = {
|
|
|
|
|
.y = 1,
|
|
|
|
|
.x = 1,
|
|
|
|
|
.rows = 2,
|
|
|
|
|
.cols = 2,
|
|
|
|
|
.userptr = nullptr, .name = "new1", .resizecb = nullptr, .flags = 0,
|
|
|
|
|
.margin_b = 0, .margin_r = 0,
|
|
|
|
|
};
|
|
|
|
|
auto n1 = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(n1);
|
|
|
|
|
nopts.name = "new2";
|
|
|
|
|
auto n2 = ncplane_create(n1, &nopts);
|
|
|
|
|
REQUIRE(n2);
|
|
|
|
|
nopts.name = "new3";
|
|
|
|
|
auto n3 = ncplane_create(n2, &nopts);
|
|
|
|
|
REQUIRE(n3);
|
|
|
|
|
CHECK(ncplane_reparent(n1, n3));
|
|
|
|
|
CHECK(ncplane_reparent(n2, n3));
|
|
|
|
|
ncplane_destroy(n3);
|
|
|
|
|
ncplane_destroy(n2);
|
|
|
|
|
ncplane_destroy(n1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// you ought not be able to output control characters
|
|
|
|
|
SUBCASE("DenyControlASCII") {
|
|
|
|
|
signed char c = 0;
|
|
|
|
|
c = -1;
|
|
|
|
|
do{
|
|
|
|
|
++c;
|
|
|
|
|
if(c && !isprint(c)){
|
|
|
|
|
CHECK(0 > ncplane_putchar_yx(n_, 0, 0, c));
|
|
|
|
|
}else{
|
|
|
|
|
CHECK(1 == ncplane_putchar_yx(n_, 0, 0, c));
|
|
|
|
|
}
|
|
|
|
|
}while(c != 127);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// relative moves
|
|
|
|
|
SUBCASE("RelativePlaneMoves") {
|
|
|
|
|
struct ncplane_options nopts{};
|
|
|
|
|
nopts.x = 2;
|
|
|
|
|
nopts.y = 2;
|
|
|
|
|
nopts.rows = 4;
|
|
|
|
|
nopts.cols = 4;
|
|
|
|
|
auto n = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(nullptr != n);
|
|
|
|
|
uint64_t channels = NCCHANNELS_INITIALIZER(0, 0xff, 0, 0xff, 0, 0xff);
|
|
|
|
|
int y, x;
|
|
|
|
|
ncplane_yx(n, &y, &x);
|
|
|
|
|
CHECK(y == 2);
|
|
|
|
|
CHECK(x == 2);
|
|
|
|
|
CHECK(1 == ncplane_set_base(n, " ", 0, channels));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(0 == ncplane_move_rel(n, -1, 0)); // up
|
|
|
|
|
ncplane_yx(n, &y, &x);
|
|
|
|
|
CHECK(y == 1);
|
|
|
|
|
CHECK(x == 2);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(0 == ncplane_move_rel(n, 2, 0)); // down
|
|
|
|
|
ncplane_yx(n, &y, &x);
|
|
|
|
|
CHECK(y == 3);
|
|
|
|
|
CHECK(x == 2);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(0 == ncplane_move_rel(n, 0, -1)); // left
|
|
|
|
|
ncplane_yx(n, &y, &x);
|
|
|
|
|
CHECK(y == 3);
|
|
|
|
|
CHECK(x == 1);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(0 == ncplane_move_rel(n, 0, 2)); // right
|
|
|
|
|
ncplane_yx(n, &y, &x);
|
|
|
|
|
CHECK(y == 3);
|
|
|
|
|
CHECK(x == 3);
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
CHECK(0 == ncplane_destroy(n));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUBCASE("ScrollingVirtualCursor") {
|
|
|
|
|
struct ncplane_options nopts{};
|
|
|
|
|
nopts.x = 2;
|
|
|
|
|
nopts.y = 2;
|
|
|
|
|
nopts.rows = 4;
|
|
|
|
|
nopts.cols = 20;
|
|
|
|
|
auto n = ncplane_create(n_, &nopts);
|
|
|
|
|
REQUIRE(nullptr != n);
|
|
|
|
|
CHECK(false == ncplane_set_scrolling(n, true));
|
|
|
|
|
uint64_t channels = NCCHANNELS_INITIALIZER(0, 0xff, 0, 0xff, 0, 0xff);
|
|
|
|
|
unsigned y, x;
|
|
|
|
|
CHECK(1 == ncplane_set_base(n, " ", 0, channels));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
for(unsigned i = 0 ; i < ncplane_dim_y(n) ; ++i){
|
|
|
|
|
ncplane_cursor_yx(n, &y, &x);
|
|
|
|
|
CHECK(i == y);
|
|
|
|
|
CHECK(0 == x);
|
|
|
|
|
CHECK(0 < ncplane_putstr(n, "here's a line\n"));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
for(unsigned i = 0 ; i < ncplane_dim_y(n) ; ++i){
|
|
|
|
|
ncplane_cursor_yx(n, &y, &x);
|
|
|
|
|
CHECK(ncplane_dim_y(n) - 1 == y);
|
|
|
|
|
CHECK(0 == x);
|
|
|
|
|
CHECK(0 < ncplane_putstr(n, "here's a line\n"));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
CHECK(0 == ncplane_destroy(n));
|
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHECK(0 == notcurses_stop(nc_));
|
|
|
|
|
|
|
|
|
|
}
|