mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
eliminate recursion in ncplane_polyfill_yx #2328
This commit is contained in:
parent
51e90ca7e9
commit
91420af5ce
@ -128,8 +128,8 @@ add_compile_options(-fno-signed-zeros -fno-trapping-math -fassociative-math)
|
||||
add_compile_options(-fno-math-errno -freciprocal-math -funsafe-math-optimizations)
|
||||
add_compile_options(-fexceptions -fstrict-aliasing)
|
||||
if(${USE_ASAN})
|
||||
add_compile_options(-fsanitize=undefined)
|
||||
add_link_options(-fsanitize=undefined)
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
3
NEWS.md
3
NEWS.md
@ -12,8 +12,11 @@ rearrangements of Notcurses.
|
||||
deprecated functionality, ABI3 ought require small changes, if any.
|
||||
|
||||
* 2.4.9 (not yet released)
|
||||
* Added `ncnmetric()`, which uses `snprintf()` internally. `ncmetric()`
|
||||
was reimplemented as a trivial wrapper around `ncnmetric()`.
|
||||
* `qprefix()`, `bprefix()`, and `iprefix()` have been renamed
|
||||
`ncqprefix()`, `ncbprefix()`, and `nciprefix()`, respectively.
|
||||
The former forms have been deprecated, and will be removed in abi3.
|
||||
* `notcurses_mice_enable()` and `notcurses_mouse_disable()` replace
|
||||
`notcurses_mouse_enable()` and `notcurses_mouse_disable()`, which
|
||||
have been deprecated, and will be removed in ABI3.
|
||||
|
6
USAGE.md
6
USAGE.md
@ -451,7 +451,7 @@ are available for direct mode:
|
||||
// Read a (heap-allocated) newline-delimited chunk of text. Returns NULL on
|
||||
// failure. The NCDIRECT_OPTION_INHIBIT_CBREAK flag ought not be used together
|
||||
// with this function, or the line-editing keybindings cannot be honored.
|
||||
API char* ncdirect_readline(struct ncdirect* nc, const char* prompt);
|
||||
char* ncdirect_readline(struct ncdirect* nc, const char* prompt);
|
||||
|
||||
int ncdirect_fg_rgb(struct ncdirect* nc, unsigned rgb);
|
||||
int ncdirect_bg_rgb(struct ncdirect* nc, unsigned rgb);
|
||||
@ -1674,7 +1674,7 @@ int ncplane_gradient2x1(struct ncplane* n, int y, int x, unsigned ylen,
|
||||
// remaining to the right and below, respectively. It is an error for any
|
||||
// coordinate to be outside the plane. Returns the number of cells set,
|
||||
// or -1 on failure.
|
||||
API int ncplane_format(struct ncplane* n, int y, int x, unsigned ylen,
|
||||
int ncplane_format(struct ncplane* n, int y, int x, unsigned ylen,
|
||||
unsigned xlen, uint16_t stylemask);
|
||||
|
||||
// Set the given channels throughout the specified region, keeping content and
|
||||
@ -1684,7 +1684,7 @@ API int ncplane_format(struct ncplane* n, int y, int x, unsigned ylen,
|
||||
// remaining to the right and below, respectively. It is an error for any
|
||||
// coordinate to be outside the plane. Returns the number of cells set,
|
||||
// or -1 on failure.
|
||||
API int ncplane_stain(struct ncplane* n, int y, int x, unsigned ylen,
|
||||
int ncplane_stain(struct ncplane* n, int y, int x, unsigned ylen,
|
||||
unsigned xlen, uint64_t ul, uint64_t ur,
|
||||
uint64_t ll, uint64_t lr);
|
||||
```
|
||||
|
@ -1807,7 +1807,7 @@ API void ncplane_center_abs(const struct ncplane* n, int* RESTRICT y,
|
||||
// Only glyphs from the specified ncblitset may be present. If 'pxdimy' and/or
|
||||
// 'pxdimx' are non-NULL, they will be filled in with the total pixel geometry.
|
||||
API ALLOC uint32_t* ncplane_as_rgba(const struct ncplane* n, ncblitter_e blit,
|
||||
unsigned begy, unsigned begx,
|
||||
int begy, int begx,
|
||||
unsigned leny, unsigned lenx,
|
||||
unsigned* pxdimy, unsigned* pxdimx)
|
||||
__attribute__ ((nonnull (1)));
|
||||
@ -2869,7 +2869,7 @@ API ALLOC struct ncvisual* ncvisual_from_palidx(const void* data, int rows,
|
||||
// Lengths of 0 are interpreted to mean "all available remaining area".
|
||||
API ALLOC struct ncvisual* ncvisual_from_plane(const struct ncplane* n,
|
||||
ncblitter_e blit,
|
||||
unsigned begy, unsigned begx,
|
||||
int begy, int begx,
|
||||
unsigned leny, unsigned lenx)
|
||||
__attribute__ ((nonnull (1)));
|
||||
|
||||
@ -3366,6 +3366,12 @@ API const char* ncmetric(uintmax_t val, uintmax_t decimal, char* buf,
|
||||
int omitdec, uintmax_t mult, int uprefix)
|
||||
__attribute__ ((nonnull (3)));
|
||||
|
||||
// uses snprintf() internally with the argument 's' as its bound
|
||||
API const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal,
|
||||
char* buf, int omitdec, uintmax_t mult,
|
||||
int uprefix)
|
||||
__attribute__ ((nonnull (4)));
|
||||
|
||||
// The number of columns is one fewer, as the STRLEN expressions must leave
|
||||
// an extra byte open in case 'µ' (U+00B5, 0xC2 0xB5) shows up. PREFIXCOLUMNS
|
||||
// is the maximum number of columns used by a mult == 1000 (standard)
|
||||
@ -3672,17 +3678,17 @@ API ALLOC struct ncmenu* ncmenu_create(struct ncplane* n, const ncmenu_options*
|
||||
API int ncmenu_unroll(struct ncmenu* n, int sectionidx);
|
||||
|
||||
// Roll up any unrolled menu section, and hide the menu if using hiding.
|
||||
API int ncmenu_rollup(struct ncmenu* n);
|
||||
API int ncmenu_rollup(struct ncmenu* n) __attribute__ ((nonnull (1)));
|
||||
|
||||
// Unroll the previous/next section (relative to current unrolled). If no
|
||||
// section is unrolled, the first section will be unrolled.
|
||||
API int ncmenu_nextsection(struct ncmenu* n);
|
||||
API int ncmenu_prevsection(struct ncmenu* n);
|
||||
API int ncmenu_nextsection(struct ncmenu* n) __attribute__ ((nonnull (1)));
|
||||
API int ncmenu_prevsection(struct ncmenu* n) __attribute__ ((nonnull (1)));
|
||||
|
||||
// Move to the previous/next item within the currently unrolled section. If no
|
||||
// section is unrolled, the first section will be unrolled.
|
||||
API int ncmenu_nextitem(struct ncmenu* n);
|
||||
API int ncmenu_previtem(struct ncmenu* n);
|
||||
API int ncmenu_nextitem(struct ncmenu* n) __attribute__ ((nonnull (1)));
|
||||
API int ncmenu_previtem(struct ncmenu* n) __attribute__ ((nonnull (1)));
|
||||
|
||||
// Disable or enable a menu item. Returns 0 if the item was found.
|
||||
API int ncmenu_item_set_status(struct ncmenu* n, const char* section,
|
||||
@ -4286,6 +4292,23 @@ API int ncplane_highgradient_sized(struct ncplane* n, uint32_t ul, uint32_t ur,
|
||||
uint32_t ll, uint32_t lr, int ylen, int xlen)
|
||||
__attribute__ ((deprecated));
|
||||
|
||||
__attribute__ ((deprecated)) static inline const char*
|
||||
qprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
|
||||
return ncmetric(val, decimal, buf, omitdec, 1000, '\0');
|
||||
}
|
||||
|
||||
// Mibi, kebi, gibibytes sans 'i' suffix. Use IPREFIXSTRLEN + 1.
|
||||
__attribute__ ((deprecated)) static inline const char*
|
||||
iprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
|
||||
return ncmetric(val, decimal, buf, omitdec, 1024, '\0');
|
||||
}
|
||||
|
||||
// Mibi, kebi, gibibytes. Use BPREFIXSTRLEN + 1 and BPREFIXCOLUMNS.
|
||||
__attribute__ ((deprecated)) static inline const char*
|
||||
bprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
|
||||
return ncmetric(val, decimal, buf, omitdec, 1024, 'i');
|
||||
}
|
||||
|
||||
#undef API
|
||||
#undef ALLOC
|
||||
|
||||
|
@ -392,13 +392,13 @@ hud_print_finished(elem* list){
|
||||
if(ncplane_printf_yx(hud, line, 1, "%d", e->frames) < 0){
|
||||
return -1;
|
||||
}
|
||||
char buf[PREFIXCOLUMNS];
|
||||
ncmetric(e->totalns, NANOSECS_IN_SEC, buf, 0, 1000, '\0');
|
||||
for(size_t x = 6 ; x < 14 - strlen(buf) ; ++x){
|
||||
char buf[PREFIXCOLUMNS + 2];
|
||||
ncnmetric(e->totalns, sizeof(buf), NANOSECS_IN_SEC, buf, 0, 1000, '\0');
|
||||
for(int x = 6 ; x < 14 - ncstrwidth(buf) ; ++x){
|
||||
nccell ci = CELL_TRIVIAL_INITIALIZER;
|
||||
ncplane_putc_yx(hud, 1, x, &ci);
|
||||
}
|
||||
if(ncplane_printf_yx(hud, line, 14 - strlen(buf), "%ss", buf) < 0){
|
||||
if(ncplane_printf_yx(hud, line, 14 - ncstrwidth(buf), "%ss", buf) < 0){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_putstr_yx(hud, line, 16, e->name) < 0){
|
||||
@ -612,13 +612,14 @@ int demo_render(struct notcurses* nc){
|
||||
if(ncplane_printf_yx(hud, 1, 1, "%d", elems->frames) < 0){
|
||||
return -1;
|
||||
}
|
||||
char buf[PREFIXCOLUMNS];
|
||||
ncmetric(ns, NANOSECS_IN_SEC, buf, 0, 1000, '\0');
|
||||
for(size_t x = 6 ; x < 14 - strlen(buf) ; ++x){
|
||||
char buf[PREFIXCOLUMNS + 2];
|
||||
ncnmetric(ns, sizeof(buf), NANOSECS_IN_SEC, buf, 0, 1000, '\0');
|
||||
for(int x = 6 ; x < 14 - ncstrwidth(buf) ; ++x){
|
||||
nccell ci = CELL_TRIVIAL_INITIALIZER;
|
||||
ncplane_putc_yx(hud, 1, x, &ci);
|
||||
}
|
||||
if(ncplane_printf_yx(hud, 1, 14 - strlen(buf), "%ss", buf) < 0){
|
||||
//fprintf(stderr, "[%s] %zu %d\n", buf, strlen(buf), ncstrwidth(buf));
|
||||
if(ncplane_printf_yx(hud, 1, 14 - ncstrwidth(buf), "%ss", buf) < 0){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_putstr_yx(hud, 1, 16, elems->name) < 0){
|
||||
|
@ -124,7 +124,7 @@ int intro(struct notcurses* nc){
|
||||
if(!notcurses_canutf8(nc)){
|
||||
return 0;
|
||||
}
|
||||
int rows, cols;
|
||||
unsigned rows, cols;
|
||||
struct ncplane* ncp = notcurses_stddim_yx(nc, &rows, &cols);
|
||||
uint32_t ccul, ccur, ccll, cclr;
|
||||
ccul = ccur = ccll = cclr = 0;
|
||||
|
@ -146,7 +146,7 @@ int luigi_demo(struct notcurses* nc){
|
||||
if(!notcurses_canopen_images(nc)){
|
||||
return 0;
|
||||
}
|
||||
int rows, cols;
|
||||
unsigned rows, cols;
|
||||
char* map = find_data("megaman2.bmp");
|
||||
struct ncvisual* nv = ncvisual_from_file(map);
|
||||
free(map);
|
||||
@ -166,7 +166,7 @@ int luigi_demo(struct notcurses* nc){
|
||||
const int height = 32;
|
||||
int yoff = rows * 4 / 5 - height + 1; // tuned
|
||||
struct ncplane* lns[3];
|
||||
int i;
|
||||
unsigned i;
|
||||
struct ncplane* lastseen = NULL;
|
||||
for(i = 0 ; i < 3 ; ++i){
|
||||
struct ncplane_options nopts = {
|
||||
|
@ -509,14 +509,14 @@ int witherworm_demo(struct notcurses* nc){
|
||||
}
|
||||
int ulen = 0;
|
||||
int r;
|
||||
//if(wcwidth(wcs) <= maxx - x){
|
||||
if(wcwidth(wcs) <= (int)maxx - x){
|
||||
if((r = ncplane_putegc(n, &(*s)[idx], &ulen)) <= 0){
|
||||
if(ulen < 0){
|
||||
return -1;
|
||||
}else if(ulen == 0){
|
||||
break; // FIXME work around missing unicode
|
||||
}
|
||||
//}
|
||||
}
|
||||
}else{
|
||||
if((r = ncplane_putchar(n, '#')) < 1){
|
||||
return -1;
|
||||
|
114
src/lib/fill.c
114
src/lib/fill.c
@ -20,50 +20,58 @@ void ncplane_greyscale(ncplane *n){
|
||||
// success. so a return of 0 means there's no work to be done here, and N means
|
||||
// we did some work here, filling everything we could reach. out-of-plane is 0.
|
||||
static int
|
||||
ncplane_polyfill_recurse(ncplane* n, unsigned y, unsigned x, const nccell* c, const char* filltarg){
|
||||
if(y >= (unsigned)n->leny || x >= (unsigned)n->lenx){
|
||||
return 0; // not fillable
|
||||
ncplane_polyfill_inner(ncplane* n, unsigned y, unsigned x, const nccell* c, const char* filltarg){
|
||||
struct topolyfill* stack = NULL;
|
||||
if(create_polyfill_op(y, x, &stack) == NULL){
|
||||
return -1;
|
||||
}
|
||||
int ret = 0;
|
||||
do{
|
||||
struct topolyfill* s = stack;
|
||||
stack = stack->next;
|
||||
y = s->y;
|
||||
x = s->x;
|
||||
nccell* cur = &n->fb[nfbcellidx(n, y, x)];
|
||||
const char* glust = nccell_extended_gcluster(n, cur);
|
||||
//fprintf(stderr, "checking %d/%d (%s) for [%s]\n", y, x, glust, filltarg);
|
||||
if(strcmp(glust, filltarg)){
|
||||
return 0;
|
||||
}
|
||||
if(strcmp(glust, filltarg) == 0){
|
||||
++ret;
|
||||
if(nccell_duplicate(n, cur, c) < 0){
|
||||
// FIXME need free stack!
|
||||
return -1;
|
||||
}
|
||||
int r, ret = 1;
|
||||
//fprintf(stderr, "blooming from %d/%d ret: %d\n", y, x, ret);
|
||||
if(y){
|
||||
if((r = ncplane_polyfill_recurse(n, y - 1, x, c, filltarg)) < 0){
|
||||
if(create_polyfill_op(y - 1, x, &stack) == NULL){
|
||||
return -1;
|
||||
}
|
||||
ret += r;
|
||||
}
|
||||
if((r = ncplane_polyfill_recurse(n, y + 1, x, c, filltarg)) < 0){
|
||||
if(y + 1 < n->leny){
|
||||
if(create_polyfill_op(y + 1, x, &stack) == NULL){
|
||||
return -1;
|
||||
}
|
||||
ret += r;
|
||||
}
|
||||
if(x){
|
||||
if((r = ncplane_polyfill_recurse(n, y, x - 1, c, filltarg)) < 0){
|
||||
if(create_polyfill_op(y, x - 1, &stack) == NULL){
|
||||
return -1;
|
||||
}
|
||||
ret += r;
|
||||
}
|
||||
if((r = ncplane_polyfill_recurse(n, y, x + 1, c, filltarg)) < 0){
|
||||
if(x + 1 < n->lenx){
|
||||
if(create_polyfill_op(y, x + 1, &stack) == NULL){
|
||||
return -1;
|
||||
}
|
||||
ret += r;
|
||||
}
|
||||
}
|
||||
free(s);
|
||||
}while(stack);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// at the initial step only, invalid ystart, xstart is an error, so explicitly check.
|
||||
int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){
|
||||
int ret = -1;
|
||||
if(ystart < 0){
|
||||
if(ystart != -1){
|
||||
logerror("invalid ystart: %d\n", ystart);
|
||||
logerror("invalid y: %d\n", ystart);
|
||||
return -1;
|
||||
}
|
||||
ystart = n->y;
|
||||
@ -71,7 +79,7 @@ int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){
|
||||
unsigned y = ystart;
|
||||
if(xstart < 0){
|
||||
if(xstart != -1){
|
||||
logerror("invalid xstart: %d\n", xstart);
|
||||
logerror("invalid x: %d\n", xstart);
|
||||
return -1;
|
||||
}
|
||||
xstart = n->x;
|
||||
@ -88,11 +96,12 @@ int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){
|
||||
if(strcmp(fillegc, targ) == 0){
|
||||
return 0;
|
||||
}
|
||||
int ret = -1;
|
||||
// we need an external copy of this, since we'll be writing to it on
|
||||
// the first call into ncplane_polyfill_recurse()
|
||||
// the first call into ncplane_polyfill_inner()
|
||||
char* targcopy = strdup(targ);
|
||||
if(targcopy){
|
||||
ret = ncplane_polyfill_recurse(n, y, x, c, targcopy);
|
||||
ret = ncplane_polyfill_inner(n, y, x, c, targcopy);
|
||||
free(targcopy);
|
||||
}
|
||||
return ret;
|
||||
@ -141,69 +150,6 @@ bool check_gradient_args(uint64_t ul, uint64_t ur, uint64_t bl, uint64_t br){
|
||||
return false;
|
||||
}
|
||||
|
||||
// takes a signed starting coordinate (where -1 indicates the cursor's
|
||||
// position), and an unsigned vector (where 0 indicates "everything
|
||||
// remaining", i.e. to the right and below). returns 0 iff everything
|
||||
// is valid and on the plane, filling in 'ystart'/'xstart' with the
|
||||
// (non-negative) starting coordinates and 'ylen'/'xlen with the
|
||||
// (positive) dimensions of the affected area.
|
||||
static int
|
||||
check_geometry_args(const ncplane* n, int y, int x,
|
||||
unsigned* ylen, unsigned* xlen,
|
||||
unsigned* ystart, unsigned* xstart){
|
||||
// handle the special -1 case for y/x, and reject other negatives
|
||||
if(y < 0){
|
||||
if(y != -1){
|
||||
logerror("invalid y: %d\n", y);
|
||||
return -1;
|
||||
}
|
||||
y = n->y;
|
||||
}
|
||||
if(x < 0){
|
||||
if(x != -1){
|
||||
logerror("invalid x: %d\n", x);
|
||||
return -1;
|
||||
}
|
||||
x = n->x;
|
||||
}
|
||||
// y and x are both now definitely positive, but might be off-plane.
|
||||
// lock in y and x as ystart and xstart for unsigned comparisons.
|
||||
*ystart = y;
|
||||
*xstart = x;
|
||||
unsigned ymax, xmax;
|
||||
ncplane_dim_yx(n, &ymax, &xmax);
|
||||
if(*ystart >= ymax || *xstart >= xmax){
|
||||
logerror("invalid starting coordinates: %u/%u\n", *ystart, *xstart);
|
||||
return -1;
|
||||
}
|
||||
// handle the special 0 case for ylen/xlen
|
||||
if(*ylen == 0){
|
||||
*ylen = ymax - *ystart;
|
||||
}
|
||||
if(*xlen == 0){
|
||||
*xlen = xmax - *xstart;
|
||||
}
|
||||
// ensure ylen/xlen are on-plane
|
||||
if(*ylen > ymax){
|
||||
logerror("ylen > dimy %u > %u\n", *ylen, ymax);
|
||||
return -1;
|
||||
}
|
||||
if(*xlen > xmax){
|
||||
logerror("xlen > dimx %u > %u\n", *xlen, xmax);
|
||||
return -1;
|
||||
}
|
||||
// ensure x + xlen and y + ylen are on-plane, without overflow
|
||||
if(ymax - *ylen < *ystart){
|
||||
logerror("y + ylen > ymax %u + %u > %u\n", *ystart, *ylen, ymax);
|
||||
return -1;
|
||||
}
|
||||
if(xmax - *xlen < *xstart){
|
||||
logerror("x + xlen > xmax %u + %u > %u\n", *xstart, *xlen, xmax);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// calculate both channels of a gradient at a particular point, knowing that
|
||||
// we're using double halfblocks, into `c`->channels.
|
||||
static inline void
|
||||
@ -248,7 +194,7 @@ int ncplane_gradient2x1(ncplane* n, int y, int x, unsigned ylen, unsigned xlen,
|
||||
if(pool_blit_direct(&n->pool, targc, "▀", strlen("▀"), 1) <= 0){
|
||||
return -1;
|
||||
}
|
||||
calc_highgradient(targc, ul, ur, ll, lr, yy - ystart, xx - xstart, ylen, xlen);
|
||||
calc_highgradient(targc, ul, ur, ll, lr, yy - ystart, xx - xstart, ylen * 2, xlen);
|
||||
++total;
|
||||
}
|
||||
}
|
||||
|
@ -1448,6 +1448,69 @@ int drop_signals(void* nc);
|
||||
int block_signals(sigset_t* old_blocked_signals);
|
||||
int unblock_signals(const sigset_t* old_blocked_signals);
|
||||
|
||||
// takes a signed starting coordinate (where -1 indicates the cursor's
|
||||
// position), and an unsigned vector (where 0 indicates "everything
|
||||
// remaining", i.e. to the right and below). returns 0 iff everything
|
||||
// is valid and on the plane, filling in 'ystart'/'xstart' with the
|
||||
// (non-negative) starting coordinates and 'ylen'/'xlen with the
|
||||
// (positive) dimensions of the affected area.
|
||||
static inline int
|
||||
check_geometry_args(const ncplane* n, int y, int x,
|
||||
unsigned* ylen, unsigned* xlen,
|
||||
unsigned* ystart, unsigned* xstart){
|
||||
// handle the special -1 case for y/x, and reject other negatives
|
||||
if(y < 0){
|
||||
if(y != -1){
|
||||
logerror("invalid y: %d\n", y);
|
||||
return -1;
|
||||
}
|
||||
y = n->y;
|
||||
}
|
||||
if(x < 0){
|
||||
if(x != -1){
|
||||
logerror("invalid x: %d\n", x);
|
||||
return -1;
|
||||
}
|
||||
x = n->x;
|
||||
}
|
||||
// y and x are both now definitely positive, but might be off-plane.
|
||||
// lock in y and x as ystart and xstart for unsigned comparisons.
|
||||
*ystart = y;
|
||||
*xstart = x;
|
||||
unsigned ymax, xmax;
|
||||
ncplane_dim_yx(n, &ymax, &xmax);
|
||||
if(*ystart >= ymax || *xstart >= xmax){
|
||||
logerror("invalid starting coordinates: %u/%u\n", *ystart, *xstart);
|
||||
return -1;
|
||||
}
|
||||
// handle the special 0 case for ylen/xlen
|
||||
if(*ylen == 0){
|
||||
*ylen = ymax - *ystart;
|
||||
}
|
||||
if(*xlen == 0){
|
||||
*xlen = xmax - *xstart;
|
||||
}
|
||||
// ensure ylen/xlen are on-plane
|
||||
if(*ylen > ymax){
|
||||
logerror("ylen > dimy %u > %u\n", *ylen, ymax);
|
||||
return -1;
|
||||
}
|
||||
if(*xlen > xmax){
|
||||
logerror("xlen > dimx %u > %u\n", *xlen, xmax);
|
||||
return -1;
|
||||
}
|
||||
// ensure x + xlen and y + ylen are on-plane, without overflow
|
||||
if(ymax - *ylen < *ystart){
|
||||
logerror("y + ylen > ymax %u + %u > %u\n", *ystart, *ylen, ymax);
|
||||
return -1;
|
||||
}
|
||||
if(xmax - *xlen < *xstart){
|
||||
logerror("x + xlen > xmax %u + %u > %u\n", *xstart, *xlen, xmax);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ncvisual_printbanner(fbuf* f);
|
||||
|
||||
// alpha comes to us 0--255, but we have only 3 alpha values to map them to
|
||||
@ -1615,6 +1678,27 @@ resize_bitmap(const uint32_t* bmap, int srows, int scols, size_t sstride,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// a neighbor on which to polyfill. by the time we get to it, it might or
|
||||
// might not have been filled in. if so, discard immediately. otherwise,
|
||||
// check self, and if valid, push all neighbors.
|
||||
struct topolyfill {
|
||||
int y, x;
|
||||
struct topolyfill* next;
|
||||
};
|
||||
|
||||
static inline struct topolyfill*
|
||||
create_polyfill_op(int y, int x, struct topolyfill** stck){
|
||||
// cast for the benefit of c++ callers
|
||||
struct topolyfill* n = (struct topolyfill*)malloc(sizeof(*n));
|
||||
if(n){
|
||||
n->y = y;
|
||||
n->x = x;
|
||||
n->next = *stck;
|
||||
*stck = n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// implemented by a multimedia backend (ffmpeg or oiio), and installed
|
||||
// prior to calling notcurses_core_init() (by notcurses_init()).
|
||||
typedef struct ncvisual_implementation {
|
||||
|
@ -22,8 +22,9 @@ detect_utf8(void){
|
||||
}
|
||||
}
|
||||
|
||||
const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec,
|
||||
uintmax_t mult, int uprefix){
|
||||
const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal,
|
||||
char* buf, int omitdec, uintmax_t mult,
|
||||
int uprefix){
|
||||
// FIXME this is global to the process...ick :/
|
||||
fesetround(FE_TONEAREST);
|
||||
pthread_once(&utf8_detector, detect_utf8);
|
||||
@ -70,15 +71,17 @@ const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec,
|
||||
// 1,024). That can overflow with large 64-bit values, but we can first
|
||||
// divide both sides by mult, and then scale by 100.
|
||||
if(omitdec && (val % dv) == 0){
|
||||
sprintfed = sprintf(buf, "%" PRIu64 "%lc", (uint64_t)(val / dv),
|
||||
sprintfed = snprintf(buf, s, "%" PRIu64 "%lc", (uint64_t)(val / dv),
|
||||
(wint_t)prefixes[consumed - 1]);
|
||||
}else{
|
||||
sprintfed = sprintf(buf, "%.2f%lc", (double)val / dv,
|
||||
sprintfed = snprintf(buf, s, "%.2f%lc", (double)val / dv,
|
||||
(wint_t)prefixes[consumed - 1]);
|
||||
}
|
||||
if(uprefix){
|
||||
if((size_t)sprintfed < s){
|
||||
buf[sprintfed] = uprefix;
|
||||
buf[sprintfed + 1] = '\0';
|
||||
buf[++sprintfed] = '\0';
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
@ -86,22 +89,29 @@ const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec,
|
||||
// val / decimal < dv (or we ran out of prefixes)
|
||||
if(omitdec && val % decimal == 0){
|
||||
if(consumed){
|
||||
sprintfed = sprintf(buf, "%" PRIu64 "%lc", (uint64_t)(val / decimal),
|
||||
sprintfed = snprintf(buf, s, "%" PRIu64 "%lc", (uint64_t)(val / decimal),
|
||||
(wint_t)subprefixes[consumed - 1]);
|
||||
}else{
|
||||
sprintfed = sprintf(buf, "%" PRIu64, (uint64_t)(val / decimal));
|
||||
sprintfed = snprintf(buf, s, "%" PRIu64, (uint64_t)(val / decimal));
|
||||
}
|
||||
}else{
|
||||
if(consumed){
|
||||
sprintfed = sprintf(buf, "%.2f%lc", (double)val / decimal,
|
||||
sprintfed = snprintf(buf, s, "%.2f%lc", (double)val / decimal,
|
||||
(wint_t)subprefixes[consumed - 1]);
|
||||
}else{
|
||||
sprintfed = sprintf(buf, "%.2f", (double)val / decimal);
|
||||
sprintfed = snprintf(buf, s, "%.2f", (double)val / decimal);
|
||||
}
|
||||
}
|
||||
if(consumed && uprefix){
|
||||
if((size_t)sprintfed < s){
|
||||
buf[sprintfed] = uprefix;
|
||||
buf[sprintfed + 1] = '\0';
|
||||
buf[++sprintfed] = '\0';
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec,
|
||||
uintmax_t mult, int uprefix){
|
||||
return ncnmetric(val, SIZE_MAX, decimal, buf, omitdec, mult, uprefix);
|
||||
}
|
||||
|
@ -1994,6 +1994,7 @@ int ncplane_vline_interp(ncplane* n, const nccell* c, unsigned len,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// we must have at least 2x2, or it's an error
|
||||
int ncplane_box(ncplane* n, const nccell* ul, const nccell* ur,
|
||||
const nccell* ll, const nccell* lr, const nccell* hl,
|
||||
const nccell* vl, unsigned ystop, unsigned xstop,
|
||||
@ -2845,23 +2846,11 @@ is_bg_p(int idx, int py, int px, int width){
|
||||
|
||||
static inline uint32_t*
|
||||
ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit,
|
||||
unsigned begy, unsigned begx, unsigned leny,
|
||||
unsigned lenx, unsigned* pxdimy, unsigned* pxdimx){
|
||||
int begy, int begx, unsigned leny, unsigned lenx,
|
||||
unsigned* pxdimy, unsigned* pxdimx){
|
||||
const notcurses* ncur = ncplane_notcurses_const(nc);
|
||||
if(begx >= (unsigned)nc->lenx || begy >= (unsigned)nc->leny){
|
||||
logerror("invalid origin (%u,%u)\n", begy, begx);
|
||||
return NULL;
|
||||
}
|
||||
if(lenx == 0){ // -1 means "to the end"; use all space available
|
||||
lenx = nc->lenx - begx;
|
||||
}
|
||||
if(leny == 0){
|
||||
leny = nc->leny - begy;
|
||||
}
|
||||
//fprintf(stderr, "sum: %d/%d avail: %d/%d\n", begy + leny, begx + lenx, nc->leny, nc->lenx);
|
||||
if(nc->lenx - begx < lenx || nc->leny - begy < leny){
|
||||
logerror("invalid specs %u + %u > %d or %u + %u > %d\n",
|
||||
begx, lenx, nc->lenx, begy, leny, nc->leny);
|
||||
unsigned ystart, xstart;
|
||||
if(check_geometry_args(nc, begy, begx, &leny, &lenx, &ystart, &xstart)){
|
||||
return NULL;
|
||||
}
|
||||
if(blit == NCBLIT_PIXEL){ // FIXME extend this to support sprixels
|
||||
@ -2887,8 +2876,8 @@ ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit,
|
||||
uint32_t* ret = malloc(sizeof(*ret) * lenx * bset->width * leny * bset->height);
|
||||
//fprintf(stderr, "GEOM: %d/%d %d/%d ret: %p\n", bset->height, bset->width, *pxdimy, *pxdimx, ret);
|
||||
if(ret){
|
||||
for(unsigned y = begy, targy = 0 ; y < begy + leny ; ++y, targy += bset->height){
|
||||
for(unsigned x = begx, targx = 0 ; x < begx + lenx ; ++x, targx += bset->width){
|
||||
for(unsigned y = ystart, targy = 0 ; y < ystart + leny ; ++y, targy += bset->height){
|
||||
for(unsigned x = xstart, targx = 0 ; x < xstart + lenx ; ++x, targx += bset->width){
|
||||
uint16_t stylemask;
|
||||
uint64_t channels;
|
||||
char* c = ncplane_at_yx(nc, y, x, &stylemask, &channels);
|
||||
@ -2941,7 +2930,7 @@ ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit,
|
||||
}
|
||||
|
||||
uint32_t* ncplane_as_rgba(const ncplane* nc, ncblitter_e blit,
|
||||
unsigned begy, unsigned begx, unsigned leny,
|
||||
int begy, int begx, unsigned leny,
|
||||
unsigned lenx, unsigned* pxdimy, unsigned* pxdimx){
|
||||
unsigned px, py;
|
||||
if(!pxdimy){
|
||||
@ -2955,39 +2944,15 @@ uint32_t* ncplane_as_rgba(const ncplane* nc, ncblitter_e blit,
|
||||
|
||||
// return a heap-allocated copy of the contents
|
||||
char* ncplane_contents(ncplane* nc, int begy, int begx, unsigned leny, unsigned lenx){
|
||||
if(begy < 0){
|
||||
if(begy != -1){
|
||||
logerror("invalid y coordinate: %d\n", begy);
|
||||
}
|
||||
begy = nc->y;
|
||||
}
|
||||
if(begx < 0){
|
||||
if(begx != -1){
|
||||
logerror("invalid x coordinate: %d\n", begx);
|
||||
}
|
||||
begx = nc->x;
|
||||
}
|
||||
if((unsigned)begx >= nc->lenx || (unsigned)begy >= nc->leny){
|
||||
logerror("beginning coordinates (%d/%d) exceeded area (%u/%u)\n",
|
||||
begy, begx, nc->leny, nc->lenx);
|
||||
return NULL;
|
||||
}
|
||||
if(lenx == 0){ // 0 means "to the end"; use all space available
|
||||
lenx = nc->lenx - begx;
|
||||
}
|
||||
if(leny == 0){
|
||||
leny = nc->leny - begy;
|
||||
}
|
||||
if(nc->lenx - begx < lenx || nc->leny - begy < leny){
|
||||
logerror("ending coordinates (%u/%u) exceeded lengths (%u/%u)\n",
|
||||
begy + leny, begx + lenx, nc->leny, nc->lenx);
|
||||
unsigned ystart, xstart;
|
||||
if(check_geometry_args(nc, begy, begx, &leny, &lenx, &ystart, &xstart)){
|
||||
return NULL;
|
||||
}
|
||||
size_t retlen = 1;
|
||||
char* ret = malloc(retlen);
|
||||
if(ret){
|
||||
for(unsigned y = begy, targy = 0 ; y < begy + leny ; ++y, targy += 2){
|
||||
for(unsigned x = begx, targx = 0 ; x < begx + lenx ; ++x, ++targx){
|
||||
for(unsigned y = ystart, targy = 0 ; y < ystart + leny ; ++y, targy += 2){
|
||||
for(unsigned x = xstart, targx = 0 ; x < xstart + lenx ; ++x, ++targx){
|
||||
nccell ncl = CELL_TRIVIAL_INITIALIZER;
|
||||
// we need ncplane_at_yx_cell() here instead of ncplane_at_yx(),
|
||||
// because we should only have one copy of each wide EGC.
|
||||
|
@ -61,10 +61,10 @@ ncreader_redraw(ncreader* n){
|
||||
assert(n->xproject >= 0);
|
||||
assert(n->textarea->lenx >= n->ncp->lenx);
|
||||
assert(n->textarea->leny >= n->ncp->leny);
|
||||
for(int y = 0 ; y < n->ncp->leny ; ++y){
|
||||
const int texty = y;
|
||||
for(int x = 0 ; x < n->ncp->lenx ; ++x){
|
||||
const int textx = x + n->xproject;
|
||||
for(unsigned y = 0 ; y < n->ncp->leny ; ++y){
|
||||
const unsigned texty = y;
|
||||
for(unsigned x = 0 ; x < n->ncp->lenx ; ++x){
|
||||
const unsigned textx = x + n->xproject;
|
||||
const nccell* src = &n->textarea->fb[nfbcellidx(n->textarea, texty, textx)];
|
||||
nccell* dst = &n->ncp->fb[nfbcellidx(n->ncp, y, x)];
|
||||
//fprintf(stderr, "projecting %d/%d [%s] to %d/%d [%s]\n", texty, textx, cell_extended_gcluster(n->textarea, src), y, x, cell_extended_gcluster(n->ncp, dst));
|
||||
@ -121,9 +121,9 @@ int ncreader_move_left(ncreader* n){
|
||||
// row. if on the right side of the viewarea, but not the right side of the
|
||||
// textarea, pans right. returns 0 if a move was made.
|
||||
int ncreader_move_right(ncreader* n){
|
||||
int viewx = n->ncp->x;
|
||||
int textx = n->textarea->x;
|
||||
int y = n->ncp->y;
|
||||
unsigned textx = n->textarea->x;
|
||||
unsigned y = n->ncp->y;
|
||||
unsigned viewx = n->ncp->x;
|
||||
//fprintf(stderr, "moving right: tcurs: %dx%d vcurs: %dx%d xproj: %d\n", y, textx, y, viewx, n->xproject);
|
||||
if(textx >= n->textarea->lenx - 1){
|
||||
// are we on the last column of the textarea? if so, we must also be on
|
||||
@ -171,7 +171,7 @@ int ncreader_move_up(ncreader* n){
|
||||
// try to move down. does not move past the bottom of the textarea.
|
||||
// returns 0 if a move was made.
|
||||
int ncreader_move_down(ncreader* n){
|
||||
int y = n->ncp->y;
|
||||
unsigned y = n->ncp->y;
|
||||
if(y >= n->textarea->leny - 1){
|
||||
// are we on the last row of the textarea? if so, we can't move.
|
||||
return -1;
|
||||
@ -190,14 +190,14 @@ int ncreader_write_egc(ncreader* n, const char* egc){
|
||||
logerror("Fed illegal UTF-8 [%s]\n", egc);
|
||||
return -1;
|
||||
}
|
||||
if(n->textarea->x >= n->textarea->lenx - cols){
|
||||
if(n->textarea->x >= (int)n->textarea->lenx - cols){
|
||||
if(n->horscroll){
|
||||
if(ncplane_resize_simple(n->textarea, n->textarea->leny, n->textarea->lenx + cols)){
|
||||
return -1;
|
||||
}
|
||||
++n->xproject;
|
||||
}
|
||||
}else if(n->ncp->x >= n->ncp->lenx){
|
||||
}else if((unsigned)n->ncp->x >= n->ncp->lenx){
|
||||
++n->xproject;
|
||||
}
|
||||
// use ncplane_putegc on both planes because it'll get cursor movement right
|
||||
@ -207,12 +207,12 @@ int ncreader_write_egc(ncreader* n, const char* egc){
|
||||
if(ncplane_putegc(n->ncp, egc, NULL) < 0){
|
||||
return -1;
|
||||
}
|
||||
if(n->textarea->x >= n->textarea->lenx - cols){
|
||||
if(n->textarea->x >= (int)n->textarea->lenx - cols){
|
||||
if(!n->horscroll){
|
||||
n->textarea->x = n->textarea->lenx - cols;
|
||||
}
|
||||
}
|
||||
if(n->ncp->x >= n->ncp->lenx - cols){
|
||||
if(n->ncp->x >= (int)n->ncp->lenx - cols){
|
||||
n->ncp->x = n->ncp->lenx - cols;
|
||||
}
|
||||
ncreader_redraw(n);
|
||||
@ -275,7 +275,7 @@ ncreader_ctrl_input(ncreader* n, const ncinput* ni){
|
||||
}
|
||||
break;
|
||||
case 'E': // cursor to end of line
|
||||
while(n->textarea->x < ncplane_dim_x(n->textarea) - 1){
|
||||
while(n->textarea->x < (int)ncplane_dim_x(n->textarea) - 1){
|
||||
if(ncreader_move_right(n)){
|
||||
break;
|
||||
}
|
||||
@ -320,7 +320,7 @@ ncreader_alt_input(ncreader* n, const ncinput* ni){
|
||||
}
|
||||
break;
|
||||
case 'f': // forward one word (past end cell)
|
||||
while(n->textarea->x < ncplane_dim_x(n->textarea) - 1){
|
||||
while(n->textarea->x < (int)ncplane_dim_x(n->textarea) - 1){
|
||||
if(ncreader_move_right(n)){
|
||||
break;
|
||||
}
|
||||
|
@ -186,7 +186,10 @@ tablet_geom(const ncreel* nr, nctablet* t, int* begx, int* begy,
|
||||
//fprintf(stderr, "jigsawing %p with %d/%d dir %d\n", t, frontiertop, frontierbottom, direction);
|
||||
*begy = 0;
|
||||
*begx = 0;
|
||||
ncplane_dim_yx(nr->p, leny, lenx);
|
||||
unsigned uleny, ulenx;
|
||||
ncplane_dim_yx(nr->p, &uleny, &ulenx);
|
||||
*leny = uleny;
|
||||
*lenx = ulenx;
|
||||
if(frontiertop < 0){
|
||||
if(direction == DIRECTION_UP){
|
||||
return -1;
|
||||
@ -501,14 +504,15 @@ tighten_reel_down(ncreel* r, int ybot){
|
||||
if(cur->p == NULL){
|
||||
break;
|
||||
}
|
||||
int cury, curx, ylen;
|
||||
int cury, curx;
|
||||
unsigned ylen;
|
||||
ncplane_yx(cur->p, &cury, &curx);
|
||||
ncplane_dim_yx(cur->p, &ylen, NULL);
|
||||
if(cury <= ybot - ylen - 1){
|
||||
if(cury <= ybot - (int)ylen - 1){
|
||||
break;
|
||||
}
|
||||
//fprintf(stderr, "tightening %p down to %d from %d\n", cur, ybot - ylen, cury);
|
||||
cury = ybot - ylen;
|
||||
cury = ybot - (int)ylen;
|
||||
ncplane_move_yx(cur->p, cury, curx);
|
||||
ybot = cury - 1;
|
||||
if((cur = cur->prev) == r->tablets){
|
||||
@ -580,7 +584,7 @@ tighten_reel(ncreel* r){
|
||||
const int ybot = rylen - 1 + !!(r->ropts.bordermask & NCBOXMASK_BOTTOM);
|
||||
// FIXME want to tighten down whenever we're at the bottom, and the reel
|
||||
// is full, not just in this case (this can leave a gap of more than 1 row)
|
||||
if(yoff + ylen + 1 >= ybot){
|
||||
if(yoff + (int)ylen + 1 >= ybot){
|
||||
if(tighten_reel_down(r, ybot)){
|
||||
return -1;
|
||||
}
|
||||
|
@ -19,16 +19,16 @@ typedef struct ncselector {
|
||||
unsigned selected; // index of selection
|
||||
unsigned startdisp; // index of first option displayed
|
||||
unsigned maxdisplay; // max number of items to display, 0 -> no limit
|
||||
int longop; // columns occupied by longest option
|
||||
int longdesc; // columns occupied by longest description
|
||||
unsigned longop; // columns occupied by longest option
|
||||
unsigned longdesc; // columns occupied by longest description
|
||||
struct ncselector_int* items; // list of items and descriptions, heap-copied
|
||||
unsigned itemcount; // number of pairs in 'items'
|
||||
char* title; // can be NULL, in which case there's no riser
|
||||
int titlecols; // columns occupied by title
|
||||
unsigned titlecols; // columns occupied by title
|
||||
char* secondary; // can be NULL
|
||||
int secondarycols; // columns occupied by secondary
|
||||
unsigned secondarycols; // columns occupied by secondary
|
||||
char* footer; // can be NULL
|
||||
int footercols; // columns occupied by footer
|
||||
unsigned footercols; // columns occupied by footer
|
||||
uint64_t opchannels; // option channels
|
||||
uint64_t descchannels; // description channels
|
||||
uint64_t titlechannels; // title channels
|
||||
@ -42,15 +42,15 @@ typedef struct ncmultiselector {
|
||||
unsigned current; // index of highlighted item
|
||||
unsigned startdisp; // index of first option displayed
|
||||
unsigned maxdisplay; // max number of items to display, 0 -> no limit
|
||||
int longitem; // columns occupied by longest item
|
||||
unsigned longitem; // columns occupied by longest item
|
||||
struct ncmselector_int* items; // items, descriptions, and statuses, heap-copied
|
||||
unsigned itemcount; // number of pairs in 'items'
|
||||
char* title; // can be NULL, in which case there's no riser
|
||||
unsigned titlecols; // columns occupied by title
|
||||
char* secondary; // can be NULL
|
||||
int secondarycols; // columns occupied by secondary
|
||||
unsigned secondarycols; // columns occupied by secondary
|
||||
char* footer; // can be NULL
|
||||
int footercols; // columns occupied by footer
|
||||
unsigned footercols; // columns occupied by footer
|
||||
uint64_t opchannels; // option channels
|
||||
uint64_t descchannels; // description channels
|
||||
uint64_t titlechannels; // title channels
|
||||
@ -62,7 +62,7 @@ typedef struct ncmultiselector {
|
||||
// ideal body width given the ncselector's items and secondary/footer
|
||||
static int
|
||||
ncselector_body_width(const ncselector* n){
|
||||
int cols = 0;
|
||||
unsigned cols = 0;
|
||||
// the body is the maximum of
|
||||
// * longop + longdesc + 5
|
||||
// * secondary + 2
|
||||
@ -162,7 +162,7 @@ ncselector_draw(ncselector* n){
|
||||
// Top line of body (background and possibly up arrow)
|
||||
++yoff;
|
||||
ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
|
||||
for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
|
||||
ncplane_putc(n->ncp, &transc);
|
||||
}
|
||||
@ -181,12 +181,12 @@ ncselector_draw(ncselector* n){
|
||||
n->uarrowy = yoff;
|
||||
unsigned printidx = n->startdisp;
|
||||
unsigned printed = 0;
|
||||
for(yoff += 1 ; yoff < dimy - 2 ; ++yoff){
|
||||
for(yoff += 1 ; yoff < (int)dimy - 2 ; ++yoff){
|
||||
if(n->maxdisplay && printed == n->maxdisplay){
|
||||
break;
|
||||
}
|
||||
ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
|
||||
for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
for(int i = xoff + 1 ; i < (int)dimx - 1 ; ++i){
|
||||
nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
|
||||
ncplane_putc(n->ncp, &transc);
|
||||
}
|
||||
@ -207,7 +207,7 @@ ncselector_draw(ncselector* n){
|
||||
}
|
||||
// Bottom line of body (background and possibly down arrow)
|
||||
ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
|
||||
for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
for(int i = xoff + 1 ; i < (int)dimx - 1 ; ++i){
|
||||
nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
|
||||
ncplane_putc(n->ncp, &transc);
|
||||
}
|
||||
@ -225,8 +225,8 @@ ncselector_draw(ncselector* n){
|
||||
|
||||
// calculate the necessary dimensions based off properties of the selector
|
||||
static void
|
||||
ncselector_dim_yx(const ncselector* n, int* ncdimy, int* ncdimx){
|
||||
int rows = 0, cols = 0; // desired dimensions
|
||||
ncselector_dim_yx(const ncselector* n, unsigned* ncdimy, unsigned* ncdimx){
|
||||
unsigned rows = 0, cols = 0; // desired dimensions
|
||||
const ncplane* parent = ncplane_parent(n->ncp);
|
||||
unsigned dimy, dimx; // dimensions of containing plane
|
||||
ncplane_dim_yx(parent, &dimy, &dimx);
|
||||
@ -305,13 +305,21 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
|
||||
}
|
||||
for(ns->itemcount = 0 ; ns->itemcount < itemcount ; ++ns->itemcount){
|
||||
const struct ncselector_item* src = &opts->items[ns->itemcount];
|
||||
int cols = ncstrwidth(src->option);
|
||||
int unsafe = ncstrwidth(src->option);
|
||||
if(unsafe < 0){
|
||||
goto freeitems;
|
||||
}
|
||||
unsigned cols = unsafe;
|
||||
ns->items[ns->itemcount].opcolumns = cols;
|
||||
if(cols > ns->longop){
|
||||
ns->longop = cols;
|
||||
}
|
||||
const char *desc = src->desc ? src->desc : "";
|
||||
cols = ncstrwidth(desc);
|
||||
unsafe = ncstrwidth(desc);
|
||||
if(unsafe < 0){
|
||||
goto freeitems;
|
||||
}
|
||||
cols = unsafe;
|
||||
ns->items[ns->itemcount].desccolumns = cols;
|
||||
if(cols > ns->longdesc){
|
||||
ns->longdesc = cols;
|
||||
@ -324,7 +332,7 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){
|
||||
goto freeitems;
|
||||
}
|
||||
}
|
||||
int dimy, dimx;
|
||||
unsigned dimy, dimx;
|
||||
ns->ncp = n;
|
||||
ncselector_dim_yx(ns, &dimy, &dimx);
|
||||
if(ncplane_resize_simple(n, dimy, dimx)){
|
||||
@ -347,7 +355,7 @@ freeitems:
|
||||
}
|
||||
|
||||
int ncselector_additem(ncselector* n, const struct ncselector_item* item){
|
||||
int origdimy, origdimx;
|
||||
unsigned origdimy, origdimx;
|
||||
ncselector_dim_yx(n, &origdimy, &origdimx);
|
||||
size_t newsize = sizeof(*n->items) * (n->itemcount + 1);
|
||||
struct ncselector_int* items = realloc(n->items, newsize);
|
||||
@ -358,7 +366,11 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
|
||||
n->items[n->itemcount].option = strdup(item->option);
|
||||
const char *desc = item->desc ? item->desc : "";
|
||||
n->items[n->itemcount].desc = strdup(desc);
|
||||
int cols = ncstrwidth(item->option);
|
||||
int usafecols = ncstrwidth(item->option);
|
||||
if(usafecols < 0){
|
||||
return -1;
|
||||
}
|
||||
unsigned cols = usafecols;
|
||||
n->items[n->itemcount].opcolumns = cols;
|
||||
if(cols > n->longop){
|
||||
n->longop = cols;
|
||||
@ -369,7 +381,7 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
|
||||
n->longdesc = cols;
|
||||
}
|
||||
++n->itemcount;
|
||||
int dimy, dimx;
|
||||
unsigned dimy, dimx;
|
||||
ncselector_dim_yx(n, &dimy, &dimx);
|
||||
if(origdimx < dimx || origdimy < dimy){ // resize if too small
|
||||
ncplane_resize_simple(n->ncp, dimy, dimx);
|
||||
@ -378,7 +390,7 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){
|
||||
}
|
||||
|
||||
int ncselector_delitem(ncselector* n, const char* item){
|
||||
int origdimy, origdimx;
|
||||
unsigned origdimy, origdimx;
|
||||
ncselector_dim_yx(n, &origdimy, &origdimx);
|
||||
bool found = false;
|
||||
int maxop = 0, maxdesc = 0;
|
||||
@ -410,7 +422,7 @@ int ncselector_delitem(ncselector* n, const char* item){
|
||||
if(found){
|
||||
n->longop = maxop;
|
||||
n->longdesc = maxdesc;
|
||||
int dimy, dimx;
|
||||
unsigned dimy, dimx;
|
||||
ncselector_dim_yx(n, &dimy, &dimx);
|
||||
if(origdimx > dimx || origdimy > dimy){ // resize if too big
|
||||
ncplane_resize_simple(n->ncp, dimy, dimx);
|
||||
@ -560,9 +572,9 @@ ncplane* ncmultiselector_plane(ncmultiselector* n){
|
||||
}
|
||||
|
||||
// ideal body width given the ncselector's items and secondary/footer
|
||||
static int
|
||||
static unsigned
|
||||
ncmultiselector_body_width(const ncmultiselector* n){
|
||||
int cols = 0;
|
||||
unsigned cols = 0;
|
||||
// the body is the maximum of
|
||||
// * longop + longdesc + 5
|
||||
// * secondary + 2
|
||||
@ -589,7 +601,7 @@ ncmultiselector_draw(ncmultiselector* n){
|
||||
// if we have a title, we'll draw a riser. the riser is two rows tall, and
|
||||
// exactly four columns longer than the title, and aligned to the right. we
|
||||
// draw a rounded box. the body will blow part or all of the bottom away.
|
||||
int yoff = 0;
|
||||
unsigned yoff = 0;
|
||||
if(n->title){
|
||||
size_t riserwidth = n->titlecols + 4;
|
||||
int offx = ncplane_halign(n->ncp, NCALIGN_RIGHT, riserwidth);
|
||||
@ -649,7 +661,7 @@ ncmultiselector_draw(ncmultiselector* n){
|
||||
// Top line of body (background and possibly up arrow)
|
||||
++yoff;
|
||||
ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
|
||||
for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
|
||||
ncplane_putc(n->ncp, &transc);
|
||||
}
|
||||
@ -670,7 +682,7 @@ ncmultiselector_draw(ncmultiselector* n){
|
||||
break;
|
||||
}
|
||||
ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
|
||||
for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
|
||||
ncplane_putc(n->ncp, &transc);
|
||||
}
|
||||
@ -700,7 +712,7 @@ ncmultiselector_draw(ncmultiselector* n){
|
||||
}
|
||||
// Bottom line of body (background and possibly down arrow)
|
||||
ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1);
|
||||
for(int i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
|
||||
nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell
|
||||
ncplane_putc(n->ncp, &transc);
|
||||
}
|
||||
@ -899,11 +911,19 @@ ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_option
|
||||
}
|
||||
for(ns->itemcount = 0 ; ns->itemcount < itemcount ; ++ns->itemcount){
|
||||
const struct ncmselector_item* src = &opts->items[ns->itemcount];
|
||||
int cols = ncstrwidth(src->option);
|
||||
int unsafe = ncstrwidth(src->option);
|
||||
if(unsafe < 0){
|
||||
goto freeitems;
|
||||
}
|
||||
unsigned cols = unsafe;
|
||||
if(cols > ns->longitem){
|
||||
ns->longitem = cols;
|
||||
}
|
||||
int cols2 = ncstrwidth(src->desc);
|
||||
unsafe = ncstrwidth(src->desc);
|
||||
if(unsafe < 0){
|
||||
goto freeitems;
|
||||
}
|
||||
unsigned cols2 = unsafe;
|
||||
if(cols + cols2 > ns->longitem){
|
||||
ns->longitem = cols + cols2;
|
||||
}
|
||||
|
@ -1193,7 +1193,7 @@ ncplane* ncvisual_render(notcurses* nc, ncvisual* ncv, const struct ncvisual_opt
|
||||
}
|
||||
|
||||
ncvisual* ncvisual_from_plane(const ncplane* n, ncblitter_e blit,
|
||||
unsigned begy, unsigned begx,
|
||||
int begy, int begx,
|
||||
unsigned leny, unsigned lenx){
|
||||
unsigned py, px;
|
||||
uint32_t* rgba = ncplane_as_rgba(n, blit, begy, begx, leny, lenx, &py, &px);
|
||||
@ -1269,26 +1269,6 @@ int ncvisual_at_yx(const ncvisual* n, unsigned y, unsigned x, uint32_t* pixel){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// a neighbor on which to polyfill. by the time we get to it, it might or
|
||||
// might not have been filled in. if so, discard immediately. otherwise,
|
||||
// check self, and if valid, push all neighbors.
|
||||
struct topolyfill {
|
||||
int y, x;
|
||||
struct topolyfill* next;
|
||||
};
|
||||
|
||||
static inline struct topolyfill*
|
||||
create_polyfill_op(int y, int x, struct topolyfill** stack){
|
||||
struct topolyfill* n = malloc(sizeof(*n));
|
||||
if(n){
|
||||
n->y = y;
|
||||
n->x = x;
|
||||
n->next = *stack;
|
||||
*stack = n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// originally i wrote this recursively, at which point it promptly began
|
||||
// exploding once i multithreaded the [yield] demo. hence the clumsy stack
|
||||
// and hand-rolled iteration. alas, poor yorick!
|
||||
@ -1314,6 +1294,7 @@ ncvisual_polyfill_core(ncvisual* n, unsigned y, unsigned x, uint32_t rgba, uint3
|
||||
*pixel = rgba;
|
||||
if(y){
|
||||
if(create_polyfill_op(y - 1, x, &stack) == NULL){
|
||||
// FIXME need free stack!
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -74,13 +74,14 @@ int main(int argc, char **argv){
|
||||
totalb += conv;
|
||||
add_wchar(&wbuf, &bufsize, &used, w);
|
||||
}
|
||||
int y, x, newy, newx;
|
||||
putchar('\n');
|
||||
unsigned y, x;
|
||||
ncdirect_cursor_yx(n, &y, &x);
|
||||
printf("%s", *argv);
|
||||
fflush(stdout);
|
||||
unsigned newy, newx;
|
||||
ncdirect_cursor_yx(n, &newy, &newx);
|
||||
int realcols = (newx - x) + ncdirect_dim_x(n) * (newy - y);
|
||||
unsigned realcols = (newx - x) + ncdirect_dim_x(n) * (newy - y);
|
||||
printf("\n iterated wcwidth: %d total bytes: %llu wcswidth: %d true width: %d\n\n",
|
||||
totalcols, (unsigned long long)totalb, wcswidth(wbuf, used), realcols);
|
||||
ncdirect_cursor_yx(n, &y, &x);
|
||||
@ -123,7 +124,7 @@ int main(int argc, char **argv){
|
||||
}
|
||||
ncdirect_set_fg_default(n);
|
||||
ncdirect_set_bg_default(n);
|
||||
for(int z = 0 ; z < realcols && z < ncdirect_dim_x(n) ; ++z){
|
||||
for(unsigned z = 0 ; z < realcols && z < ncdirect_dim_x(n) ; ++z){
|
||||
putchar('0' + z % 10);
|
||||
}
|
||||
if(realcols < ncdirect_dim_x(n)){
|
||||
|
@ -10,7 +10,7 @@ int main(void){
|
||||
if(!nc){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
int dimy, dimx;
|
||||
unsigned dimy, dimx;
|
||||
struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
|
||||
ncplane_printf_yx(n, dimy / 2 - 2, 0, "ࡢࡣࡤࡥࡦࡧࡨࡩࡪࢠࢡࢢࢣࢤࢥࢦࢧࢨࢩࢪࢫࢬࢭࢮࢯࢰࢱࢲࢳࢴࢶࢷࢸࢹࢺࢻࢼࢽः");
|
||||
ncplane_printf_yx(n, dimy / 2 - 1, 0, "࠲࠳࠴࠵࠶࠷࠸࠹࠺࠻࠼࠽࠾ࡀࡁࡂࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌࡍࡎࡏࡐࡑࡒࡓࡔࡕࡖࡗࡘ࡞ࡡ");
|
||||
|
@ -7,7 +7,7 @@
|
||||
static int
|
||||
across_row(struct notcurses* nc, int y, struct ncplane* n, struct ncplane* t,
|
||||
const struct timespec* ds){
|
||||
for(int x = 0 ; x < ncplane_dim_x(n) ; ++x){
|
||||
for(unsigned x = 0 ; x < ncplane_dim_x(n) ; ++x){
|
||||
if(ncplane_move_yx(t, y, x)){
|
||||
return -1;
|
||||
}
|
||||
@ -21,7 +21,7 @@ across_row(struct notcurses* nc, int y, struct ncplane* n, struct ncplane* t,
|
||||
|
||||
static int
|
||||
across_bmap(struct notcurses* nc, struct ncplane* n, struct ncplane* t, const struct timespec* ds){
|
||||
for(int y = 0 ; y < ncplane_dim_y(n) - 1 ; ++y){
|
||||
for(unsigned y = 0 ; y < ncplane_dim_y(n) - 1 ; ++y){
|
||||
if(across_row(nc, y, n, t, ds)){
|
||||
return -1;
|
||||
}
|
||||
|
@ -577,7 +577,9 @@ TEST_CASE("Fills") {
|
||||
const char* qr = "a very simple qr code";
|
||||
unsigned dimy, dimx;
|
||||
ncplane_dim_yx(n_, &dimy, &dimx);
|
||||
CHECK(0 < ncplane_qrcode(n_, &dimy, &dimx, qr, strlen(qr)));
|
||||
int sdimy = dimy;
|
||||
int sdimx = dimx;
|
||||
CHECK(0 < ncplane_qrcode(n_, &sdimy, &sdimx, qr, strlen(qr)));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user