mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19: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
|
been purged, as have `min_` and `max_supported_rows` and `_cols`. There
|
||||||
is no longer any need to provide a pipe/eventfd. `ncreel_touch()`,
|
is no longer any need to provide a pipe/eventfd. `ncreel_touch()`,
|
||||||
`ncreel_del_focused()`, and `ncreel_move()` have been removed.
|
`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)
|
* 1.6.0 (2020-07-04)
|
||||||
* Behavior has changed regarding use of the provided `FILE*` (which, when
|
* 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,
|
int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len,
|
||||||
uint64_t h1, uint64_t h2);
|
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
|
// Display an image using the specified blitter and scaling. The image may
|
||||||
// be arbitrarily many rows -- the output will scroll -- but will only occupy
|
// be arbitrarily many rows -- the output will scroll -- but will only occupy
|
||||||
// the column of the cursor, and those to the right.
|
// 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);**
|
**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);**
|
**nc_err_e ncdirect_render_image(struct ncdirect* n, const char* filename, ncblitter_e blitter, ncscale_e scale);**
|
||||||
|
|
||||||
# DESCRIPTION
|
# 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,
|
API int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len,
|
||||||
uint64_t h1, uint64_t h2);
|
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.
|
// Release 'nc' and any associated resources. 0 on success, non-0 on failure.
|
||||||
API int ncdirect_stop(struct ncdirect* nc);
|
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_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_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_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_canopen_images(const struct ncdirect* n);
|
||||||
bool ncdirect_canutf8(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);
|
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 "notcurses/direct.h"
|
||||||
#include "internal.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(channels_fg_default_p(channels)){
|
||||||
if(ncdirect_fg_default(nc)){
|
if(ncdirect_fg_default(nc)){
|
||||||
return -1;
|
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))){
|
}else if(ncdirect_bg(nc, channels_bg(channels))){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return fprintf(nc->ttyfp, "%s", egc);
|
return fprintf(nc->ttyfp, "%s", utf8);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ncdirect_cursor_up(ncdirect* nc, int num){
|
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;
|
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.
|
// Can we load images? This requires being built against FFmpeg/OIIO.
|
||||||
bool ncdirect_canopen_images(const ncdirect* n){
|
bool ncdirect_canopen_images(const ncdirect* n){
|
||||||
(void)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,
|
int term_setstyle(FILE* out, unsigned cur, unsigned targ, unsigned stylebit,
|
||||||
const char* ton, const char* toff);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1668,12 +1668,6 @@ int ncplane_vline_interp(ncplane* n, const cell* c, int len,
|
|||||||
return ret;
|
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,
|
int ncplane_box(ncplane* n, const cell* ul, const cell* ur,
|
||||||
const cell* ll, const cell* lr, const cell* hl,
|
const cell* ll, const cell* lr, const cell* hl,
|
||||||
const cell* vl, int ystop, int xstop,
|
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)){
|
if(ncdirect_stop(n)){
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user