ncdirect_hline_interp(), ncdirect_vline_interp(), dirlines PoC #753

pull/791/head
nick black 4 years ago committed by Nick Black
parent 750f88b70a
commit c783244185

@ -11,6 +11,7 @@ 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()`.
* 1.6.0 (2020-07-04)
* Behavior has changed regarding use of the provided `FILE*` (which, when

@ -47,6 +47,10 @@ supplied a struct of type `notcurses_options`:
// Get a human-readable string describing the running Notcurses version.
const char* notcurses_version(void);
// Cannot be inline, as we want to get the versions of the actual notcurses
// library we loaded, not what we compile against.
void notcurses_version_components(int* major, int* minor, int* patch, int* tweak);
struct cell; // a coordinate on an ncplane: an EGC plus styling
struct ncplane; // a drawable Notcurses surface, composed of cells
struct notcurses; // Notcurses state for a given terminal, composed of ncplanes
@ -263,10 +267,10 @@ bool notcurses_cansixel(const struct notcurses* nc);
## Direct mode
"Direct mode" makes a limited subset of notcurses is available for manipulating
typical scrolling or file-backed output. These functions output directly and
immediately to the provided `FILE*`, and `notcurses_render()` is neither
supported nor necessary for such an instance. Use `ncdirect_init()` to create a
direct mode context:
typical scrolling or file-backed output. Its functions are exported via
`<notcurses/direct.h>`, and output directly and immediately to the provided
`FILE*`. `notcurses_render()` is neither supported nor necessary for such an
instance. Use `ncdirect_init()` to create a direct mode context:
```c
struct ncdirect; // minimal state for a terminal
@ -328,6 +332,31 @@ int ncdirect_cursor_left(struct ncdirect* nc, int num);
int ncdirect_cursor_right(struct ncdirect* nc, int num);
int ncdirect_cursor_down(struct ncdirect* nc, int num);
// Get the cursor position, when supported. This requires writing to the
// terminal, and then reading from it. If the terminal doesn't reply, or
// doesn't reply in a way we understand, the results might be deleterious.
int ncdirect_cursor_yx(struct ncdirect* n, int* y, int* x);
// Push or pop the cursor location to the terminal's stack. The depth of this
// stack, and indeed its existence, is terminal-dependent.
int ncdirect_cursor_push(struct ncdirect* n);
int ncdirect_cursor_pop(struct ncdirect* n);
// Formatted printing (plus alignment relative to the terminal).
int ncdirect_printf_aligned(struct ncdirect* n, int y, ncalign_e align,
const char* fmt, ...)
__attribute__ ((format (printf, 4, 5)));
// Draw horizontal/vertical lines using the specified channels, interpolating
// between them as we go. The EGC may not use more than one column. For a
// 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
// will scroll as necessary. All lines start at the current cursor position.
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);
// 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.

@ -54,7 +54,7 @@ ncdirect_init - minimal notcurses instances for styling text
**int ncdirect_cursor_down(struct ncdirect* nc, int num);**
**int ncdirect_putc(struct ncdirect* nc, uint64_t channels, const char* egc);**
**int ncdirect_putstr(struct ncdirect* nc, uint64_t channels, const char* utf8);**
**nc_err_e ncdirect_render_image(struct ncdirect* n, const char* filename, ncblitter_e blitter, ncscale_e scale);**

@ -31,8 +31,8 @@ API int ncdirect_bg_palindex(struct ncdirect* nc, int pidx);
// more colors than they actually support, downsampling internally.
API int ncdirect_palette_size(const struct ncdirect* nc);
// Output the EGC |egc| according to the channels |channels|.
API int ncdirect_putc(struct ncdirect* nc, uint64_t channels, const char* egc);
// Output the string |utf8| according to the channels |channels|.
API int ncdirect_putstr(struct ncdirect* nc, uint64_t channels, const char* utf8);
static inline int
ncdirect_bg_rgb(struct ncdirect* nc, unsigned r, unsigned g, unsigned b){
@ -87,8 +87,8 @@ API int ncdirect_printf_aligned(struct ncdirect* n, int y, ncalign_e align,
__attribute__ ((format (printf, 4, 5)));
// 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.
// be arbitrarily many rows -- the output will scroll -- but will only occupy
// the column of the cursor, and those to the right.
API nc_err_e ncdirect_render_image(struct ncdirect* n, const char* filename,
ncalign_e align, ncblitter_e blitter,
ncscale_e scale);
@ -99,6 +99,16 @@ API int ncdirect_clear(struct ncdirect* nc);
// Release 'nc' and any associated resources. 0 on success, non-0 on failure.
API int ncdirect_stop(struct ncdirect* nc);
// Draw horizontal/vertical lines using the specified channels, interpolating
// between them as we go. The EGC may not use more than one column. For a
// 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
// 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,
uint64_t h1, uint64_t h2);
API int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len,
uint64_t h1, uint64_t h2);
#undef API
#ifdef __cplusplus

