normalize lenghts for line-drawing functions #1696

This commit is contained in:
nick black 2021-11-04 02:09:07 -04:00 committed by nick black
parent d80884ea48
commit 37f077a653
8 changed files with 95 additions and 72 deletions

View File

@ -16,7 +16,9 @@ rearrangements of Notcurses.
functions. Lengths are now `unsigned` as opposed to `int`. Where -1 was functions. Lengths are now `unsigned` as opposed to `int`. Where -1 was
being used to indicate "everything", 0 is now required. This affects being used to indicate "everything", 0 is now required. This affects
`ncplane_as_rgba()`, `ncplane_contents()`, and `ncvisual_from_plane()`, `ncplane_as_rgba()`, `ncplane_contents()`, and `ncvisual_from_plane()`,
which all used -1. which all used -1. A length of zero passed to line-drawing functions is
now an error. Several line-drawing functions now reliably return errors
as opposed to short successes.
* `ncvisual_geom()` has been introduced, using the `ncvgeom` struct * `ncvisual_geom()` has been introduced, using the `ncvgeom` struct
introduced for direct mode. This allows complete statement of geometry introduced for direct mode. This allows complete statement of geometry
for an `ncvisual`. It replaces `ncvisual_blitter_geom()`, which has been for an `ncvisual`. It replaces `ncvisual_blitter_geom()`, which has been

View File

@ -526,10 +526,11 @@ int ncdirect_putegc(struct ncdirect* nc, uint64_t channels,
// horizontal line, |len| cannot exceed the screen width minus the cursor's // horizontal line, |len| cannot exceed the screen width minus the cursor's
// offset. For a vertical line, it may be as long as you'd like; the screen // offset. For a vertical line, it may be as long as you'd like; the screen
// will scroll as necessary. All lines start at the current cursor position. // will scroll as necessary. All lines start at the current cursor position.
int ncdirect_hline_interp(struct ncdirect* n, const char* egc, int len, // A length of 0 is an error, resulting in a return of -1.
uint64_t h1, uint64_t h2); int ncdirect_hline_interp(struct ncdirect* n, const char* egc,
int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len, unsigned len, uint64_t h1, uint64_t h2);
uint64_t h1, uint64_t h2); int ncdirect_vline_interp(struct ncdirect* n, const char* egc,
unsigned len, uint64_t h1, uint64_t h2);
// Draw a box with its upper-left corner at the current cursor position, having // Draw a box with its upper-left corner at the current cursor position, having
// dimensions |ylen|x|xlen|. See ncplane_box() for more information. The // dimensions |ylen|x|xlen|. See ncplane_box() for more information. The
@ -1499,21 +1500,20 @@ on both sides. Boxes allow fairly detailed specification of how they're drawn.
// current cursor position. The cursor will end at the cell following the last // current cursor position. The cursor will end at the cell following the last
// cell output (even, perhaps counter-intuitively, when drawing vertical // cell output (even, perhaps counter-intuitively, when drawing vertical
// lines), just as if ncplane_putc() was called at that spot. Return the // lines), just as if ncplane_putc() was called at that spot. Return the
// number of cells drawn on success. On error, return the negative number of // number of cells drawn on success. A length of 0 is an error.
// cells drawn. int ncplane_hline_interp(struct ncplane* n, const nccell* c,
int ncplane_hline_interp(struct ncplane* n, const nccell* c, int len, unsigned len, uint64_t c1, uint64_t c2);
uint64_t c1, uint64_t c2);
static inline int static inline int
ncplane_hline(struct ncplane* n, const nccell* c, int len){ ncplane_hline(struct ncplane* n, const nccell* c, unsigned len){
return ncplane_hline_interp(n, c, len, c->channels, c->channels); return ncplane_hline_interp(n, c, len, c->channels, c->channels);
} }
int ncplane_vline_interp(struct ncplane* n, const nccell* c, int len, int ncplane_vline_interp(struct ncplane* n, const nccell* c,
uint64_t c1, uint64_t c2); unsigned len, uint64_t c1, uint64_t c2);
static inline int static inline int
ncplane_vline(struct ncplane* n, const nccell* c, int len){ ncplane_vline(struct ncplane* n, const nccell* c, unsigned len){
return ncplane_vline_interp(n, c, len, c->channels, c->channels); return ncplane_vline_interp(n, c, len, c->channels, c->channels);
} }

