From 0d2c43603bdf1dd52e54951efa013770d0fcd8c4 Mon Sep 17 00:00:00 2001 From: Nick Black Date: Tue, 10 Dec 2019 06:02:49 -0500 Subject: [PATCH] Luigi in Mega Man world (#127) * uniblock-demo: reset background to black * warning about quantization * some luigi love * update cell documentation * add unit test for move of stdplane * MoveToLowerRight unit test * ncplane_move_yx(): error to move stdscr * better box permutations test * luigi in megaman2 world * stats: don't print 'em if we haven't got 'em --- README.md | 20 ++-- doc/man/man1/notcurses-demo.1 | 4 +- include/enmetric.h | 60 +++++++++++ include/notcurses.h | 2 +- src/demo/demo.c | 4 +- src/demo/demo.h | 1 + src/demo/luigi.c | 193 ++++++++++++++++++++++++++++++++++ src/demo/unicodeblocks.c | 4 +- src/lib/libav.c | 2 +- src/lib/notcurses.c | 46 +++++--- tests/megaman2.bmp | Bin 0 -> 69738 bytes tests/ncplane.cpp | 75 ++++++++++--- tests/notcurses.cpp | 7 ++ 13 files changed, 369 insertions(+), 49 deletions(-) create mode 100644 include/enmetric.h create mode 100644 src/demo/luigi.c create mode 100644 tests/megaman2.bmp diff --git a/README.md b/README.md index 1acd84ecf..ff0982385 100644 --- a/README.md +++ b/README.md @@ -304,7 +304,7 @@ 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. -void ncplane_move_yx(struct ncplane* n, int y, int x); +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); @@ -503,7 +503,7 @@ ncplane_double_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels, // 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 are invalidated, and must not be used after the call. void ncplane_erase(struct ncplane* n); // Set the current fore/background color using RGB specifications. If the @@ -571,18 +571,20 @@ available to the user: // are unlikely in common use. typedef struct cell { // These 32 bits are either a single-byte, single-character grapheme cluster - // (values 0--0x7f), or a pointer into a per-ncplane attached pool of - // varying-length UTF-8 grapheme clusters. This pool may thus be up to 16MB. + // (values 0--0x7f), or an offset into a per-ncplane attached pool of + // varying-length UTF-8 grapheme clusters. This pool may thus be up to 32MB. uint32_t gcluster; // 1 * 4b -> 4b - // The classic NCURSES WA_* attributes (16 bits), plus 16 bits of alpha. + // CELL_STYLE_* attributes (16 bits) + 16 reserved bits uint32_t attrword; // + 4b -> 8b - // (channels & 0x8000000000000000ull): inherit styling from prior cell + // (channels & 0x8000000000000000ull): wide character (left or right side) // (channels & 0x4000000000000000ull): foreground is *not* "default color" - // (channels & 0x3f00000000000000ull): reserved, must be 0 + // (channels & 0x3000000000000000ull): foreground alpha (2 bits) + // (channels & 0x0f00000000000000ull): reserved, must be 0 // (channels & 0x00ffffff00000000ull): foreground in 3x8 RGB (rrggbb) - // (channels & 0x0000000080000000ull): in the middle of a multicolumn glyph + // (channels & 0x0000000080000000ull): reserved, must be 0 // (channels & 0x0000000040000000ull): background is *not* "default color" - // (channels & 0x000000003f000000ull): reserved, must be 0 + // (channels & 0x0000000030000000ull): background alpha (2 bits) + // (channels & 0x000000000f000000ull): reserved, must be 0 // (channels & 0x0000000000ffffffull): background in 3x8 RGB (rrggbb) // At render time, these 24-bit values are quantized down to terminal // capabilities, if necessary. There's a clear path to 10-bit support should diff --git a/doc/man/man1/notcurses-demo.1 b/doc/man/man1/notcurses-demo.1 index 802454073..3366eb45c 100644 --- a/doc/man/man1/notcurses-demo.1 +++ b/doc/man/man1/notcurses-demo.1 @@ -20,7 +20,7 @@ on your terminal after the program exits. Print a usage message, and exit with success. .TP .IR demospec -Select which demos to run, and what order to run them in. The default is "imbgsuwvpo". See below for a list of demos. +Select which demos to run, and what order to run them in. The default is "imlbgsuwvpo". See below for a list of demos. .SH DESCRIPTION .B notcurses-demo contains a set of text-based demonstrations of capabilities from the notcurses library. The demonstrations include: @@ -33,6 +33,8 @@ contains a set of text-based demonstrations of capabilities from the notcurses l .P (m)axcolors—smoothly changing colors .P +(l)uigi-a dashing plumber of Apennine persuasion +.P (b)oxes—pulsating boxes with a transparent center .P (g)rid—a gradient of color lain atop a great grid diff --git a/include/enmetric.h b/include/enmetric.h new file mode 100644 index 000000000..6f6ce491e --- /dev/null +++ b/include/enmetric.h @@ -0,0 +1,60 @@ +#ifndef NOTCURSES_ENMETRIC +#define NOTCURSES_ENMETRIC + +#ifdef __cplusplus +extern "C" { +#else +#define RESTRICT restrict +#endif + +#define PREFIXSTRLEN 7 // Does not include a '\0' (xxx.xxU) +#define IPREFIXSTRLEN 8 // Does not include a '\0' (xxxx.xxU) +#define BPREFIXSTRLEN 9 // Does not include a '\0' (xxxx.xxUi), i == prefix + +// A bit of the nasties here to stringize our preprocessor tokens just now +// #defined, making them usable as printf(3) specifiers. +#define STRHACK1(x) #x +#define STRHACK2(x) STRHACK1(x) +#define PREFIXFMT "%" STRHACK2(PREFIXSTRLEN) "s" +#define IPREFIXFMT "%" STRHACK2(IPREFIXSTRLEN) "s" +#define BPREFIXFMT "%" STRHACK2(BPREFIXSTRLEN) "s" + +// Takes an arbitrarily large number, and prints it into a fixed-size buffer by +// adding the necessary SI suffix. Usually, pass a |[B]PREFIXSTRLEN+1|-sized +// buffer to generate up to [B]PREFIXSTRLEN characters. The characteristic can +// occupy up through |mult-1| characters (3 for 1000, 4 for 1024). The mantissa +// can occupy either zero or two characters. +// +// Floating-point is never used, because an IEEE758 double can only losslessly +// represent integers through 2^53-1. +// +// 2^64-1 is 18446744073709551615, 18.45E(xa). KMGTPEZY thus suffice to handle +// a 89-bit uintmax_t. Beyond Z(etta) and Y(otta) lie lands unspecified by SI. +// +// val: value to print +// decimal: scaling. '1' if none has taken place. +// buf: buffer in which string will be generated +// omitdec: inhibit printing of all-0 decimal portions +// mult: base of suffix system (almost always 1000 or 1024) +// uprefix: character to print following suffix ('i' for kibibytes basically). +// only printed if suffix is actually printed (input >= mult). +const char *enmetric(uintmax_t val, unsigned decimal, char *buf, int omitdec, + unsigned mult, int uprefix); + +// Mega, kilo, gigabytes. Use PREFIXSTRLEN + 1. +static inline const char * +qprefix(uintmax_t val, unsigned decimal, char *buf, int omitdec){ + return enmetric(val, decimal, buf, omitdec, 1000, '\0'); +} + +// Mibi, kebi, gibibytes. Use BPREFIXSTRLEN + 1. +static inline const char * +bprefix(uintmax_t val, unsigned decimal, char *buf, int omitdec){ + return enmetric(val, decimal, buf, omitdec, 1024, 'i'); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/include/notcurses.h b/include/notcurses.h index 952ffb796..03529ad75 100644 --- a/include/notcurses.h +++ b/include/notcurses.h @@ -303,7 +303,7 @@ API 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. -API void ncplane_move_yx(struct ncplane* n, int y, int x); +API int ncplane_move_yx(struct ncplane* n, int y, int x); // Get the origin of this plane relative to the standard plane. API void ncplane_yx(const struct ncplane* n, int* RESTRICT y, int* RESTRICT x); diff --git a/src/demo/demo.c b/src/demo/demo.c index 1ec9bb48e..e11fbfee1 100644 --- a/src/demo/demo.c +++ b/src/demo/demo.c @@ -9,7 +9,7 @@ #include #include "demo.h" -static const char DEFAULT_DEMO[] = "imbgswuvpo"; +static const char DEFAULT_DEMO[] = "imlbgswuvpo"; int timespec_subtract(struct timespec *result, const struct timespec *time0, struct timespec *time1){ @@ -45,6 +45,7 @@ usage(const char* exe, int status){ fprintf(out, " b: run box\n"); fprintf(out, " g: run grid\n"); fprintf(out, " i: run intro\n"); + fprintf(out, " l: run luigi\n"); fprintf(out, " m: run maxcolor\n"); fprintf(out, " o: run outro\n"); fprintf(out, " p: run panelreels\n"); @@ -145,6 +146,7 @@ ext_demos(struct notcurses* nc, const char* demos){ case 'm': ret = maxcolor_demo(nc); break; case 'b': ret = box_demo(nc); break; case 'g': ret = grid_demo(nc); break; + case 'l': ret = luigi_demo(nc); break; case 'v': ret = view_demo(nc); break; case 'w': ret = widecolor_demo(nc); break; case 'p': ret = panelreel_demo(nc); break; diff --git a/src/demo/demo.h b/src/demo/demo.h index c9502c7e0..4dc8f4059 100644 --- a/src/demo/demo.h +++ b/src/demo/demo.h @@ -19,6 +19,7 @@ int grid_demo(struct notcurses* nc); int sliding_puzzle_demo(struct notcurses* nc); int view_demo(struct notcurses* nc); int panelreel_demo(struct notcurses* nc); +int luigi_demo(struct notcurses* nc); int outro(struct notcurses* nc); int timespec_subtract(struct timespec *result, const struct timespec *time1, diff --git a/src/demo/luigi.c b/src/demo/luigi.c new file mode 100644 index 000000000..b8ee36dde --- /dev/null +++ b/src/demo/luigi.c @@ -0,0 +1,193 @@ +#include "demo.h" + +//0 = trans +//1 = white +//2 = yellow +//3 = green + +static const char luigi1[] = "0000000000000000" +"0000000000000000" +"0000000111110000" +"0000011111120000" +"0000111111220000" +"0000111111111110" +"0000333223222000" +"0003223223322220" +"0003223322222222" +"0033223322232222" +"0033222223333330" +"0003322222333330" +"0000032222222200" +"0000311122200000" +"0003133313000000" +"0003133331300000" +"0033133333112200" +"0031133333332222" +"0031113333332222" +"0001113333333222" +"0001111333333222" +"0001111113331000" +"0001111111111000" +"0001111111113000" +"3333111111131100" +"3333111113311100" +"3333111131111000" +"3333111001111000" +"3333000003333000" +"3300000003333000" +"3000000003333330" +"0000000003333330"; + +static const char luigi2[] = "0000000000000000" +"0000001111100000" +"0000111111200000" +"0001111112200000" +"0001111111111100" +"0003332232220000" +"0032232233222200" +"0032233222222220" +"0332233222322220" +"0332222233333300" +"0033222223333300" +"0003322222222000" +"0000111122000000" +"0003133113300000" +"0031333311300000" +"0031333311330000" +"0031333311130000" +"0031333332230000" +"0031333322220000" +"0011133322221000" +"0011133322221100" +"0011113322211100" +"0011111133111100" +"0001111133311000" +"0000111333333000" +"0000113333330000" +"0000011333300000" +"0000031113330000" +"0000033330330000" +"0000333330000000" +"0000333333300000" +"0000003333300000"; + +static const char luigi3[] = "0000001111100000" +"0000111111200000" +"0001111112200000" +"0001111111111100" +"0003332232220000" +"0032232233222200" +"0032233222222220" +"0332233222322220" +"0332222233333300" +"0333222223333300" +"0003322222222000" +"0000033322000000" +"0000111133100020" +"0003333113310222" +"0033333311313222" +"0333333311331222" +"0333333311331323" +"0333333111331330" +"3333331112132300" +"3333111111111000" +"2222211111111000" +"2222211111111003" +"2222111111111033" +"0222111111133333" +"0001311111133333" +"0031131111133333" +"3331113311133333" +"3333111100033333" +"3333310000000000" +"0333000000000000" +"0333000000000000" +"0033300000000000"; + +static int +draw_luigi(struct ncplane* n, const char* sprite){ + cell bgc = CELL_TRIVIAL_INITIALIZER; + cell_bg_set_alpha(&bgc, 3); + ncplane_set_background(n, &bgc); + cell_release(n, &bgc); + size_t s; + int sbytes; + uint64_t channels = 0; + for(s = 0 ; s < strlen(sprite) ; ++s){ + switch(sprite[s]){ + case '0': + ncplane_cursor_move_yx(n, (s + 1) / 16, (s + 1) % 16); + break; + case '1': + notcurses_fg_prep(&channels, 255, 255, 255); + break; + case '2': + notcurses_fg_prep(&channels, 0xe3, 0x9d, 0x25); + break; + case '3': + notcurses_fg_prep(&channels, 0x3a, 0x84, 0x00); + break; + } + if(sprite[s] != '0'){ + if(ncplane_putegc(n, "\u2588", 0, channels, &sbytes) != 1){ + return -1; + } + } + } + return 0; +} + +int luigi_demo(struct notcurses* nc){ + struct ncplane* n = notcurses_stdplane(nc); + int averr = 0; + struct ncvisual* nv = ncplane_visual_open(n, "../tests/megaman2.bmp", &averr); + if(nv == NULL){ + return -1; + } + if(ncvisual_decode(nv, &averr) == NULL){ + return -1; + } + if(ncvisual_render(nv)){ + return -1; + } + int rows, cols; + ncplane_dim_yx(n, &rows, &cols); + // he should be walking on the platform ~4/5 of the way down + const int height = 32; + int yoff = rows * 4 / 5 - height + 1; // tuned + struct ncplane* lns[3]; + int i; + for(i = 0 ; i < 3 ; ++i){ + lns[i] = notcurses_newplane(nc, height, 16, yoff, -16, NULL); + if(lns[i] == NULL){ + while(--i){ + ncplane_destroy(lns[i]); + } + return -1; + } + } + draw_luigi(lns[0], luigi1); + draw_luigi(lns[1], luigi2); + draw_luigi(lns[2], luigi3); + struct ncplane* lastseen = NULL; + struct timespec stepdelay; + ns_to_timespec(timespec_to_ns(&demodelay) / (cols - 16 - 1), &stepdelay); + for(i = 0 ; i < cols - 16 - 1 ; ++i){ + if(lastseen){ // hide the previous sprite + ncplane_move_yx(lastseen, yoff, -16); + } + if(i % 4 == 3){ + lastseen = lns[1]; + }else{ + lastseen = lns[i % 4]; + } + ncplane_move_yx(lastseen, yoff, i); + notcurses_render(nc); + nanosleep(&stepdelay, NULL); + } + for(i = 0 ; i < 3 ; ++i){ + ncplane_destroy(lns[i]); + } + ncvisual_destroy(nv); + return 0; +} diff --git a/src/demo/unicodeblocks.c b/src/demo/unicodeblocks.c index 6364f2235..e8d6e7e7e 100644 --- a/src/demo/unicodeblocks.c +++ b/src/demo/unicodeblocks.c @@ -180,8 +180,9 @@ int unicodeblocks_demo(struct notcurses* nc){ // we don't want a full delay period for each one, urk...or do we? struct timespec subdelay; uint64_t nstotal = timespec_to_ns(&demodelay); - ns_to_timespec(nstotal, &subdelay); + ns_to_timespec(nstotal / 5, &subdelay); for(sindex = 0 ; sindex < sizeof(blocks) / sizeof(*blocks) ; ++sindex){ + ncplane_set_bg_rgb(n, 0, 0, 0); //ncplane_erase(n); uint32_t blockstart = blocks[sindex].start; const char* description = blocks[sindex].name; @@ -204,7 +205,6 @@ int unicodeblocks_demo(struct notcurses* nc){ return -1; } ncplane_set_fg_rgb(n, 0x40, 0xc0, 0x40); - ncplane_set_bg_rgb(n, 0, 0, 0); if(ncplane_cursor_move_yx(n, 6 + BLOCKSIZE / CHUNKSIZE, 0)){ return -1; } diff --git a/src/lib/libav.c b/src/lib/libav.c index d4fd412c8..2cbaf098a 100644 --- a/src/lib/libav.c +++ b/src/lib/libav.c @@ -153,7 +153,7 @@ ncvisual* ncplane_visual_open(struct ncplane* nc, const char* filename, int* ave ncplane_dim_yx(nc, &ncv->dstheight, &ncv->dstwidth); // FIXME we only want to do this if we're not already large enough to // faithfully reproduce the image, methinks? - //ncv->dstwidth *= 2; + // ncv->dstwidth *= 2; ncv->dstheight *= 2; *averr = avformat_open_input(&ncv->fmtctx, filename, NULL, NULL); if(*averr < 0){ diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 664a44dbc..d698a2c31 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -357,8 +357,6 @@ ncplane* notcurses_newplane(notcurses* nc, int rows, int cols, if(n == NULL){ return n; } - n->absx = xoff; - n->absy = yoff; n->userptr = opaque; return n; } @@ -680,6 +678,15 @@ notcurses* notcurses_init(const notcurses_options* opts){ ret->top->leny, ret->top->lenx, ret->top->lenx * ret->top->leny * sizeof(*ret->top->fb), ret->colors, ret->RGBflag ? "direct" : "palette"); + if(!ret->RGBflag){ // FIXME + if(ret->colors > 16){ + putp(tiparm(ret->setaf, 207)); + }else{ + putp(tiparm(ret->setaf, 9)); + } + fprintf(ret->ttyfp, "\nWarning: you will not have colors until this is resolved:\n"); + fprintf(ret->ttyfp, " https://github.com/dankamongmen/notcurses/issues/4\n"); + } return ret; err: @@ -700,20 +707,21 @@ int notcurses_stop(notcurses* nc){ ret = -1; } ret |= tcsetattr(nc->ttyfd, TCSANOW, &nc->tpreserved); - double avg = nc->stats.renders ? - nc->stats.render_ns / (double)nc->stats.renders : 0; - fprintf(stderr, "%ju renders, %.03gs total (%.03gs min, %.03gs max, %.02gs avg)\n", - nc->stats.renders, - nc->stats.render_ns / 1000000000.0, - nc->stats.render_min_ns / 1000000000.0, - nc->stats.render_max_ns / 1000000000.0, - avg / NANOSECS_IN_SEC); - avg = nc->stats.renders ? nc->stats.render_bytes / (double)nc->stats.renders : 0; - fprintf(stderr, "%.03fKB total (%.03fKB min, %.03fKB max, %.02fKB avg)\n", - nc->stats.render_bytes / 1024.0, - nc->stats.render_min_bytes / 1024.0, - nc->stats.render_max_bytes / 1024.0, - avg / 1024); + if(nc->stats.renders){ + double avg = nc->stats.render_ns / (double)nc->stats.renders; + fprintf(stderr, "%ju renders, %.03gs total (%.03gs min, %.03gs max, %.02gs avg)\n", + nc->stats.renders, + nc->stats.render_ns / 1000000000.0, + nc->stats.render_min_ns / 1000000000.0, + nc->stats.render_max_ns / 1000000000.0, + avg / NANOSECS_IN_SEC); + avg = nc->stats.render_bytes / (double)nc->stats.renders; + fprintf(stderr, "%.03fKB total (%.03fKB min, %.03fKB max, %.02fKB avg)\n", + nc->stats.render_bytes / 1024.0, + nc->stats.render_min_bytes / 1024.0, + nc->stats.render_max_bytes / 1024.0, + avg / 1024); + } fprintf(stderr, "Emits/elides: def %lu/%lu fg %lu/%lu bg %lu/%lu\n", nc->stats.defaultemissions, nc->stats.defaultelisions, @@ -1672,9 +1680,13 @@ int ncplane_box(ncplane* n, const cell* ul, const cell* ur, return 0; } -void ncplane_move_yx(ncplane* n, int y, int x){ +int ncplane_move_yx(ncplane* n, int y, int x){ + if(n == n->nc->stdscr){ + return -1; + } n->absy = y; n->absx = x; + return 0; } void ncplane_yx(const ncplane* n, int* y, int* x){ diff --git a/tests/megaman2.bmp b/tests/megaman2.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b443f1873a0e7225dd012b4e6a07255f9eae5e83 GIT binary patch literal 69738 zcmeI4J(A?O5ru0cXCv0oM(6@Eb&hq`lA{yIkR?}R?g?}fSsOaQ97LuL(h)5t3Lh(x zMDnj#)y=6lF^EJa^5N(45d_&i^YdT+@za-!{rT5WejUnhL;3qqzFhuv`Tb!3_lGZ+ zKmK?rWpL}C_siw_*ZlXNfBEY_X<2K37ZU&T?d_d%`SX9@WBJ?Hw|5G8-e&ne$Lc=J3pY!(i_WteLw|BF9%RPAJlFgNQlZPdrb}a2?$knTUS3O=Mw~=4N&~MD8 zKkS}7!=O3rR_%hrZpC}PwEk9K&$#}J{M!!h_F3|6KevMZ;#_H8Yw5S?ua40hf2+=p z&SzcCd>v1;ueDnL^|{^fIdlEtwaLGOfBJj0U8}>r`zifr_(!jAsek6TWV87%;b_nB zOY{5a_OD;RzJJC7uX7g8v2(e-HgH&<^U<96xny3(xwe7)Y^LkdCbzxs^{Y$!y*ZZ^iTsLpy9DUoG`WAf5eYW3QPn<(9XD+q{ zA9J7OFX?t}eV?H%^0akM_u{vXcXa-}^S>8=^m^9zcXr*bU8nN)f9L*;+?j5Fy8OHO z*5$uDea1QOnbW=d%DwnKb3PJt@BHt@AGsFmtL(S_yO*n*o_pghtwHVcKgSb4_w&=} z_J?05`)<_j66Y~L`bXnqfB4v?@nar7b_pNbm;9{XB^>P$pZPKVC_MeHwb{J3;?b?` zt>wI6+I9N1{unE>aZK`v<7bvUEP2r7F?7?}?h2O8+SK+_vcHCpVj@RlZ=0zV(W;W(WKf@7^`OzmY zvoSyV8IE|&k3M;sjrq~faKvMN^vTO?%#VJCBOddkPhMtYe)M}d_pP?sYfZlqAN^i` z7R&OocNh=zi_g!6-w&704|Y9$eyj_B9Cya!9B;IVzjge1U5<6rZRL54 z1>SvpQWswQJz77eF%@xeMh)=Ju*ceZ_u#+?FaFTN78`Xl?C+a&D16J8_-pxC(&AqI zfHS`RnZ(A6*C6_qBmDI`iNELSr|ORP*=X5&iI3XmJ`%p@7Ji}?f5YB3Xa!yl)6bwg z>$B{wZqHzx%#Py=FaAD4Kek`0h=a3ffam>^wRJ7!%(V+I{^sqy-$zU&%iHdSkA1`FIx8Fa!smMV}A67ci&y?J{NyiP2Zs(G=}BsGmV^WiQ2=?$BV3!F$oH#cEE26aLDh_ba5fG2Gi+A3HPL4K>QHaa3$$fcc=3le4${x4!J$9S0p2$HtT`oS^Qe0C`TmSy zapBu{wUHC?cb|St|E`R@x>$OiHQoBWp)P#*KY@*(4o`)*PF(!0$HnA4B7sfdG^|bc_{Dy+=wt$(d`5=ab$T z!q1#>Uz~rh4bBYMxwbVq!rycUU(wESG}lHyb2)Qu-v!>D5ySl(3+s;Yi7)(wJL5?F zUGLk8UZU3a=*KWB;^1T&uswm|?+f;d*oGh5i|_8E*iPTVJH7|4G<=A^@wv51KaMZ- zRjl2ENt^FC%jtdZAy@e2v#Io{B9(Vy`B`+MfT7k{_kv0*Qp*g5{JO+_4> zOap$uw0eAg6Z3H&EAhJD61V$+II-f_xQ~%%_Zo5G#UHvr6UBG>iF>ne_ib6+=b$~W zJKBX`ah|RBuK2s%x1021&y3!gHH*jGEH8@--}0UDl*M0>KjT709Gpx8_WY*se9HW- z@z|g6?fV0KU?X4A&+@YP_l)OEYHPQ3Hs^!jM}Ellabm>^-|*>qDty=HyN`=M_xlDj z`hlmyW5}E6c;LC4m&Id$SzZ 4 && x > 4){ maxx -= 2; maxy -= 2; ++x; ++y; ASSERT_EQ(0, ncplane_resize(newp, 1, 1, maxy, maxx, 1, 1, maxy, maxx)); + EXPECT_EQ(0, notcurses_render(nc_)); // FIXME check dims, pos } while(y > 4){ maxy -= 2; ++y; ASSERT_EQ(0, ncplane_resize(newp, 1, 0, maxy, maxx, 1, 0, maxy, maxx)); + EXPECT_EQ(0, notcurses_render(nc_)); // FIXME check dims, pos } while(x > 4){ maxx -= 2; ++x; ASSERT_EQ(0, ncplane_resize(newp, 0, 1, maxy, maxx, 0, 1, maxy, maxx)); + EXPECT_EQ(0, notcurses_render(nc_)); // FIXME check dims, pos } ASSERT_EQ(0, ncplane_resize(newp, 0, 0, 0, 0, 0, 0, 2, 2)); + EXPECT_EQ(0, notcurses_render(nc_)); // FIXME check dims, pos ASSERT_EQ(0, ncplane_destroy(newp)); } @@ -686,3 +696,34 @@ TEST_F(NcplaneTest, RightToLeft) { EXPECT_LT(0, ncplane_putstr(n_, "㉀㉁㉂㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌㉍㉎㉏㉐㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟")); EXPECT_EQ(0, notcurses_render(nc_)); } + +TEST_F(NcplaneTest, NewPlaneOnRight) { + int ncols, nrows; + ncplane_dim_yx(n_, &nrows, &ncols); + cell ul{}, ll{}, lr{}, ur{}, hl{}, vl{}; + int y, x; + ncplane_yx(n_, &y, &x); + struct ncplane* ncp = notcurses_newplane(nc_, 2, 2, y, ncols - 3, nullptr); + ASSERT_NE(nullptr, ncp); + ASSERT_EQ(0, cells_rounded_box(ncp, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl)); + EXPECT_EQ(0, ncplane_box(ncp, &ul, &ur, &ll, &lr, &hl, &vl, y + 1, x + 1, 0)); + EXPECT_EQ(0, notcurses_render(nc_)); + // FIXME verify with ncplane_at_cursor() + EXPECT_EQ(0, ncplane_destroy(ncp)); +} +TEST_F(NcplaneTest, MoveToLowerRight) { + int ncols, nrows; + ncplane_dim_yx(n_, &nrows, &ncols); + cell ul{}, ll{}, lr{}, ur{}, hl{}, vl{}; + int y, x; + ncplane_yx(n_, &y, &x); + struct ncplane* ncp = notcurses_newplane(nc_, 2, 2, y, x, nullptr); + ASSERT_NE(nullptr, ncp); + ASSERT_EQ(0, cells_rounded_box(ncp, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl)); + EXPECT_EQ(0, ncplane_box(ncp, &ul, &ur, &ll, &lr, &hl, &vl, y + 1, x + 1, 0)); + EXPECT_EQ(0, notcurses_render(nc_)); + EXPECT_EQ(0, ncplane_move_yx(ncp, nrows - 3, ncols - 3)); + EXPECT_EQ(0, notcurses_render(nc_)); + EXPECT_EQ(0, ncplane_destroy(ncp)); + // FIXME verify with ncplane_at_cursor() +} diff --git a/tests/notcurses.cpp b/tests/notcurses.cpp index 0b50a7aca..e78240582 100644 --- a/tests/notcurses.cpp +++ b/tests/notcurses.cpp @@ -76,6 +76,13 @@ TEST_F(NotcursesTest, RejectDestroyStdPlane) { ASSERT_NE(0, ncplane_destroy(ncp)); } +// it is an error to attempt to move the standard plane +TEST_F(NotcursesTest, RejectMoveStdPlane) { + ncplane* ncp = notcurses_stdplane(nc_); + ASSERT_NE(nullptr, ncp); + ASSERT_NE(0, ncplane_move_yx(ncp, 1, 1)); +} + // create planes partitioning the entirety of the screen, one at each coordinate TEST_F(NotcursesTest, TileScreenWithPlanes) { int maxx, maxy;