@ -484,7 +484,7 @@ struct ncdirect* ncdirect_init(const char* termtype, FILE* fp);
int ncdirect_bg_rgb(struct ncdirect* n, unsigned r, unsigned g, unsigned b);
int ncdirect_fg_rgb(struct ncdirect* n, unsigned r, unsigned g, unsigned b);
int ncdirect_palette_size(const struct ncdirect* nc);
int ncdirect_putc(struct ncdirect* nc, uint64_t channels, const char* egc);
int ncdirect_putstr(struct ncdirect* nc, uint64_t channels, const char* utf8);
int ncdirect_fg(struct ncdirect* n, unsigned rgb);
int ncdirect_bg(struct ncdirect* n, unsigned rgb);
int ncdirect_styles_set(struct ncdirect* n, unsigned stylebits);
@ -501,6 +501,8 @@ int ncdirect_cursor_up(struct ncdirect* nc, int num);
int ncdirect_cursor_left(struct ncdirect* nc, int num);
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);
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_putc(ncdirect* nc, uint64_t channels, const char* egc){
int ncdirect_putstr(ncdirect* nc, uint64_t channels, const char* egc){
if(channels_fg_default_p(channels)){
if(ncdirect_fg_default(nc)){
return -1;
@ -474,7 +474,7 @@ int ncdirect_stop(ncdirect* nc){
static inline int
ncdirect_style_emit(ncdirect* n, const char* sgr, unsigned stylebits, FILE* out){
if(sgr == NULL){
if(sgr == nullptr){
return -1;
}
int r = term_emit("sgr", tiparm(sgr, stylebits & NCSTYLE_STANDOUT,
@ -536,7 +536,7 @@ int ncdirect_fg_default(ncdirect* nc){
if(nc->bgdefault){
return 0;
}
return ncdirect_bg(nc, nc->fgrgb);
return ncdirect_bg(nc, nc->bgrgb);
}
return -1;
}
@ -547,7 +547,107 @@ int ncdirect_bg_default(ncdirect* nc){
if(nc->fgdefault){
return 0;
}
return ncdirect_fg(nc, nc->bgrgb);
return ncdirect_fg(nc, nc->fgrgb);
}
return -1;
}
int ncdirect_hline_interp(ncdirect* n, const char* egc, int len,
uint64_t c1, uint64_t c2){
unsigned ur, ug, ub;
int r1, g1, b1, r2, g2, b2;
int br1, bg1, bb1, br2, bg2, bb2;
channels_fg_rgb(c1, &ur, &ug, &ub);
r1 = ur; g1 = ug; b1 = ub;
channels_fg_rgb(c2, &ur, &ug, &ub);
r2 = ur; g2 = ug; b2 = ub;
channels_bg_rgb(c1, &ur, &ug, &ub);
br1 = ur; bg1 = ug; bb1 = ub;
channels_bg_rgb(c2, &ur, &ug, &ub);
br2 = ur; bg2 = ug; bb2 = ub;
int deltr = r2 - r1;
int deltg = g2 - g1;
int deltb = b2 - b1;
int deltbr = br2 - br1;
int deltbg = bg2 - bg1;
int deltbb = bb2 - bb1;
int ret;
bool fgdef = false, bgdef = false;
if(channels_fg_default_p(c1) && channels_fg_default_p(c2)){
fgdef = true;
}
if(channels_bg_default_p(c1) && channels_bg_default_p(c2)){
bgdef = true;
}
for(ret = 0 ; ret < len ; ++ret){
int r = (deltr * ret) / len + r1;
int g = (deltg * ret) / len + g1;
int b = (deltb * ret) / len + b1;
int br = (deltbr * ret) / len + br1;
int bg = (deltbg * ret) / len + bg1;
int bb = (deltbb * ret) / len + bb1;
if(!fgdef){
ncdirect_fg_rgb(n, r, g, b);
}
if(!bgdef){
ncdirect_bg_rgb(n, br, bg, bb);
}
if(fprintf(n->ttyfp, "%s", egc) < 0){
break;
}
}
return ret;
}
int ncdirect_vline_interp(ncdirect* n, const char* egc, int len,
uint64_t c1, uint64_t c2){
unsigned ur, ug, ub;
int r1, g1, b1, r2, g2, b2;
int br1, bg1, bb1, br2, bg2, bb2;
channels_fg_rgb(c1, &ur, &ug, &ub);
r1 = ur; g1 = ug; b1 = ub;
channels_fg_rgb(c2, &ur, &ug, &ub);
r2 = ur; g2 = ug; b2 = ub;
channels_bg_rgb(c1, &ur, &ug, &ub);
br1 = ur; bg1 = ug; bb1 = ub;
channels_bg_rgb(c2, &ur, &ug, &ub);
br2 = ur; bg2 = ug; bb2 = ub;
int deltr = (r2 - r1) / (len + 1);
int deltg = (g2 - g1) / (len + 1);
int deltb = (b2 - b1) / (len + 1);
int deltbr = (br2 - br1) / (len + 1);
int deltbg = (bg2 - bg1) / (len + 1);
int deltbb = (bb2 - bb1) / (len + 1);
int ret;
bool fgdef = false, bgdef = false;
if(channels_fg_default_p(c1) && channels_fg_default_p(c2)){
fgdef = true;
}
if(channels_bg_default_p(c1) && channels_bg_default_p(c2)){
bgdef = true;
}
for(ret = 0 ; ret < len ; ++ret){
r1 += deltr;
g1 += deltg;
b1 += deltb;
br1 += deltbr;
bg1 += deltbg;
bb1 += deltbb;
uint64_t channels = 0;
if(!fgdef){
channels_set_fg_rgb(&channels, r1, g1, b1);
}
if(!bgdef){
channels_set_bg_rgb(&channels, br1, bg1, bb1);
}
if(ncdirect_putstr(n, channels, egc) <= 0){
break;
}
if(len - ret > 1){
if(ncdirect_cursor_down(n, 1) || ncdirect_cursor_left(n, 1)){
break;
}
}
}
return ret;
}

@ -0,0 +1,41 @@
#include <stdlib.h>
#include <locale.h>
#include <notcurses/direct.h>
int main(void){
if(!setlocale(LC_ALL, "")){
return EXIT_FAILURE;
}
struct ncdirect* n = ncdirect_init(NULL, stdout);
putchar('\n');
for(int i = 0 ; i < 15 ; ++i){
uint64_t c1 = 0, c2 = 0;
channels_set_fg_rgb(&c1, 0x0, 0x10 * i, 0xff);
channels_set_fg_rgb(&c2, 0x10 * i, 0x0, 0x0);
if(ncdirect_hline_interp(n, "-", i, c1, c2) < i){
return EXIT_FAILURE;
}
ncdirect_fg_default(n);
ncdirect_bg_default(n);
putchar('\n');
}
for(int i = 0 ; i < 15 ; ++i){
uint64_t c1 = 0, c2 = 0;
channels_set_fg_rgb(&c1, 0x0, 0x10 * i, 0xff);
channels_set_fg_rgb(&c2, 0x10 * i, 0x0, 0x0);
if(ncdirect_vline_interp(n, "|", i, c1, c2) < i){
return EXIT_FAILURE;
}
ncdirect_fg_default(n);
ncdirect_bg_default(n);
if(i < 14){
if(ncdirect_cursor_up(n, i)){
return EXIT_FAILURE;
}
}
}
if(ncdirect_stop(n)){
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

@ -1,6 +1,6 @@
#include <locale.h>
#include <unistd.h>
#include <notcurses/notcurses.h>
#include <notcurses/direct.h>
// can we leave what was already on the screen there? (narrator: it seems not)
int main(void){

Loading…
Cancel
Save