View File

@ -78,9 +78,9 @@ notcurses_direct - minimal notcurses instances for styling text
**const char* ncdirect_detected_terminal(const struct ncdirect* ***n***);** **const char* ncdirect_detected_terminal(const struct ncdirect* ***n***);**
**int ncdirect_hline_interp(struct ncdirect* ***n***, const char* ***egc***, int ***len***, uint64_t ***h1***, uint64_t ***h2***);** **int ncdirect_hline_interp(struct ncdirect* ***n***, const char* ***egc***, unsigned ***len***, uint64_t ***h1***, uint64_t ***h2***);**
**int ncdirect_vline_interp(struct ncdirect* ***n***, const char* ***egc***, int ***len***, uint64_t ***h1***, uint64_t ***h2***);** **int ncdirect_vline_interp(struct ncdirect* ***n***, const char* ***egc***, unsigned ***len***, uint64_t ***h1***, uint64_t ***h2***);**
**int ncdirect_box(struct ncdirect* ***n***, uint64_t ***ul***, uint64_t ***ur***, uint64_t ***ll***, uint64_t ***lr***, const wchar_t* ***wchars***, int ***ylen***, int ***xlen***, unsigned ***ctlword***);** **int ncdirect_box(struct ncdirect* ***n***, uint64_t ***ul***, uint64_t ***ur***, uint64_t ***ll***, uint64_t ***lr***, const wchar_t* ***wchars***, int ***ylen***, int ***xlen***, unsigned ***ctlword***);**

View File

@ -10,13 +10,13 @@ notcurses_lines - operations on lines and boxes
**#include <notcurses/notcurses.h>** **#include <notcurses/notcurses.h>**
**int ncplane_hline_interp(struct ncplane* ***n***, const nccell* ***c***, int ***len***, uint64_t ***c1***, uint64_t ***c2***);** **int ncplane_hline_interp(struct ncplane* ***n***, const nccell* ***c***, unsigned ***len***, uint64_t ***c1***, uint64_t ***c2***);**
**static inline int ncplane_hline(struct ncplane* ***n***, const nccell* ***c***, int ***len***);** **static inline int ncplane_hline(struct ncplane* ***n***, const nccell* ***c***, unsigned ***len***);**
**int ncplane_vline_interp(struct ncplane* ***n***, const nccell* ***c***, int ***len***, uint64_t ***c1***, uint64_t ***c2***);** **int ncplane_vline_interp(struct ncplane* ***n***, const nccell* ***c***, unsigned ***len***, uint64_t ***c1***, uint64_t ***c2***);**
**static inline int ncplane_vline(struct ncplane* ***n***, const nccell* ***c***, int ***len***);** **static inline int ncplane_vline(struct ncplane* ***n***, const nccell* ***c***, unsigned ***len***);**
```c ```c
#define NCBOXMASK_TOP 0x0001 #define NCBOXMASK_TOP 0x0001
@ -78,6 +78,10 @@ Box- and line-drawing is unaffected by a plane's scrolling status.
**ncplane_format** returns -1 if either **ystop** or **xstop** is less than the **ncplane_format** returns -1 if either **ystop** or **xstop** is less than the
current equivalent position, otherwise 0. current equivalent position, otherwise 0.
**ncplane_hline_interp**, **ncplane_hline**, **ncplane_vline_interp**, and
**ncplane_vline** all return the number of glyphs drawn on success, or -1
on failure. Passing a length of 0 is an error.
# SEE ALSO # SEE ALSO
**notcurses(3)**, **notcurses(3)**,

