mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 09:09:03 -04:00
Zoo 2, electric boogaloo (#939)
* Reimplement the widget zoo demo. The previous PoC was a multithreaded monster with behavior dependent on screen geometry. Replace it with a single thread state machine. Closes #936. * Support titles for ncplot. Adds title to the ncplot_options struct, which may be NULL. Closes #941 . * Properly color ncplot according to maxchannels and minchannels. Closes #940 * Add tools/function-table.sh script for generating public API list.
This commit is contained in:
parent
1e6558fed9
commit
73dc0a7d69
5
NEWS.md
5
NEWS.md
@ -3,6 +3,11 @@ rearrangements of Notcurses.
|
||||
|
||||
* 1.6.17 (not yet released)
|
||||
* `ncdirect_flush()` now takes a `const struct ncdirect*`.
|
||||
* A `const char* title` field has been added to `ncplot_options`. If not
|
||||
`NULL`, this title will be displayed to the right of any labels. Plot
|
||||
data will cover the title, if present.
|
||||
* `ncplot` no longer inverts `maxchannel` and `minchannel`. Speaking
|
||||
of which, both of these fields are now plural, `maxchannels` etc.
|
||||
|
||||
* 1.6.16 (2020-08-22)
|
||||
* `cell_simple_p()` has been removed. It is no longer a useful concept for
|
||||
|
@ -20,8 +20,8 @@ notcurses_plot - high level widget for plotting
|
||||
typedef struct ncplot_options {
|
||||
// channels for the maximum and minimum levels.
|
||||
// lerp across the domain between these two.
|
||||
uint64_t maxchannel;
|
||||
uint64_t minchannel;
|
||||
uint64_t maxchannels;
|
||||
uint64_t minchannels;
|
||||
// styling used for labels (NCPLOT_OPTION_LABELTICKSD)
|
||||
uint16_t legendstyle;
|
||||
// number of "pixels" per row x column
|
||||
@ -31,6 +31,7 @@ typedef struct ncplot_options {
|
||||
bool labelaxisd; // label dependent axis
|
||||
bool exponentially; // is dependent exponential?
|
||||
bool vertical_indep; // vertical independent variable
|
||||
const char* title; // optional title
|
||||
} ncplot_options;
|
||||
```
|
||||
|
||||
|
@ -2206,20 +2206,20 @@ API struct ncvisual* ncvisual_from_plane(const struct ncplane* n,
|
||||
struct ncvisual_options {
|
||||
// if no ncplane is provided, one will be created using the exact size
|
||||
// necessary to render the source with perfect fidelity (this might be
|
||||
// smaller or larger than the rendering area). if provided, style is
|
||||
// taken into account, relative to the provided ncplane.
|
||||
// smaller or larger than the rendering area).
|
||||
struct ncplane* n;
|
||||
// the style is ignored if no ncplane is provided (it ought be NCSCALE_NONE
|
||||
// the scaling is ignored if no ncplane is provided (it ought be NCSCALE_NONE
|
||||
// in this case). otherwise, the source is stretched/scaled relative to the
|
||||
// provided ncplane.
|
||||
ncscale_e scaling;
|
||||
// if an ncplane is provided, y and x specify where the visual will be
|
||||
// rendered on that plane. otherwise, they specify where the created ncplane
|
||||
// will be placed.
|
||||
// will be placed relative to the standard plane's origin.
|
||||
int y, x;
|
||||
// the section of the visual that ought be rendered. for the entire visual,
|
||||
// pass an origin of 0, 0 and a size of 0, 0 (or the true height and width).
|
||||
// these numbers are all in terms of ncvisual pixels.
|
||||
// these numbers are all in terms of ncvisual pixels. negative values are
|
||||
// prohibited.
|
||||
int begy, begx; // origin of rendered section
|
||||
int leny, lenx; // size of rendered section
|
||||
// use NCBLIT_DEFAULT if you don't care, to use NCBLIT_2x2 (assuming
|
||||
@ -2571,6 +2571,7 @@ bprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){
|
||||
return ncmetric(val, decimal, buf, omitdec, 1024, 'i');
|
||||
}
|
||||
|
||||
// Enable or disable the terminal's cursor, if supported. Immediate effect.
|
||||
API void notcurses_cursor_enable(struct notcurses* nc);
|
||||
API void notcurses_cursor_disable(struct notcurses* nc);
|
||||
|
||||
@ -2580,16 +2581,16 @@ API void notcurses_cursor_disable(struct notcurses* nc);
|
||||
// terminal. If you can limit yourself to 256 colors, that's probably best.
|
||||
|
||||
typedef struct palette256 {
|
||||
// We store the RGB values as a regular ol' channel
|
||||
uint32_t chans[NCPALETTESIZE];
|
||||
uint32_t chans[NCPALETTESIZE]; // RGB values as regular ol' channels
|
||||
} palette256;
|
||||
|
||||
// Create a new palette store. It will be initialized with notcurses' best
|
||||
// knowledge of the currently configured palette.
|
||||
// knowledge of the currently configured palette. The palette upon startup
|
||||
// cannot be reliably detected, sadly.
|
||||
API palette256* palette256_new(struct notcurses* nc);
|
||||
|
||||
// Attempt to configure the terminal with the provided palette 'p'. Does not
|
||||
// transfer ownership of 'p'; palette256_free() can still be called.
|
||||
// transfer ownership of 'p'; palette256_free() can (ought) still be called.
|
||||
API int palette256_use(struct notcurses* nc, const palette256* p);
|
||||
|
||||
// Manipulate entries in the palette store 'p'. These are *not* locked.
|
||||
@ -2671,6 +2672,8 @@ typedef struct ncselector_options {
|
||||
API struct ncselector* ncselector_create(struct ncplane* n, int y, int x,
|
||||
const ncselector_options* opts);
|
||||
|
||||
// Dynamically add or delete items. It is usually sufficient to supply a static
|
||||
// list of items via ncselector_options->items.
|
||||
API int ncselector_additem(struct ncselector* n, const struct ncselector_item* item);
|
||||
API int ncselector_delitem(struct ncselector* n, const char* item);
|
||||
|
||||
@ -2890,8 +2893,8 @@ API int ncmenu_destroy(struct ncmenu* n);
|
||||
typedef struct ncplot_options {
|
||||
// channels for the maximum and minimum levels. linear or exponential
|
||||
// interpolation will be applied across the domain between these two.
|
||||
uint64_t maxchannel;
|
||||
uint64_t minchannel;
|
||||
uint64_t maxchannels;
|
||||
uint64_t minchannels;
|
||||
// styling used for the legend, if NCPLOT_OPTION_LABELTICKSD is set
|
||||
uint16_t legendstyle;
|
||||
// if you don't care, pass NCBLIT_DEFAULT and get NCBLIT_8x1 (assuming
|
||||
@ -2903,6 +2906,7 @@ typedef struct ncplot_options {
|
||||
// if rangex is 0, it is dynamically set to the number of columns.
|
||||
int rangex;
|
||||
uint64_t flags; // bitfield over NCPLOT_OPTION_*
|
||||
const char* title; // optional, printed by the labels
|
||||
} ncplot_options;
|
||||
|
||||
// Use the provided plane 'n' for plotting according to the options 'opts'.
|
||||
|
@ -348,12 +348,13 @@ int ncplane_rotate_ccw(struct ncplane* n);
|
||||
void ncplane_translate(const struct ncplane* src, const struct ncplane* dst, int* y, int* x);
|
||||
bool ncplane_translate_abs(const struct ncplane* n, int* y, int* x);
|
||||
typedef struct ncplot_options {
|
||||
uint64_t maxchannel;
|
||||
uint64_t minchannel;
|
||||
uint64_t maxchannels;
|
||||
uint64_t minchannels;
|
||||
uint16_t legendstyle;
|
||||
ncblitter_e gridtype;
|
||||
uint64_t rangex;
|
||||
unsigned flags;
|
||||
const char* title;
|
||||
} ncplot_options;
|
||||
struct ncuplot* ncuplot_create(struct ncplane* n, const ncplot_options* opts, uint64_t miny, uint64_t maxy);
|
||||
struct ncdplot* ncdplot_create(struct ncplane* n, const ncplot_options* opts, double miny, double maxy);
|
||||
|
@ -119,6 +119,13 @@ timespec_subtract(struct timespec *result, const struct timespec *time0,
|
||||
return timespec_to_ns(time0) < timespec_to_ns(time1);
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
timespec_add(struct timespec *result, const struct timespec *time0,
|
||||
struct timespec *time1){
|
||||
uint64_t ns = timespec_to_ns(time0) + timespec_to_ns(time1);
|
||||
ns_to_timespec(ns, result);
|
||||
return ns;
|
||||
}
|
||||
|
||||
// divide the provided timespec 'ts' by 'divisor' into 'quots'
|
||||
static inline void
|
||||
|
@ -543,12 +543,13 @@ int fpsgraph_init(struct notcurses* nc){
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.flags = NCPLOT_OPTION_LABELTICKSD | NCPLOT_OPTION_EXPONENTIALD;
|
||||
opts.legendstyle = NCSTYLE_ITALIC;
|
||||
channels_set_fg_rgb(&opts.minchannel, 0xff, 0x00, 0xff);
|
||||
channels_set_bg(&opts.minchannel, 0x201020);
|
||||
channels_set_bg_alpha(&opts.minchannel, CELL_ALPHA_BLEND);
|
||||
channels_set_fg_rgb(&opts.maxchannel, 0x00, 0xff, 0x00);
|
||||
channels_set_bg(&opts.maxchannel, 0x201020);
|
||||
channels_set_bg_alpha(&opts.maxchannel, CELL_ALPHA_BLEND);
|
||||
opts.title = "frames per second";
|
||||
channels_set_fg_rgb(&opts.minchannels, 0x80, 0x80, 0xff);
|
||||
channels_set_bg(&opts.minchannels, 0x201020);
|
||||
channels_set_bg_alpha(&opts.minchannels, CELL_ALPHA_BLEND);
|
||||
channels_set_fg_rgb(&opts.maxchannels, 0x80, 0xff, 0x80);
|
||||
channels_set_bg(&opts.maxchannels, 0x201020);
|
||||
channels_set_bg_alpha(&opts.maxchannels, CELL_ALPHA_BLEND);
|
||||
struct ncuplot* fpsplot = ncuplot_create(newp, &opts, 0, 0);
|
||||
if(!fpsplot){
|
||||
ncplane_destroy(newp);
|
||||
|
@ -96,7 +96,7 @@ int intro(struct notcurses* nc){
|
||||
return -1;
|
||||
}
|
||||
ncplane_styles_on(ncp, NCSTYLE_ITALIC | NCSTYLE_BOLD);
|
||||
if(ncplane_putstr_aligned(ncp, rows / 2 - 2, NCALIGN_CENTER, str) != (int)strlen(str)){
|
||||
if(ncplane_putstr_aligned(ncp, rows / 2 - 3, NCALIGN_CENTER, str) != (int)strlen(str)){
|
||||
return -1;
|
||||
}
|
||||
ncplane_styles_off(ncp, NCSTYLE_ITALIC);
|
||||
@ -104,12 +104,12 @@ int intro(struct notcurses* nc){
|
||||
int major, minor, patch, tweak;
|
||||
notcurses_version_components(&major, &minor, &patch, &tweak);
|
||||
if(tweak){
|
||||
if(ncplane_printf_aligned(ncp, rows / 2, NCALIGN_CENTER, "notcurses %d.%d.%d.%d. press 'q' to quit.",
|
||||
if(ncplane_printf_aligned(ncp, rows / 2 - 1, NCALIGN_CENTER, "notcurses %d.%d.%d.%d. press 'q' to quit.",
|
||||
major, minor, patch, tweak) < 0){
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
if(ncplane_printf_aligned(ncp, rows / 2, NCALIGN_CENTER, "notcurses %d.%d.%d. press 'q' to quit.",
|
||||
if(ncplane_printf_aligned(ncp, rows / 2 - 1, NCALIGN_CENTER, "notcurses %d.%d.%d. press 'q' to quit.",
|
||||
major, minor, patch) < 0){
|
||||
return -1;
|
||||
}
|
||||
@ -119,6 +119,10 @@ int intro(struct notcurses* nc){
|
||||
if(ncplane_putwstr_aligned(ncp, rows / 2 - 6, NCALIGN_CENTER, wstr) < 0){
|
||||
return -1;
|
||||
}
|
||||
const wchar_t iwstr[] = L"▏█ ▇ ▆ ▅ ▄ ▃ ▂ ▁ ▁ ▂ ▃ ▄ ▅ ▆ ▇ █▕";
|
||||
if(ncplane_putwstr_aligned(ncp, rows / 2 + 1, NCALIGN_CENTER, iwstr) < 0){
|
||||
return -1;
|
||||
}
|
||||
if(rows < 45){
|
||||
ncplane_set_fg_rgb(ncp, 0xc0, 0x80, 0x80);
|
||||
ncplane_set_bg_rgb(ncp, 0x20, 0x20, 0x20);
|
||||
|
573
src/demo/zoo.c
573
src/demo/zoo.c
@ -1,29 +1,29 @@
|
||||
#include "demo.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#define THREAD_RETURN_NEGATIVE ((void*)-1)
|
||||
#define THREAD_RETURN_POSITIVE ((void*)1)
|
||||
|
||||
// As the subwidgets (selector etc.) are taking the catwalk out, they process
|
||||
// input to show off their functionality. Once they're done, the expositional
|
||||
// plane might still be generating output; it should then start using
|
||||
// demo_getc_blocking(), passing any input to the widgets itself (since they're
|
||||
// inactive otherwise). This is set by the last widget (current multiselector).
|
||||
static int sub_widgets_done = 0; // guarded by main lock
|
||||
static struct ncmultiselector* mselector = NULL;
|
||||
|
||||
// open up changes.jpg, stretch it to fill, drop it to greyscale
|
||||
static int
|
||||
locked_demo_render(struct notcurses* nc, pthread_mutex_t* lock){
|
||||
int ret;
|
||||
|
||||
if(pthread_mutex_lock(lock)){
|
||||
return -1;
|
||||
draw_background(struct notcurses* nc){
|
||||
if(notcurses_canopen_images(nc)){
|
||||
struct ncplane* n = notcurses_stdplane(nc);
|
||||
nc_err_e err;
|
||||
char* path = find_data("changes.jpg");
|
||||
struct ncvisual* ncv = ncvisual_from_file(path, &err);
|
||||
free(path);
|
||||
if(!ncv){
|
||||
return -1;
|
||||
}
|
||||
struct ncvisual_options vopts = {
|
||||
.scaling = NCSCALE_STRETCH,
|
||||
.n = n,
|
||||
};
|
||||
if(ncvisual_render(nc, ncv, &vopts) == NULL){
|
||||
ncvisual_destroy(ncv);
|
||||
return -1;
|
||||
}
|
||||
ncplane_greyscale(n);
|
||||
ncvisual_destroy(ncv);
|
||||
}
|
||||
ret = demo_render(nc);
|
||||
if(pthread_mutex_unlock(lock)){
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we list all distributions on which notcurses is known to exist
|
||||
@ -64,9 +64,7 @@ static struct ncmselector_item mselect_items[] = {
|
||||
};
|
||||
|
||||
static struct ncmultiselector*
|
||||
multiselector_demo(struct ncplane* n, struct ncplane* under, int dimx,
|
||||
int y, pthread_mutex_t* lock, int* ret){
|
||||
struct notcurses* nc = ncplane_notcurses(n);
|
||||
multiselector_demo(struct ncplane* n, struct ncplane* under, int y){
|
||||
ncmultiselector_options mopts = {
|
||||
.maxdisplay = 8,
|
||||
.title = "multi-item selector",
|
||||
@ -80,110 +78,17 @@ multiselector_demo(struct ncplane* n, struct ncplane* under, int dimx,
|
||||
};
|
||||
channels_set_fg_alpha(&mopts.bgchannels, CELL_ALPHA_BLEND);
|
||||
channels_set_bg_alpha(&mopts.bgchannels, CELL_ALPHA_BLEND);
|
||||
pthread_mutex_lock(lock);
|
||||
struct ncmultiselector* mselect = ncmultiselector_create(n, y, 0, &mopts);
|
||||
if(mselect == NULL){
|
||||
pthread_mutex_unlock(lock);
|
||||
return NULL;
|
||||
}
|
||||
struct ncplane* mplane = ncmultiselector_plane(mselect);
|
||||
ncplane_move_below(mplane, under);
|
||||
pthread_mutex_unlock(lock);
|
||||
struct timespec swoopdelay;
|
||||
timespec_div(&demodelay, dimx / 3, &swoopdelay);
|
||||
pthread_mutex_lock(lock);
|
||||
int length = ncplane_dim_x(mplane);
|
||||
ncplane_move_yx(mplane, y, -length);
|
||||
pthread_mutex_unlock(lock);
|
||||
ncinput ni;
|
||||
for(int i = -length + 1 ; i < dimx - (length + 1) ; ++i){
|
||||
struct timespec now, deadline;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
ns_to_timespec(timespec_to_ns(&swoopdelay) + timespec_to_ns(&now), &deadline);
|
||||
do{
|
||||
pthread_mutex_lock(lock);
|
||||
*ret = demo_render(nc);
|
||||
ncplane_move_yx(mplane, y, i);
|
||||
pthread_mutex_unlock(lock);
|
||||
if(*ret){
|
||||
ncmultiselector_destroy(mselect);
|
||||
return NULL;
|
||||
}
|
||||
struct timespec iterdelay;
|
||||
ns_to_timespec(timespec_subtract_ns(&deadline, &now), &iterdelay);
|
||||
char32_t wc = demo_getc(nc, &iterdelay, &ni);
|
||||
if(wc == (char32_t)-1){
|
||||
ncmultiselector_destroy(mselect);
|
||||
return NULL;
|
||||
}else if(wc){
|
||||
pthread_mutex_lock(lock);
|
||||
ncmultiselector_offer_input(mselect, &ni);
|
||||
*ret = demo_render(nc);
|
||||
pthread_mutex_unlock(lock);
|
||||
if(*ret){
|
||||
ncmultiselector_destroy(mselect);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
}while(timespec_to_ns(&now) < timespec_to_ns(&deadline));
|
||||
}
|
||||
if( (*ret = locked_demo_render(nc, lock)) ){
|
||||
ncmultiselector_destroy(mselect);
|
||||
return NULL;
|
||||
}
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
uint64_t cur = timespec_to_ns(&ts);
|
||||
uint64_t targ = cur + timespec_to_ns(&demodelay);
|
||||
do{
|
||||
struct timespec rel;
|
||||
ns_to_timespec(targ - cur, &rel);
|
||||
char32_t wc = demo_getc(nc, &rel, &ni);
|
||||
if(wc == (char32_t)-1){
|
||||
ncmultiselector_destroy(mselect);
|
||||
return NULL;
|
||||
}else if(wc){
|
||||
ncmultiselector_offer_input(mselect, &ni);
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
cur = timespec_to_ns(&ts);
|
||||
}while(cur < targ);
|
||||
pthread_mutex_lock(lock);
|
||||
sub_widgets_done = 1;
|
||||
pthread_mutex_unlock(lock);
|
||||
return mselect;
|
||||
}
|
||||
|
||||
static int
|
||||
draw_background(struct notcurses* nc){
|
||||
if(notcurses_canopen_images(nc)){
|
||||
struct ncplane* n = notcurses_stdplane(nc);
|
||||
nc_err_e err;
|
||||
char* path = find_data("changes.jpg");
|
||||
struct ncvisual* ncv = ncvisual_from_file(path, &err);
|
||||
free(path);
|
||||
if(!ncv){
|
||||
return -1;
|
||||
}
|
||||
struct ncvisual_options vopts = {
|
||||
.scaling = NCSCALE_STRETCH,
|
||||
.n = n,
|
||||
};
|
||||
if(ncvisual_render(nc, ncv, &vopts) == NULL){
|
||||
ncvisual_destroy(ncv);
|
||||
return -1;
|
||||
}
|
||||
ncplane_greyscale(n);
|
||||
ncvisual_destroy(ncv);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ncselector*
|
||||
selector_demo(struct ncplane* n, struct ncplane* under, int dimx,
|
||||
int y, pthread_mutex_t* lock, int* ret){
|
||||
struct notcurses* nc = ncplane_notcurses(n);
|
||||
selector_demo(struct ncplane* n, struct ncplane* under, int dimx, int y){
|
||||
ncselector_options sopts = {
|
||||
.title = "single-item selector",
|
||||
.items = select_items,
|
||||
@ -198,54 +103,20 @@ selector_demo(struct ncplane* n, struct ncplane* under, int dimx,
|
||||
};
|
||||
channels_set_fg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND);
|
||||
channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND);
|
||||
pthread_mutex_lock(lock);
|
||||
struct ncselector* selector = ncselector_create(n, y, dimx, &sopts);
|
||||
if(selector == NULL){
|
||||
pthread_mutex_unlock(lock);
|
||||
return NULL;
|
||||
}
|
||||
struct ncplane* splane = ncselector_plane(selector);
|
||||
ncplane_move_below(splane, under);
|
||||
pthread_mutex_unlock(lock);
|
||||
struct timespec swoopdelay;
|
||||
timespec_div(&demodelay, dimx / 3, &swoopdelay);
|
||||
ncinput ni;
|
||||
for(int i = dimx - 1 ; i > 1 ; --i){
|
||||
struct timespec now, deadline;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
ns_to_timespec(timespec_to_ns(&swoopdelay) + timespec_to_ns(&now), &deadline);
|
||||
do{
|
||||
pthread_mutex_lock(lock);
|
||||
*ret = demo_render(nc);
|
||||
ncplane_move_yx(splane, y, i);
|
||||
pthread_mutex_unlock(lock);
|
||||
if(*ret){
|
||||
ncselector_destroy(selector, NULL);
|
||||
return NULL;
|
||||
}
|
||||
struct timespec iterdelay;
|
||||
ns_to_timespec(timespec_subtract_ns(&deadline, &now), &iterdelay);
|
||||
char32_t wc = demo_getc(nc, &iterdelay, &ni);
|
||||
if(wc == (char32_t)-1){
|
||||
ncselector_destroy(selector, NULL);
|
||||
return NULL;
|
||||
}else if(wc){
|
||||
pthread_mutex_lock(lock);
|
||||
ncselector_offer_input(selector, &ni);
|
||||
*ret = demo_render(nc);
|
||||
pthread_mutex_unlock(lock);
|
||||
if(*ret){
|
||||
ncselector_destroy(selector, NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
}while(timespec_to_ns(&now) < timespec_to_ns(&deadline));
|
||||
}
|
||||
if( (*ret = locked_demo_render(nc, lock)) ){
|
||||
ncselector_destroy(selector, NULL);
|
||||
return NULL;
|
||||
}
|
||||
struct ncplane* mplane = ncselector_plane(selector);
|
||||
ncplane_move_below(mplane, under);
|
||||
return selector;
|
||||
}
|
||||
|
||||
// wait one demodelay period, offering input to the multiselector, then fade
|
||||
// out both widgets (if supported).
|
||||
static int
|
||||
reader_post(struct notcurses* nc, struct ncselector* selector, struct ncmultiselector* mselector){
|
||||
int ret;
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
uint64_t cur = timespec_to_ns(&ts);
|
||||
@ -253,143 +124,194 @@ selector_demo(struct ncplane* n, struct ncplane* under, int dimx,
|
||||
do{
|
||||
struct timespec rel;
|
||||
ns_to_timespec(targ - cur, &rel);
|
||||
ncinput ni;
|
||||
char32_t wc = demo_getc(nc, &rel, &ni);
|
||||
if(wc == (char32_t)-1){
|
||||
ncselector_destroy(selector, NULL);
|
||||
return NULL;
|
||||
return -1;
|
||||
}else if(wc){
|
||||
pthread_mutex_lock(lock);
|
||||
ncselector_offer_input(selector, &ni);
|
||||
pthread_mutex_unlock(lock);
|
||||
ncmultiselector_offer_input(mselector, &ni);
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
cur = timespec_to_ns(&ts);
|
||||
}while(cur < targ);
|
||||
return selector;
|
||||
}
|
||||
|
||||
static int
|
||||
riser_collect_input(struct notcurses* nc, const struct timespec* ts){
|
||||
struct timespec now, deadline;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
ns_to_timespec(timespec_to_ns(&now) + timespec_to_ns(ts), &deadline);
|
||||
do{
|
||||
ncinput ni;
|
||||
char32_t key = demo_getc(nc, ts, &ni);
|
||||
if(key == (char32_t)-1){
|
||||
return -1;
|
||||
}else if(key){
|
||||
ncmultiselector_offer_input(mselector, &ni);
|
||||
if( (ret = demo_render(nc)) ){
|
||||
return ret;
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
}while(timespec_to_ns(&deadline) > timespec_to_ns(&now));
|
||||
}while(cur < targ);
|
||||
if(notcurses_canfade(nc)){
|
||||
if(ncplane_fadeout(ncselector_plane(selector), &demodelay, demo_fader, NULL)){
|
||||
return -1;
|
||||
}
|
||||
if(ncplane_fadeout(ncmultiselector_plane(mselector), &demodelay, demo_fader, NULL)){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct read_marshal {
|
||||
struct notcurses* nc;
|
||||
struct ncreader* reader;
|
||||
pthread_mutex_t* lock;
|
||||
} read_marshal;
|
||||
static int
|
||||
layout_next_text(struct ncreader* reader, const char* text, size_t* textpos){
|
||||
size_t towrite = strcspn(text + *textpos, " \t\n");
|
||||
towrite += strspn(text + *textpos + towrite, " \t\n");
|
||||
if(towrite){
|
||||
char* duped = strndup(text + *textpos, towrite);
|
||||
size_t bytes;
|
||||
if(ncplane_puttext(ncreader_plane(reader), -1, NCALIGN_LEFT, duped, &bytes) < 0 || bytes != strlen(duped)){
|
||||
free(duped);
|
||||
return -1;
|
||||
}
|
||||
free(duped);
|
||||
*textpos += towrite;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void*
|
||||
reader_thread(void* vmarsh){
|
||||
static int
|
||||
run_out_text(struct ncreader* reader, const char* text, size_t* textpos,
|
||||
const struct timespec* iterdelay){
|
||||
while(text[*textpos]){
|
||||
int ret = layout_next_text(reader, text, textpos);
|
||||
if(ret){
|
||||
return ret;
|
||||
}
|
||||
demo_nanosleep(ncplane_notcurses(ncreader_plane(reader)), iterdelay);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// selector moves across to the left; reader moves up halfway to the center
|
||||
static int
|
||||
selector_run(struct notcurses* nc, struct ncreader* reader, struct ncselector* selector){
|
||||
const char text[] =
|
||||
"Notcurses provides several widgets to quickly build vivid TUIs.\n\n"
|
||||
"This NCReader widget facilitates free-form text entry complete with readline-style bindings. "
|
||||
"NCSelector allows a single option to be selected from a list. "
|
||||
"NCSelector allows a single option to be selected from a list. ";
|
||||
int ret = 0, dimy, dimx;
|
||||
ncplane_dim_yx(notcurses_stdplane(nc), &dimy, &dimx);
|
||||
const int centery = (dimy - ncplane_dim_y(ncreader_plane(reader))) / 2;
|
||||
int ry, rx, sy, sx;
|
||||
ncplane_yx(ncreader_plane(reader), &ry, &rx);
|
||||
ncplane_yx(ncselector_plane(selector), &sy, &sx);
|
||||
const int xiters = sx - 2;
|
||||
const int yiters = (ry - centery) / 2;
|
||||
const int iters = yiters > xiters ? yiters : xiters;
|
||||
const double eachy = (double)iters / yiters;
|
||||
const double eachx = (double)iters / xiters;
|
||||
int xi = 1;
|
||||
int yi = 1;
|
||||
struct timespec iterdelay, start;
|
||||
timespec_div(&demodelay, iters, &iterdelay);
|
||||
size_t textpos = 0;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
for(int i = 0 ; i < iters ; ++i){
|
||||
if( (ret = layout_next_text(reader, text, &textpos)) ){
|
||||
return ret;
|
||||
}
|
||||
if(i == (int)(xi * eachx)){
|
||||
if(ncplane_move_yx(ncselector_plane(selector), sy, --sx)){
|
||||
return -1;
|
||||
}
|
||||
++xi;
|
||||
}
|
||||
if(i == (int)(yi * eachy)){
|
||||
if(ncplane_move_yx(ncreader_plane(reader), --ry, rx)){
|
||||
return -1;
|
||||
}
|
||||
++yi;
|
||||
}
|
||||
struct timespec targettime, now;
|
||||
timespec_mul(&iterdelay, i + 1, &targettime);
|
||||
const uint64_t deadline_ns = timespec_to_ns(&start) + timespec_to_ns(&targettime);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
while(timespec_to_ns(&now) < deadline_ns){
|
||||
if( (ret = demo_render(nc)) ){
|
||||
return ret;
|
||||
}
|
||||
struct ncinput ni;
|
||||
struct timespec inputtime;
|
||||
ns_to_timespec(deadline_ns - timespec_to_ns(&now), &inputtime);
|
||||
char32_t wc = demo_getc(nc, &inputtime, &ni);
|
||||
if(wc == (char32_t)-1){
|
||||
return -1;
|
||||
}else if(wc){
|
||||
ncselector_offer_input(selector, &ni);
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
}
|
||||
}
|
||||
return run_out_text(reader, text, &textpos, &iterdelay);
|
||||
}
|
||||
|
||||
// selector moves across to the right; reader moves up halfway to the center
|
||||
static int
|
||||
mselector_run(struct notcurses* nc, struct ncreader* reader, struct ncmultiselector* mselector){
|
||||
const char text[] =
|
||||
"NCMultiselector allows 0..n options to be selected from a list of n items. "
|
||||
"NCFdplane streams a file descriptor, while NCSubproc spawns a subprocess and streams its output. "
|
||||
"A variety of plots are supported, and menus can be placed along the top and/or bottom of any plane.\n\n"
|
||||
"Widgets can be controlled with the keyboard and/or mouse. They are implemented atop ncplanes, and these planes can be manipulated like all others.";
|
||||
const size_t textlen = strlen(text);
|
||||
read_marshal* marsh = vmarsh;
|
||||
struct notcurses* nc = marsh->nc;
|
||||
struct ncreader* reader = marsh->reader;
|
||||
pthread_mutex_t* lock = marsh->lock;
|
||||
free(marsh);
|
||||
int x, y;
|
||||
struct ncplane* rplane = ncreader_plane(reader);
|
||||
struct timespec rowdelay;
|
||||
ncplane_yx(rplane, &y, &x);
|
||||
int targrow = y / 2;
|
||||
// the other widgets divide the movement range by 3 (and thus take about 3
|
||||
// demodelays to transit). take about 3 demodelays to rise to midscreen. this
|
||||
// also affects the "typing" speed.
|
||||
timespec_div(&demodelay, (y - targrow) / 2, &rowdelay);
|
||||
// we usually won't be done rendering the text before reaching our target row
|
||||
int ret = 0, dimy, dimx;
|
||||
ncplane_dim_yx(notcurses_stdplane(nc), &dimy, &dimx);
|
||||
const int centery = (dimy - ncplane_dim_y(ncreader_plane(reader))) / 2;
|
||||
int ry, rx, sy, sx;
|
||||
ncplane_yx(ncreader_plane(reader), &ry, &rx);
|
||||
ncplane_yx(ncmultiselector_plane(mselector), &sy, &sx);
|
||||
const int xiters = dimx - ncplane_dim_x(ncmultiselector_plane(mselector));
|
||||
const int yiters = ry - centery;
|
||||
const int iters = yiters > xiters ? yiters : xiters;
|
||||
const double eachy = (double)iters / yiters;
|
||||
const double eachx = (double)iters / xiters;
|
||||
int xi = 1;
|
||||
int yi = 1;
|
||||
struct timespec iterdelay, start;
|
||||
timespec_div(&demodelay, iters, &iterdelay);
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
size_t textpos = 0;
|
||||
int ret;
|
||||
bool collect_input = false;
|
||||
while(textpos < textlen || y > targrow){
|
||||
pthread_mutex_lock(lock);
|
||||
ncplane_move_yx(rplane, y, x);
|
||||
size_t towrite = strcspn(text + textpos, " \t\n");
|
||||
towrite += strspn(text + textpos + towrite, " \t\n");
|
||||
if(towrite){
|
||||
char* duped = strndup(text + textpos, towrite);
|
||||
size_t bytes;
|
||||
if(ncplane_puttext(rplane, -1, NCALIGN_LEFT, duped, &bytes) < 0 || bytes != strlen(duped)){
|
||||
free(duped);
|
||||
return THREAD_RETURN_NEGATIVE;
|
||||
}
|
||||
free(duped);
|
||||
textpos += towrite;
|
||||
for(int i = 0 ; i < iters ; ++i){
|
||||
if( (ret = layout_next_text(reader, text, &textpos)) ){
|
||||
return ret;
|
||||
}
|
||||
if(i == (int)(xi * eachx)){
|
||||
if(ncplane_move_yx(ncmultiselector_plane(mselector), sy, ++sx)){
|
||||
return -1;
|
||||
}
|
||||
if(sub_widgets_done){
|
||||
collect_input = true;
|
||||
++xi;
|
||||
}
|
||||
if(i == (int)(yi * eachy)){
|
||||
if(ncplane_move_yx(ncreader_plane(reader), --ry, rx)){
|
||||
return -1;
|
||||
}
|
||||
++yi;
|
||||
}
|
||||
struct timespec targettime, now;
|
||||
timespec_mul(&iterdelay, i + 1, &targettime);
|
||||
const uint64_t deadline_ns = timespec_to_ns(&start) + timespec_to_ns(&targettime);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
while(timespec_to_ns(&now) < deadline_ns){
|
||||
if( (ret = demo_render(nc)) ){
|
||||
pthread_mutex_unlock(lock);
|
||||
if(ret < 0){
|
||||
return THREAD_RETURN_NEGATIVE;
|
||||
}else if(ret > 0){
|
||||
return THREAD_RETURN_POSITIVE;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
if(y > targrow){
|
||||
--y;
|
||||
struct ncinput ni;
|
||||
struct timespec inputtime;
|
||||
ns_to_timespec(deadline_ns - timespec_to_ns(&now), &inputtime);
|
||||
char32_t wc = demo_getc(nc, &inputtime, &ni);
|
||||
if(wc == (char32_t)-1){
|
||||
return -1;
|
||||
}else if(wc){
|
||||
ncmultiselector_offer_input(mselector, &ni);
|
||||
}
|
||||
pthread_mutex_unlock(lock);
|
||||
if(collect_input){
|
||||
ret = riser_collect_input(nc, &rowdelay);
|
||||
}else{
|
||||
ret = clock_nanosleep(CLOCK_MONOTONIC, 0, &rowdelay, NULL);
|
||||
}
|
||||
if(ret < 0){
|
||||
return THREAD_RETURN_NEGATIVE;
|
||||
}else if(ret > 0){
|
||||
return THREAD_RETURN_POSITIVE;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
}
|
||||
}
|
||||
pthread_mutex_lock(lock);
|
||||
if(sub_widgets_done){
|
||||
collect_input = true;
|
||||
}
|
||||
pthread_mutex_unlock(lock);
|
||||
if(collect_input){
|
||||
ret = riser_collect_input(nc, &demodelay);
|
||||
}
|
||||
if(ret < 0){
|
||||
return THREAD_RETURN_NEGATIVE;
|
||||
}else if(ret > 0){
|
||||
return THREAD_RETURN_POSITIVE;
|
||||
}
|
||||
return NULL;
|
||||
return run_out_text(reader, text, &textpos, &iterdelay);
|
||||
}
|
||||
|
||||
// creates an ncreader, and spawns a thread which will fill it with text
|
||||
// describing the rest of the demo
|
||||
static struct ncreader*
|
||||
reader_demo(struct notcurses* nc, pthread_t* tid, pthread_mutex_t* lock){
|
||||
read_marshal* marsh = malloc(sizeof(*marsh));
|
||||
if(marsh == NULL){
|
||||
return NULL;
|
||||
}
|
||||
marsh->nc = nc;
|
||||
marsh->lock = lock;
|
||||
int dimy;
|
||||
struct ncplane* std = notcurses_stddim_yx(nc, &dimy, NULL);
|
||||
// creates an ncreader, ncselector, and ncmultiselector, and moves them into
|
||||
// place. the latter two are then faded out. all three are then destroyed.
|
||||
static int
|
||||
reader_demo(struct notcurses* nc){
|
||||
int ret = -1;
|
||||
int dimy, dimx;
|
||||
struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx);
|
||||
const int READER_COLS = 64;
|
||||
const int READER_ROWS = 8;
|
||||
ncreader_options nopts = {
|
||||
@ -401,87 +323,50 @@ reader_demo(struct notcurses* nc, pthread_t* tid, pthread_mutex_t* lock){
|
||||
};
|
||||
channels_set_bg_alpha(&nopts.echannels, CELL_ALPHA_BLEND);
|
||||
const int x = ncplane_align(std, NCALIGN_CENTER, nopts.physcols);
|
||||
if((marsh->reader = ncreader_create(std, dimy, x, &nopts)) == NULL){
|
||||
free(marsh);
|
||||
return NULL;
|
||||
struct ncselector* selector = NULL;
|
||||
struct ncmultiselector* mselector = NULL;
|
||||
struct ncreader* reader = ncreader_create(std, dimy, x, &nopts);
|
||||
if(reader == NULL){
|
||||
goto done;
|
||||
}
|
||||
struct ncreader* reader = marsh->reader;
|
||||
ncplane_set_scrolling(ncreader_plane(reader), true);
|
||||
if(pthread_create(tid, NULL, reader_thread, marsh)){
|
||||
ncreader_destroy(marsh->reader, NULL);
|
||||
free(marsh);
|
||||
return NULL;
|
||||
// Bring the selector left across the top, while raising the exposition
|
||||
// halfway to its target height.
|
||||
selector = selector_demo(std, ncreader_plane(reader), dimx, 2);
|
||||
if(selector == NULL){
|
||||
goto done;
|
||||
}
|
||||
if( (ret = selector_run(nc, reader, selector)) ){
|
||||
goto done;
|
||||
}
|
||||
// Bring the multiselector right across the top, while raising the exposition
|
||||
// the remainder of its path to the center of the screen.
|
||||
mselector = multiselector_demo(std, ncreader_plane(reader), 8);
|
||||
if(mselector == NULL){
|
||||
goto done;
|
||||
}
|
||||
if( (ret = mselector_run(nc, reader, mselector)) ){
|
||||
goto done;
|
||||
}
|
||||
// Delay and fade
|
||||
if( (ret = reader_post(nc, selector, mselector)) ){
|
||||
goto done;
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
static int
|
||||
zap_reader(pthread_t tid, unsigned cancel){
|
||||
if(cancel){
|
||||
pthread_cancel(tid);
|
||||
}
|
||||
void* res;
|
||||
int ret = pthread_join(tid, &res);
|
||||
if(res == THREAD_RETURN_NEGATIVE){
|
||||
return -1;
|
||||
}else if(res == THREAD_RETURN_POSITIVE){
|
||||
return 1;
|
||||
}
|
||||
done:
|
||||
ncselector_destroy(selector, NULL);
|
||||
ncmultiselector_destroy(mselector);
|
||||
ncreader_destroy(reader, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// a plane with exposition text rises from the bottom to the center of the
|
||||
// screen. as it does so, two widgets (selector and multiselector) come in
|
||||
// from the left and right, respectively. they then fade out.
|
||||
int zoo_demo(struct notcurses* nc){
|
||||
int dimx;
|
||||
if(draw_background(nc)){
|
||||
return -1;
|
||||
}
|
||||
pthread_mutex_t lock;
|
||||
if(pthread_mutex_init(&lock, NULL)){
|
||||
return -1;
|
||||
}
|
||||
struct ncplane* n = notcurses_stddim_yx(nc, NULL, &dimx);
|
||||
pthread_t readertid;
|
||||
struct ncreader* reader = reader_demo(nc, &readertid, &lock);
|
||||
// if we didn't get a reader, need to hand-roll the exit, since we have no
|
||||
// thread at which we might go off blasting
|
||||
if(reader == NULL){
|
||||
pthread_mutex_destroy(&lock);
|
||||
return -1;
|
||||
}
|
||||
int ret = 0;
|
||||
struct ncselector* selector = NULL;
|
||||
selector = selector_demo(n, ncreader_plane(reader), dimx, 2, &lock, &ret);
|
||||
if(selector == NULL || ret){
|
||||
goto err;
|
||||
}
|
||||
mselector = multiselector_demo(n, ncreader_plane(reader), dimx, 8, &lock, &ret); // FIXME calculate from splane
|
||||
if(mselector == NULL || ret){
|
||||
goto err;
|
||||
}
|
||||
ret |= zap_reader(readertid, false); // let the thread do its thang
|
||||
ret |= pthread_mutex_destroy(&lock);
|
||||
if(notcurses_canfade(nc)){
|
||||
if(ncplane_fadeout(ncselector_plane(selector), &demodelay, demo_fader, NULL)){
|
||||
goto err;
|
||||
}
|
||||
if(ncplane_fadeout(ncmultiselector_plane(mselector), &demodelay, demo_fader, NULL)){
|
||||
goto err;
|
||||
}
|
||||
}else{
|
||||
if( (ret = demo_nanosleep(nc, &demodelay)) ){
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
ncreader_destroy(reader, NULL);
|
||||
ncselector_destroy(selector, NULL);
|
||||
ncmultiselector_destroy(mselector);
|
||||
return ret;
|
||||
|
||||
err:
|
||||
zap_reader(readertid, true);
|
||||
pthread_mutex_destroy(&lock);
|
||||
ncreader_destroy(reader, NULL);
|
||||
ncselector_destroy(selector, NULL);
|
||||
ncmultiselector_destroy(mselector);
|
||||
return ret ? ret : -1;
|
||||
return reader_demo(nc);
|
||||
}
|
||||
|
@ -210,9 +210,9 @@ int input_demo(ncpp::NotCurses* nc) {
|
||||
struct ncplot_options popts{};
|
||||
// FIXME would be nice to switch over to exponential at some level
|
||||
popts.flags = NCPLOT_OPTION_LABELTICKSD;
|
||||
popts.minchannel = popts.maxchannel = 0;
|
||||
channels_set_fg_rgb(&popts.minchannel, 0x40, 0x50, 0xb0);
|
||||
channels_set_fg_rgb(&popts.maxchannel, 0x40, 0xff, 0xd0);
|
||||
popts.minchannels = popts.maxchannels = 0;
|
||||
channels_set_fg_rgb(&popts.minchannels, 0x40, 0x50, 0xb0);
|
||||
channels_set_fg_rgb(&popts.maxchannels, 0x40, 0xff, 0xd0);
|
||||
popts.gridtype = static_cast<ncblitter_e>(NCBLIT_2x2);
|
||||
plot = ncuplot_create(pplane, &popts, 0, 0);
|
||||
if(!plot){
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include "internal.h"
|
||||
#include "notcurses/notcurses.h"
|
||||
|
||||
@ -53,6 +54,9 @@ class ncppplot {
|
||||
return false;
|
||||
}
|
||||
int dimx = sdimx;
|
||||
if(opts->title){
|
||||
ncpp->title = std::string(opts->title);
|
||||
}
|
||||
ncpp->rangex = opts->rangex;
|
||||
// if we're sizing the plot based off the plane dimensions, scale it by the
|
||||
// plot geometry's width for all calculations
|
||||
@ -77,8 +81,8 @@ class ncppplot {
|
||||
if(ncpp->slots){
|
||||
memset(ncpp->slots, 0, slotsize);
|
||||
ncpp->ncp = n;
|
||||
ncpp->maxchannel = opts->maxchannel;
|
||||
ncpp->minchannel = opts->minchannel;
|
||||
ncpp->maxchannels = opts->maxchannels;
|
||||
ncpp->minchannels = opts->minchannels;
|
||||
ncpp->bset = bset;
|
||||
ncpp->miny = miny;
|
||||
ncpp->maxy = maxy;
|
||||
@ -127,13 +131,13 @@ class ncppplot {
|
||||
// if we want fewer slots than there are available columns, our final column
|
||||
// will be other than the plane's final column. most recent x goes here.
|
||||
const int finalx = (slotcount < scaleddim - 1 - (startx * scale) ? startx + (slotcount / scale) - 1 : dimx - 1);
|
||||
ncplane_set_attr(ncp, legendstyle);
|
||||
if(labelaxisd){
|
||||
// show the *top* of each interval range
|
||||
ncplane_set_attr(ncp, legendstyle);
|
||||
for(int y = 0 ; y < dimy ; ++y){
|
||||
uint64_t channels = 0;
|
||||
calc_gradient_channels(&channels, maxchannel, maxchannel,
|
||||
minchannel, minchannel, y, 0, dimy, dimx);
|
||||
calc_gradient_channels(&channels, minchannels, minchannels,
|
||||
maxchannels, maxchannels, y, 0, dimy, dimx);
|
||||
ncplane_set_channels(ncp, channels);
|
||||
char buf[PREFIXSTRLEN + 1];
|
||||
if(exponentiali){
|
||||
@ -145,10 +149,20 @@ class ncppplot {
|
||||
}else{
|
||||
ncmetric((maxy - interval * states * (dimy - y - 1)) * 100, 100, buf, 0, 1000, '\0');
|
||||
}
|
||||
ncplane_printf_yx(ncp, dimy - y - 1, PREFIXCOLUMNS - strlen(buf), "%s", buf);
|
||||
if(y == dimy - 1 && !title.empty()){
|
||||
ncplane_printf_yx(ncp, dimy - y - 1, PREFIXCOLUMNS - strlen(buf), "%s %s", buf, title.c_str());
|
||||
}else{
|
||||
ncplane_printf_yx(ncp, dimy - y - 1, PREFIXCOLUMNS - strlen(buf), "%s", buf);
|
||||
}
|
||||
}
|
||||
ncplane_set_attr(ncp, NCSTYLE_NONE);
|
||||
}else if(!title.empty()){
|
||||
uint64_t channels = 0;
|
||||
calc_gradient_channels(&channels, minchannels, minchannels,
|
||||
maxchannels, maxchannels, dimy - 1, 0, dimy, dimx);
|
||||
ncplane_set_channels(ncp, channels);
|
||||
ncplane_printf_yx(ncp, 0, PREFIXCOLUMNS - title.length(), "%s", title.c_str());
|
||||
}
|
||||
ncplane_set_attr(ncp, NCSTYLE_NONE);
|
||||
if(finalx < startx){ // exit on pathologically narrow planes
|
||||
return 0;
|
||||
}
|
||||
@ -182,8 +196,8 @@ class ncppplot {
|
||||
const wchar_t* egc = bset->egcs;
|
||||
for(int y = 0 ; y < dimy ; ++y){
|
||||
uint64_t channels = 0;
|
||||
calc_gradient_channels(&channels, maxchannel, maxchannel,
|
||||
minchannel, minchannel, y, x, dimy, dimx);
|
||||
calc_gradient_channels(&channels, minchannels, minchannels,
|
||||
maxchannels, maxchannels, y, x, dimy, dimx);
|
||||
ncplane_set_channels(ncp, channels);
|
||||
size_t egcidx = 0, sumidx = 0;
|
||||
// if we've got at least one interval's worth on the number of positions
|
||||
@ -363,11 +377,12 @@ class ncppplot {
|
||||
|
||||
private:
|
||||
|
||||
uint64_t maxchannel;
|
||||
uint64_t minchannel;
|
||||
uint64_t maxchannels;
|
||||
uint64_t minchannels;
|
||||
uint16_t legendstyle;
|
||||
bool vertical_indep; // not yet implemented FIXME
|
||||
const struct blitset* bset;
|
||||
std::string title;
|
||||
// requested number of slots. 0 for automatically setting the number of slots
|
||||
// to span the horizontal area. if there are more slots than there are
|
||||
// columns, we prefer showing more recent slots to less recent. if there are
|
||||
|
@ -4,21 +4,23 @@
|
||||
using namespace ncpp;
|
||||
|
||||
ncplot_options PlotD::default_options = {
|
||||
0, // maxchannel
|
||||
0, // minchannel
|
||||
0, // legendstyle
|
||||
0, // maxchannels
|
||||
0, // minchannels
|
||||
0, // legendstyle
|
||||
ncblitter_e::NCBLIT_1x1, // ncblitter_e
|
||||
0, // rangex
|
||||
0, // flags
|
||||
0, // rangex
|
||||
0, // flags
|
||||
"", // title
|
||||
};
|
||||
|
||||
ncplot_options PlotU::default_options = {
|
||||
0, // maxchannel
|
||||
0, // minchannel
|
||||
0, // legendstyle
|
||||
0, // maxchannels
|
||||
0, // minchannels
|
||||
0, // legendstyle
|
||||
ncblitter_e::NCBLIT_1x1, // ncblitter_e
|
||||
0, // rangex
|
||||
0, // flags
|
||||
0, // rangex
|
||||
0, // flags
|
||||
"", // title
|
||||
};
|
||||
|
||||
Plane* PlotD::get_plane () const noexcept
|
||||
|
@ -1,5 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# Extract a list of the public API, both shared object functions and those
|
||||
# static inline functions in the public headers.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user