diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 2ed84e0d3..53fa3c90c 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -2005,14 +2005,21 @@ int ncplane_polyfill_yx(ncplane* n, int y, int x, const cell* c){ static int calc_gradient_component(unsigned tl, unsigned tr, unsigned bl, unsigned br, int y, int x, int ylen, int xlen){ - assert(xlen >= 2); - assert(ylen >= 2); assert(y >= 0); assert(y < ylen); assert(x >= 0); assert(x < xlen); const int avm = (ylen - 1) - y; const int ahm = (xlen - 1) - x; + if(xlen < 2){ + if(ylen < 2){ + return tl; + } + return (tl * avm + bl * y) / (ylen - 1); + } + if(ylen < 2){ + return (tl * ahm + tr * x) / (xlen - 1); + } const int tlc = ahm * avm * tl; const int blc = ahm * y * bl; const int trc = x * avm * tr; @@ -2066,6 +2073,9 @@ int ncplane_gradient(ncplane* n, const char* egc, uint32_t attrword, channel_palindex_p(lr) || channel_palindex_p(ur)){ return -1; } + if(egc == NULL){ + return -1; + } int yoff, xoff, ymax, xmax; ncplane_cursor_yx(n, &yoff, &xoff); // must be at least 1x1, with its upper-left corner at the current cursor @@ -2084,14 +2094,18 @@ int ncplane_gradient(ncplane* n, const char* egc, uint32_t attrword, const int ylen = ystop - yoff + 1; if(ylen == 1){ if(xlen == 1){ - // single cell FIXME + if(ul != ur || ur != lr || lr != ll){ + return -1; + } }else{ - // horizontal 1d FIXME + if(ul != ll || ur != lr){ + return -1; + } } - return 0; }else if(xlen == 1){ - // vertical 1d FIXME - return 0; + if(ul != ur || ll != lr){ + return -1; + } } for(int y = yoff ; y <= ystop ; ++y){ for(int x = xoff ; x <= xstop ; ++x){ diff --git a/tests/fills.cpp b/tests/fills.cpp index b30b66b58..eb572b65e 100644 --- a/tests/fills.cpp +++ b/tests/fills.cpp @@ -219,7 +219,7 @@ TEST_CASE("Fills") { } } CHECK(0 == notcurses_render(nc_)); - // attr should change, but not the EGC/color + // EGC/color should change, but nothing else CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0)); uint64_t channels = 0; channels_set_fg_rgb(&channels, 0x88, 0x99, 0x77); @@ -237,6 +237,52 @@ TEST_CASE("Fills") { } } + // test the single-cell (1x1) special case + SUBCASE("GradientSingleCell") { + int sbytes; + CHECK(0 == ncplane_set_fg(n_, 0x444444)); + CHECK(1 == ncplane_putegc_yx(n_, 0, 0, "A", &sbytes)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0)); + uint64_t channels = 0; + channels_set_fg_rgb(&channels, 0x88, 0x99, 0x77); + channels_set_bg(&channels, 0); + REQUIRE(0 == ncplane_gradient(n_, "A", 0, channels, channels, channels, channels, 0, 0)); + CHECK(0 == notcurses_render(nc_)); + cell d = CELL_TRIVIAL_INITIALIZER; + CHECK(1 == ncplane_at_yx(n_, 0, 0, &d)); + CHECK(channels == d.channels); + REQUIRE(cell_simple_p(&d)); + CHECK('A' == d.gcluster); + } + + // 1d gradients over multiple cells + SUBCASE("Gradient1D") { + int sbytes; + CHECK(0 == ncplane_set_fg(n_, 0x444444)); + CHECK(1 == ncplane_putegc_yx(n_, 0, 0, "A", &sbytes)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0)); + uint64_t chan1 = 0, chan2 = 0; + channels_set_fg_rgb(&chan1, 0x88, 0x99, 0x77); + channels_set_fg_rgb(&chan2, 0x77, 0x99, 0x88); + channels_set_bg(&chan1, 0); + channels_set_bg(&chan2, 0); + REQUIRE(0 == ncplane_gradient(n_, "A", 0, chan1, chan2, chan1, chan2, 0, 3)); + CHECK(0 == notcurses_render(nc_)); + cell d = CELL_TRIVIAL_INITIALIZER; + CHECK(1 == ncplane_at_yx(n_, 0, 0, &d)); + CHECK(chan1 == d.channels); + REQUIRE(cell_simple_p(&d)); + CHECK('A' == d.gcluster); + CHECK(0 == ncplane_cursor_move_yx(n_, 0, 0)); + REQUIRE(0 == ncplane_gradient(n_, "A", 0, chan2, chan1, chan2, chan1, 0, 3)); + CHECK(1 == ncplane_at_yx(n_, 0, 0, &d)); + REQUIRE(cell_simple_p(&d)); + CHECK('A' == d.gcluster); + CHECK(chan2 == d.channels); + } + CHECK(0 == notcurses_stop(nc_)); CHECK(0 == fclose(outfp_));