View File

@ -263,13 +263,13 @@ API const nccapabilities* ncdirect_capabilities(const struct ncdirect* n)
// horizontal line, |len| cannot exceed the screen width minus the cursor's // horizontal line, |len| cannot exceed the screen width minus the cursor's
// offset. For a vertical line, it may be as long as you'd like; the screen // offset. For a vertical line, it may be as long as you'd like; the screen
// will scroll as necessary. All lines start at the current cursor position. // will scroll as necessary. All lines start at the current cursor position.
API int ncdirect_hline_interp(struct ncdirect* n, const char* egc, int len, API int ncdirect_hline_interp(struct ncdirect* n, const char* egc,
uint64_t h1, uint64_t h2) unsigned len, uint64_t h1, uint64_t h2)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1, 2)));
API int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len, API int ncdirect_vline_interp(struct ncdirect* n, const char* egc,
uint64_t h1, uint64_t h2) unsigned len, uint64_t h1, uint64_t h2)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1, 2)));
// Draw a box with its upper-left corner at the current cursor position, having // Draw a box with its upper-left corner at the current cursor position, having
// dimensions |ylen|x|xlen|. See ncplane_box() for more information. The // dimensions |ylen|x|xlen|. See ncplane_box() for more information. The
@ -278,7 +278,7 @@ API int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len,
API int ncdirect_box(struct ncdirect* n, uint64_t ul, uint64_t ur, API int ncdirect_box(struct ncdirect* n, uint64_t ul, uint64_t ur,
uint64_t ll, uint64_t lr, const wchar_t* wchars, uint64_t ll, uint64_t lr, const wchar_t* wchars,
int ylen, int xlen, unsigned ctlword) int ylen, int xlen, unsigned ctlword)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1, 6)));
__attribute__ ((nonnull (1))) static inline int __attribute__ ((nonnull (1))) static inline int
ncdirect_light_box(struct ncdirect* n, uint64_t ul, uint64_t ur, ncdirect_light_box(struct ncdirect* n, uint64_t ul, uint64_t ur,

View File

@ -2156,20 +2156,22 @@ API int ncplane_puttext(struct ncplane* n, int y, ncalign_e align,
// cell output (even, perhaps counter-intuitively, when drawing vertical // cell output (even, perhaps counter-intuitively, when drawing vertical
// lines), just as if ncplane_putc() was called at that spot. Return the // lines), just as if ncplane_putc() was called at that spot. Return the
// number of cells drawn on success. On error, return the negative number of // number of cells drawn on success. On error, return the negative number of
// cells drawn. // cells drawn. A length of 0 is an error, resulting in a return of -1.
API int ncplane_hline_interp(struct ncplane* n, const nccell* c, int len, API int ncplane_hline_interp(struct ncplane* n, const nccell* c,
uint64_t c1, uint64_t c2); unsigned len, uint64_t c1, uint64_t c2)
__attribute__ ((nonnull (1, 2)));
static inline int __attribute__ ((nonnull (1, 2))) static inline int
ncplane_hline(struct ncplane* n, const nccell* c, int len){ ncplane_hline(struct ncplane* n, const nccell* c, unsigned len){
return ncplane_hline_interp(n, c, len, c->channels, c->channels); return ncplane_hline_interp(n, c, len, c->channels, c->channels);
} }
API int ncplane_vline_interp(struct ncplane* n, const nccell* c, int len, API int ncplane_vline_interp(struct ncplane* n, const nccell* c,
uint64_t c1, uint64_t c2); unsigned len, uint64_t c1, uint64_t c2)
__attribute__ ((nonnull (1, 2)));
static inline int __attribute__ ((nonnull (1, 2))) static inline int
ncplane_vline(struct ncplane* n, const nccell* c, int len){ ncplane_vline(struct ncplane* n, const nccell* c, unsigned len){
return ncplane_vline_interp(n, c, len, c->channels, c->channels); return ncplane_vline_interp(n, c, len, c->channels, c->channels);
} }

View File

@ -1242,8 +1242,11 @@ int ncdirect_set_bg_default(ncdirect* nc){
return 0; return 0;
} }
int ncdirect_hline_interp(ncdirect* n, const char* egc, int len, int ncdirect_hline_interp(ncdirect* n, const char* egc, unsigned len,
uint64_t c1, uint64_t c2){ uint64_t c1, uint64_t c2){
if(len == 0){
return -1;
}
unsigned ur, ug, ub; unsigned ur, ug, ub;
int r1, g1, b1, r2, g2, b2; int r1, g1, b1, r2, g2, b2;
int br1, bg1, bb1, br2, bg2, bb2; int br1, bg1, bb1, br2, bg2, bb2;
@ -1261,7 +1264,7 @@ int ncdirect_hline_interp(ncdirect* n, const char* egc, int len,
int deltbr = br2 - br1; int deltbr = br2 - br1;
int deltbg = bg2 - bg1; int deltbg = bg2 - bg1;
int deltbb = bb2 - bb1; int deltbb = bb2 - bb1;
int ret; unsigned ret;
bool fgdef = false, bgdef = false; bool fgdef = false, bgdef = false;
if(ncchannels_fg_default_p(c1) && ncchannels_fg_default_p(c2)){ if(ncchannels_fg_default_p(c1) && ncchannels_fg_default_p(c2)){
if(ncdirect_set_fg_default(n)){ if(ncdirect_set_fg_default(n)){
@ -1276,12 +1279,12 @@ int ncdirect_hline_interp(ncdirect* n, const char* egc, int len,
bgdef = true; bgdef = true;
} }
for(ret = 0 ; ret < len ; ++ret){ for(ret = 0 ; ret < len ; ++ret){
int r = (deltr * ret) / len + r1; int r = (deltr * (int)ret) / (int)len + r1;
int g = (deltg * ret) / len + g1; int g = (deltg * (int)ret) / (int)len + g1;
int b = (deltb * ret) / len + b1; int b = (deltb * (int)ret) / (int)len + b1;
int br = (deltbr * ret) / len + br1; int br = (deltbr * (int)ret) / (int)len + br1;
int bg = (deltbg * ret) / len + bg1; int bg = (deltbg * (int)ret) / (int)len + bg1;
int bb = (deltbb * ret) / len + bb1; int bb = (deltbb * (int)ret) / (int)len + bb1;
if(!fgdef){ if(!fgdef){
ncdirect_set_fg_rgb8(n, r, g, b); ncdirect_set_fg_rgb8(n, r, g, b);
} }
@ -1289,14 +1292,17 @@ int ncdirect_hline_interp(ncdirect* n, const char* egc, int len,
ncdirect_set_bg_rgb8(n, br, bg, bb); ncdirect_set_bg_rgb8(n, br, bg, bb);
} }
if(fprintf(n->ttyfp, "%s", egc) < 0){ if(fprintf(n->ttyfp, "%s", egc) < 0){
break; return -1;
} }
} }
return ret; return ret;
} }
int ncdirect_vline_interp(ncdirect* n, const char* egc, int len, int ncdirect_vline_interp(ncdirect* n, const char* egc, unsigned len,
uint64_t c1, uint64_t c2){ uint64_t c1, uint64_t c2){
if(len == 0){
return -1;
}
unsigned ur, ug, ub; unsigned ur, ug, ub;
int r1, g1, b1, r2, g2, b2; int r1, g1, b1, r2, g2, b2;
int br1, bg1, bb1, br2, bg2, bb2; int br1, bg1, bb1, br2, bg2, bb2;
@ -1308,13 +1314,13 @@ int ncdirect_vline_interp(ncdirect* n, const char* egc, int len,
br1 = ur; bg1 = ug; bb1 = ub; br1 = ur; bg1 = ug; bb1 = ub;
ncchannels_bg_rgb8(c2, &ur, &ug, &ub); ncchannels_bg_rgb8(c2, &ur, &ug, &ub);
br2 = ur; bg2 = ug; bb2 = ub; br2 = ur; bg2 = ug; bb2 = ub;
int deltr = (r2 - r1) / (len + 1); int deltr = (r2 - r1) / ((int)len + 1);
int deltg = (g2 - g1) / (len + 1); int deltg = (g2 - g1) / ((int)len + 1);
int deltb = (b2 - b1) / (len + 1); int deltb = (b2 - b1) / ((int)len + 1);
int deltbr = (br2 - br1) / (len + 1); int deltbr = (br2 - br1) / ((int)len + 1);
int deltbg = (bg2 - bg1) / (len + 1); int deltbg = (bg2 - bg1) / ((int)len + 1);
int deltbb = (bb2 - bb1) / (len + 1); int deltbb = (bb2 - bb1) / ((int)len + 1);
int ret; unsigned ret;
bool fgdef = false, bgdef = false; bool fgdef = false, bgdef = false;
if(ncchannels_fg_default_p(c1) && ncchannels_fg_default_p(c2)){ if(ncchannels_fg_default_p(c1) && ncchannels_fg_default_p(c2)){
if(ncdirect_set_fg_default(n)){ if(ncdirect_set_fg_default(n)){
@ -1343,11 +1349,11 @@ int ncdirect_vline_interp(ncdirect* n, const char* egc, int len,
ncchannels_set_bg_rgb8(&channels, br1, bg1, bb1); ncchannels_set_bg_rgb8(&channels, br1, bg1, bb1);
} }
if(ncdirect_putstr(n, channels, egc) <= 0){ if(ncdirect_putstr(n, channels, egc) <= 0){
break; return -1;
} }
if(len - ret > 1){ if(len - ret > 1){
if(ncdirect_cursor_down(n, 1) || ncdirect_cursor_left(n, 1)){ if(ncdirect_cursor_down(n, 1) || ncdirect_cursor_left(n, 1)){
break; return -1;
} }
} }
} }

View File

@ -1877,8 +1877,12 @@ int ncplane_vprintf_stained(struct ncplane* n, const char* format, va_list ap){
return ret; return ret;
} }
int ncplane_hline_interp(ncplane* n, const nccell* c, int len, int ncplane_hline_interp(ncplane* n, const nccell* c, unsigned len,
uint64_t c1, uint64_t c2){ uint64_t c1, uint64_t c2){
if(len <= 0){
logerror("passed invalid length %u\n", len);
return -1;
}
unsigned ur, ug, ub; unsigned ur, ug, ub;
int r1, g1, b1, r2, g2, b2; int r1, g1, b1, r2, g2, b2;
int br1, bg1, bb1, br2, bg2, bb2; int br1, bg1, bb1, br2, bg2, bb2;
@ -1896,7 +1900,7 @@ int ncplane_hline_interp(ncplane* n, const nccell* c, int len,
int deltbr = br2 - br1; int deltbr = br2 - br1;
int deltbg = bg2 - bg1; int deltbg = bg2 - bg1;
int deltbb = bb2 - bb1; int deltbb = bb2 - bb1;
int ret; unsigned ret;
nccell dupc = CELL_TRIVIAL_INITIALIZER; nccell dupc = CELL_TRIVIAL_INITIALIZER;
if(nccell_duplicate(n, &dupc, c) < 0){ if(nccell_duplicate(n, &dupc, c) < 0){
return -1; return -1;
@ -1909,12 +1913,12 @@ int ncplane_hline_interp(ncplane* n, const nccell* c, int len,
bgdef = true; bgdef = true;
} }
for(ret = 0 ; ret < len ; ++ret){ for(ret = 0 ; ret < len ; ++ret){
int r = (deltr * ret) / len + r1; int r = (deltr * (int)ret) / (int)len + r1;
int g = (deltg * ret) / len + g1; int g = (deltg * (int)ret) / (int)len + g1;
int b = (deltb * ret) / len + b1; int b = (deltb * (int)ret) / (int)len + b1;
int br = (deltbr * ret) / len + br1; int br = (deltbr * (int)ret) / (int)len + br1;
int bg = (deltbg * ret) / len + bg1; int bg = (deltbg * (int)ret) / (int)len + bg1;
int bb = (deltbb * ret) / len + bb1; int bb = (deltbb * (int)ret) / (int)len + bb1;
if(!fgdef){ if(!fgdef){
nccell_set_fg_rgb8(&dupc, r, g, b); nccell_set_fg_rgb8(&dupc, r, g, b);
} }
@ -1922,15 +1926,19 @@ int ncplane_hline_interp(ncplane* n, const nccell* c, int len,
nccell_set_bg_rgb8(&dupc, br, bg, bb); nccell_set_bg_rgb8(&dupc, br, bg, bb);
} }
if(ncplane_putc(n, &dupc) <= 0){ if(ncplane_putc(n, &dupc) <= 0){
break; return -1;
} }
} }
nccell_release(n, &dupc); nccell_release(n, &dupc);
return ret; return ret;
} }
int ncplane_vline_interp(ncplane* n, const nccell* c, int len, int ncplane_vline_interp(ncplane* n, const nccell* c, unsigned len,
uint64_t c1, uint64_t c2){ uint64_t c1, uint64_t c2){
if(len <= 0){
logerror("passed invalid length %u\n", len);
return -1;
}
unsigned ur, ug, ub; unsigned ur, ug, ub;
int r1, g1, b1, r2, g2, b2; int r1, g1, b1, r2, g2, b2;
int br1, bg1, bb1, br2, bg2, bb2; int br1, bg1, bb1, br2, bg2, bb2;
@ -1942,13 +1950,14 @@ int ncplane_vline_interp(ncplane* n, const nccell* c, int len,
br1 = ur; bg1 = ug; bb1 = ub; br1 = ur; bg1 = ug; bb1 = ub;
ncchannels_bg_rgb8(c2, &ur, &ug, &ub); ncchannels_bg_rgb8(c2, &ur, &ug, &ub);
br2 = ur; bg2 = ug; bb2 = ub; br2 = ur; bg2 = ug; bb2 = ub;
int deltr = (r2 - r1) / (len + 1); int deltr = (r2 - r1) / ((int)len + 1);
int deltg = (g2 - g1) / (len + 1); int deltg = (g2 - g1) / ((int)len + 1);
int deltb = (b2 - b1) / (len + 1); int deltb = (b2 - b1) / ((int)len + 1);
int deltbr = (br2 - br1) / (len + 1); int deltbr = (br2 - br1) / ((int)len + 1);
int deltbg = (bg2 - bg1) / (len + 1); int deltbg = (bg2 - bg1) / ((int)len + 1);
int deltbb = (bb2 - bb1) / (len + 1); int deltbb = (bb2 - bb1) / ((int)len + 1);
int ret, ypos, xpos; int ypos, xpos;
unsigned ret;
ncplane_cursor_yx(n, &ypos, &xpos); ncplane_cursor_yx(n, &ypos, &xpos);
nccell dupc = CELL_TRIVIAL_INITIALIZER; nccell dupc = CELL_TRIVIAL_INITIALIZER;
if(nccell_duplicate(n, &dupc, c) < 0){ if(nccell_duplicate(n, &dupc, c) < 0){
@ -1978,7 +1987,7 @@ int ncplane_vline_interp(ncplane* n, const nccell* c, int len,
nccell_set_bg_rgb8(&dupc, br1, bg1, bb1); nccell_set_bg_rgb8(&dupc, br1, bg1, bb1);
} }
if(ncplane_putc(n, &dupc) <= 0){ if(ncplane_putc(n, &dupc) <= 0){
break; return -1;
} }
} }
nccell_release(n, &dupc); nccell_release(n, &dupc);