mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 09:09:03 -04:00
add ncdirect box-drawing functions #753
This commit is contained in:
parent
96c6dc8e16
commit
a6b002fa77
4
NEWS.md
4
NEWS.md
@ -11,7 +11,9 @@ rearrangements of Notcurses.
|
||||
been purged, as have `min_` and `max_supported_rows` and `_cols`. There
|
||||
is no longer any need to provide a pipe/eventfd. `ncreel_touch()`,
|
||||
`ncreel_del_focused()`, and `ncreel_move()` have been removed.
|
||||
* Added `ncdirect_hline_interp()` and `ncdirect_vline_interp()`.
|
||||
* Added `ncdirect_hline_interp()`, `ncdirect_vline_interp()`,
|
||||
`ncdirect_rounded_box()`, `ncdirect_double_box()`, and the ridiculously
|
||||
flexible `ncdirect_box()`.
|
||||
|
||||
* 1.6.0 (2020-07-04)
|
||||
* Behavior has changed regarding use of the provided `FILE*` (which, when
|
||||
|
18
USAGE.md
18
USAGE.md
@ -357,6 +357,24 @@ int ncdirect_hline_interp(struct ncdirect* n, const char* egc, int len,
|
||||
int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len,
|
||||
uint64_t h1, uint64_t h2);
|
||||
|
||||
// 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
|
||||
// minimum box size is 2x2, and it cannot be drawn off-screen. |wchars| is an
|
||||
// array of 6 wide characters: UL, UR, LL, LR, HL, VL.
|
||||
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);
|
||||
|
||||
// ncdirect_box() with the rounded box-drawing characters
|
||||
int ncdirect_rounded_box(struct ncdirect* n, uint64_t ul, uint64_t ur,
|
||||
uint64_t ll, uint64_t lr,
|
||||
int ylen, int xlen, unsigned ctlword);
|
||||
|
||||
// ncdirect_box() with the double box-drawing characters
|
||||
int ncdirect_double_box(struct ncdirect* n, uint64_t ul, uint64_t ur,
|
||||
uint64_t ll, uint64_t lr,
|
||||
int ylen, int xlen, unsigned ctlword);
|
||||
|
||||
// Display an image using the specified blitter and scaling. The image may
|
||||
// be arbitrarily many rows -- the output will scroll -- but will only occupy
|
||||
// the column of the cursor, and those to the right.
|
||||
|
@ -60,6 +60,16 @@ ncdirect_init - minimal notcurses instances for styling text
|
||||
|
||||
**bool ncdirect_canutf8(const struct ncdirect* n);**
|
||||
|
||||
**int ncdirect_hline_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, int 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_rounded_box(struct ncdirect* n, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ylen, int xlen, unsigned ctlword);**
|
||||
|
||||
**int ncdirect_double_box(struct ncdirect* n, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ylen, int xlen, unsigned ctlword);**
|
||||
|
||||
**nc_err_e ncdirect_render_image(struct ncdirect* n, const char* filename, ncblitter_e blitter, ncscale_e scale);**
|
||||
|
||||
# DESCRIPTION
|
||||
|
@ -112,6 +112,24 @@ API int ncdirect_hline_interp(struct ncdirect* n, const char* egc, int len,
|
||||
API int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len,
|
||||
uint64_t h1, uint64_t h2);
|
||||
|
||||
// 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
|
||||
// minimum box size is 2x2, and it cannot be drawn off-screen. |wchars| is an
|
||||
// array of 6 wide characters: UL, UR, LL, LR, HL, VL.
|
||||
API 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);
|
||||
|
||||
// ncdirect_box() with the rounded box-drawing characters
|
||||
API int ncdirect_rounded_box(struct ncdirect* n, uint64_t ul, uint64_t ur,
|
||||
uint64_t ll, uint64_t lr,
|
||||
int ylen, int xlen, unsigned ctlword);
|
||||
|
||||
// ncdirect_box() with the double box-drawing characters
|
||||
API int ncdirect_double_box(struct ncdirect* n, uint64_t ul, uint64_t ur,
|
||||
uint64_t ll, uint64_t lr,
|
||||
int ylen, int xlen, unsigned ctlword);
|
||||
|
||||
// Release 'nc' and any associated resources. 0 on success, non-0 on failure.
|
||||
API int ncdirect_stop(struct ncdirect* nc);
|
||||
|
||||
|
@ -503,6 +503,9 @@ int ncdirect_cursor_right(struct ncdirect* nc, int num);
|
||||
int ncdirect_cursor_down(struct ncdirect* nc, int num);
|
||||
int ncdirect_hline_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, int 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_rounded_box(struct ncdirect* n, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ylen, int xlen, unsigned ctlword);
|
||||
int ncdirect_double_box(struct ncdirect* n, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, int ylen, int xlen, unsigned ctlword);
|
||||
bool ncdirect_canopen_images(const struct ncdirect* n);
|
||||
bool ncdirect_canutf8(const struct ncdirect* n);
|
||||
nc_err_e ncdirect_render_image(struct ncdirect* n, const char* filename, ncalign_e align, ncblitter_e blitter, ncscale_e scale);
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "notcurses/direct.h"
|
||||
#include "internal.h"
|
||||
|
||||
int ncdirect_putstr(ncdirect* nc, uint64_t channels, const char* egc){
|
||||
int ncdirect_putstr(ncdirect* nc, uint64_t channels, const char* utf8){
|
||||
if(channels_fg_default_p(channels)){
|
||||
if(ncdirect_fg_default(nc)){
|
||||
return -1;
|
||||
@ -24,7 +24,7 @@ int ncdirect_putstr(ncdirect* nc, uint64_t channels, const char* egc){
|
||||
}else if(ncdirect_bg(nc, channels_bg(channels))){
|
||||
return -1;
|
||||
}
|
||||
return fprintf(nc->ttyfp, "%s", egc);
|
||||
return fprintf(nc->ttyfp, "%s", utf8);
|
||||
}
|
||||
|
||||
int ncdirect_cursor_up(ncdirect* nc, int num){
|
||||
@ -652,6 +652,123 @@ int ncdirect_vline_interp(ncdirect* n, const char* egc, int len,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// wchars: wchar_t[6] mapping to UL, UR, BL, BR, HL, VL.
|
||||
// they cannot be complex EGCs, but only a single wchar_t, alas.
|
||||
int ncdirect_box(ncdirect* n, uint64_t ul, uint64_t ur,
|
||||
uint64_t ll, uint64_t lr, const wchar_t* wchars,
|
||||
int ylen, int xlen, unsigned ctlword){
|
||||
if(xlen < 2 || ylen < 2){
|
||||
return -1;
|
||||
}
|
||||
char hl[WCHAR_MAX_UTF8BYTES + 1];
|
||||
char vl[WCHAR_MAX_UTF8BYTES + 1];
|
||||
unsigned edges;
|
||||
edges = !(ctlword & NCBOXMASK_TOP) + !(ctlword & NCBOXMASK_LEFT);
|
||||
if(edges >= box_corner_needs(ctlword)){
|
||||
ncdirect_fg(n, channels_fg(ul));
|
||||
ncdirect_bg(n, channels_bg(ul));
|
||||
if(fprintf(n->ttyfp, "%lc", wchars[0]) < 0){
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
ncdirect_cursor_right(n, 1);
|
||||
}
|
||||
mbstate_t ps = {};
|
||||
size_t bytes;
|
||||
if((bytes = wcrtomb(hl, wchars[4], &ps)) == (size_t)-1){
|
||||
return -1;
|
||||
}
|
||||
hl[bytes] = '\0';
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
if((bytes = wcrtomb(vl, wchars[5], &ps)) == (size_t)-1){
|
||||
return -1;
|
||||
}
|
||||
vl[bytes] = '\0';
|
||||
if(!(ctlword & NCBOXMASK_TOP)){ // draw top border, if called for
|
||||
if(xlen > 2){
|
||||
if(ncdirect_hline_interp(n, hl, xlen - 2, ul, ur) < 0){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
ncdirect_cursor_right(n, xlen - 2);
|
||||
}
|
||||
edges = !(ctlword & NCBOXMASK_TOP) + !(ctlword & NCBOXMASK_RIGHT);
|
||||
if(edges >= box_corner_needs(ctlword)){
|
||||
ncdirect_fg(n, channels_fg(ur));
|
||||
ncdirect_bg(n, channels_bg(ur));
|
||||
if(fprintf(n->ttyfp, "%lc", wchars[1]) < 0){
|
||||
return -1;
|
||||
}
|
||||
ncdirect_cursor_left(n, xlen);
|
||||
}else{
|
||||
ncdirect_cursor_left(n, xlen - 1);
|
||||
}
|
||||
ncdirect_cursor_down(n, 1);
|
||||
// middle rows (vertical lines)
|
||||
if(ylen > 2){
|
||||
if(!(ctlword & NCBOXMASK_LEFT)){
|
||||
if(ncdirect_vline_interp(n, vl, ylen - 2, ul, ll) < 0){
|
||||
return -1;
|
||||
}
|
||||
ncdirect_cursor_right(n, xlen - 2);
|
||||
ncdirect_cursor_up(n, ylen - 3);
|
||||
}else{
|
||||
ncdirect_cursor_right(n, xlen - 1);
|
||||
}
|
||||
if(!(ctlword & NCBOXMASK_RIGHT)){
|
||||
if(ncdirect_vline_interp(n, vl, ylen - 2, ur, lr) < 0){
|
||||
return -1;
|
||||
}
|
||||
ncdirect_cursor_left(n, xlen);
|
||||
}else{
|
||||
ncdirect_cursor_left(n, xlen - 1);
|
||||
}
|
||||
}
|
||||
ncdirect_cursor_down(n, 1);
|
||||
// bottom line
|
||||
edges = !(ctlword & NCBOXMASK_BOTTOM) + !(ctlword & NCBOXMASK_LEFT);
|
||||
if(edges >= box_corner_needs(ctlword)){
|
||||
ncdirect_fg(n, channels_fg(ll));
|
||||
ncdirect_bg(n, channels_bg(ll));
|
||||
if(fprintf(n->ttyfp, "%lc", wchars[2]) < 0){
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
ncdirect_cursor_right(n, 1);
|
||||
}
|
||||
if(!(ctlword & NCBOXMASK_BOTTOM)){
|
||||
if(xlen > 2){
|
||||
if(ncdirect_hline_interp(n, hl, xlen - 2, ll, lr) < 0){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
ncdirect_cursor_right(n, xlen - 2);
|
||||
}
|
||||
edges = !(ctlword & NCBOXMASK_BOTTOM) + !(ctlword & NCBOXMASK_RIGHT);
|
||||
if(edges >= box_corner_needs(ctlword)){
|
||||
ncdirect_fg(n, channels_fg(lr));
|
||||
ncdirect_bg(n, channels_bg(lr));
|
||||
if(fprintf(n->ttyfp, "%lc", wchars[3]) < 0){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncdirect_rounded_box(ncdirect* n, uint64_t ul, uint64_t ur,
|
||||
uint64_t ll, uint64_t lr,
|
||||
int ylen, int xlen, unsigned ctlword){
|
||||
return ncdirect_box(n, ul, ur, ll, lr, L"╭╮╰╯─│", ylen, xlen, ctlword);
|
||||
}
|
||||
|
||||
int ncdirect_double_box(ncdirect* n, uint64_t ul, uint64_t ur,
|
||||
uint64_t ll, uint64_t lr,
|
||||
int ylen, int xlen, unsigned ctlword){
|
||||
return ncdirect_box(n, ul, ur, ll, lr, L"╔╗╚╝═║", ylen, xlen, ctlword);
|
||||
}
|
||||
|
||||
// Can we load images? This requires being built against FFmpeg/OIIO.
|
||||
bool ncdirect_canopen_images(const ncdirect* n){
|
||||
(void)n;
|
||||
|
@ -826,6 +826,12 @@ int ffmpeg_log_level(ncloglevel_e level);
|
||||
int term_setstyle(FILE* out, unsigned cur, unsigned targ, unsigned stylebit,
|
||||
const char* ton, const char* toff);
|
||||
|
||||
// how many edges need touch a corner for it to be printed?
|
||||
static inline unsigned
|
||||
box_corner_needs(unsigned ctlword){
|
||||
return (ctlword & NCBOXCORNER_MASK) >> NCBOXCORNER_SHIFT;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1668,12 +1668,6 @@ int ncplane_vline_interp(ncplane* n, const cell* c, int len,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// how many edges need touch a corner for it to be printed?
|
||||
static inline unsigned
|
||||
box_corner_needs(unsigned ctlword){
|
||||
return (ctlword & NCBOXCORNER_MASK) >> NCBOXCORNER_SHIFT;
|
||||
}
|
||||
|
||||
int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
|
||||
const cell* ll, const cell* lr, const cell* hl,
|
||||
const cell* vl, int ystop, int xstop,
|
||||
|
@ -34,6 +34,20 @@ int main(void){
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
uint64_t ul, ur, ll, lr;
|
||||
ul = ur = ll = lr = 0;
|
||||
channels_set_fg_rgb(&ul, 0xff, 0x0, 0xff);
|
||||
channels_set_fg_rgb(&ur, 0x0, 0xff, 0x0);
|
||||
channels_set_fg_rgb(&ll, 0x0, 0x0, 0xff);
|
||||
channels_set_fg_rgb(&lr, 0xff, 0x0, 0x0);
|
||||
if(ncdirect_rounded_box(n, ul, ur, ll, lr, 10, 10, 0) < 0){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ncdirect_cursor_up(n, 9);
|
||||
if(ncdirect_double_box(n, ul, ur, ll, lr, 10, 20, 0) < 0){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(ncdirect_stop(n)){
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user