mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
ncdirect_hline_interp(), ncdirect_vline_interp(), dirlines PoC #753
This commit is contained in:
parent
750f88b70a
commit
c783244185
1
NEWS.md
1
NEWS.md
@ -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
|
||||
|
37
USAGE.md
37
USAGE.md
@ -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;
|
||||
}
|
||||
|
41
src/poc/dirlines.c
Normal file
41
src/poc/dirlines.c
Normal file
@ -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…
x
Reference in New Issue
Block a user