From 7f82ac6f160a2f9c7e640a5d5718e4e40b75ff70 Mon Sep 17 00:00:00 2001 From: nick black Date: Tue, 24 Dec 2019 23:13:43 -0500 Subject: [PATCH] ULTRAMEGAOK: mouse-moveable HUD #162 --- src/demo/boxdemo.c | 2 +- src/demo/demo.c | 28 +++++++---- src/demo/demo.h | 34 +++++++++++++ src/demo/eagle.c | 6 +-- src/demo/grid.c | 6 +-- src/demo/hud.c | 105 +++++++++++++++++++++++++++++++++++++++ src/demo/input.c | 19 ++++++- src/demo/luigi.c | 2 +- src/demo/maxcolor.c | 2 +- src/demo/outro.c | 4 +- src/demo/panelreel.c | 6 +-- src/demo/sliding.c | 6 +-- src/demo/unicodeblocks.c | 3 ++ src/demo/view.c | 8 +-- src/demo/witherworm.c | 4 +- src/demo/xray.c | 2 +- src/poc/rgbbg.c | 2 +- 17 files changed, 203 insertions(+), 36 deletions(-) create mode 100644 src/demo/hud.c diff --git a/src/demo/boxdemo.c b/src/demo/boxdemo.c index 9accfe9b1..abfa61937 100644 --- a/src/demo/boxdemo.c +++ b/src/demo/boxdemo.c @@ -82,7 +82,7 @@ int box_demo(struct notcurses* nc){ ++y; ++x; } - if(notcurses_render(nc)){ + if(demo_render(nc)){ return -1; } nanosleep(&iterdelay, NULL); diff --git a/src/demo/demo.c b/src/demo/demo.c index d6f3a90de..382f33c7b 100644 --- a/src/demo/demo.c +++ b/src/demo/demo.c @@ -15,6 +15,8 @@ static const int MIN_SUPPORTED_ROWS = 24; static const int MIN_SUPPORTED_COLS = 80; +static int democount; +static demoresult* results; static atomic_bool interrupted = ATOMIC_VAR_INIT(false); static const char DEFAULT_DEMO[] = "ixemlubgswvpo"; @@ -24,6 +26,13 @@ void interrupt_demo(void){ atomic_store(&interrupted, true); } +const demoresult* demoresult_lookup(int idx){ + if(idx < 0 || idx >= democount){ + return NULL; + } + return &results[idx]; +} + char* find_data(const char* datum){ char* path = malloc(strlen(datadir) + 1 + strlen(datum) + 1); strcpy(path, datadir); @@ -171,7 +180,7 @@ intro(struct notcurses* nc){ } ncplane_styles_off(ncp, CELL_STYLE_BLINK); // heh FIXME replace with pulse } - if(notcurses_render(nc)){ + if(demo_render(nc)){ return -1; } nanosleep(&demodelay, NULL); @@ -180,21 +189,15 @@ intro(struct notcurses* nc){ return 0; } -typedef struct demoresult { - char selector; - struct ncstats stats; - uint64_t timens; - bool failed; -} demoresult; - static demoresult* ext_demos(struct notcurses* nc, const char* demos){ int ret = 0; - demoresult* results = malloc(sizeof(*results) * strlen(demos)); + results = malloc(sizeof(*results) * strlen(demos)); if(results == NULL){ return NULL; } memset(results, 0, sizeof(*results) * strlen(demos)); + democount = strlen(demos); struct timespec start, now; clock_gettime(CLOCK_MONOTONIC, &start); uint64_t prevns = timespec_to_ns(&start); @@ -311,6 +314,9 @@ int main(int argc, char** argv){ if(notcurses_mouse_enable(nc)){ goto err; } + if(hud_create(nc) == NULL){ + goto err; + } if(input_dispatcher(nc)){ goto err; } @@ -325,7 +331,9 @@ int main(int argc, char** argv){ }else{ nanosleep(&demodelay, NULL); } - demoresult* results = ext_demos(nc, demos); + if(ext_demos(nc, demos)){ + goto err; + } if(results == NULL){ goto err; } diff --git a/src/demo/demo.h b/src/demo/demo.h index f2b3f8b11..2023b5e59 100644 --- a/src/demo/demo.h +++ b/src/demo/demo.h @@ -57,6 +57,7 @@ demo_getc_blocking(ncinput* ni){ } /*----------------------------- end demo input API -------------------------*/ +/*-------------------------------time helpers----------------------------*/ int timespec_subtract(struct timespec *result, const struct timespec *time1, struct timespec *time0); @@ -98,6 +99,39 @@ timespec_mul(const struct timespec* ts, unsigned multiplier, struct timespec* pr product->tv_nsec = ns % GIG; product->tv_sec = ns / GIG; } +/*-------------------------------time helpers----------------------------*/ + +/*----------------------------------HUD----------------------------------*/ +extern struct ncplane* hud; +struct ncplane* hud_create(struct notcurses* nc); +int hud_destroy(struct ncplane* hud); + +// let the HUD know about an upcoming demo +int hud_schedule(const char* demoname); + +// demos should not call notcurses_render() themselves, but instead call +// demo_render(), which will ensure the HUD stays on the top of the z-stack. +int demo_render(struct notcurses* nc); + +// grab the hud with the mouse +int hud_grab(int y, int x); + +// release the hud +int hud_release(void); + +typedef struct demoresult { + char selector; + struct ncstats stats; + uint64_t timens; + bool failed; +} demoresult; + +// let the HUD know that a demo has completed, reporting the stats +int hud_completion_notify(int idx, const demoresult* result); + +// HUD retrieves results on demand from core +const demoresult* demoresult_lookup(int idx); +/*----------------------------------HUD----------------------------------*/ #ifdef __cplusplus } diff --git a/src/demo/eagle.c b/src/demo/eagle.c index 2060df18f..af7aa77f7 100644 --- a/src/demo/eagle.c +++ b/src/demo/eagle.c @@ -38,7 +38,7 @@ outzoomed_map(struct notcurses* nc, const char* map){ if(ncvisual_render(ncv, 0, 0, 0, 0)){ return NULL; } - if(notcurses_render(nc)){ + if(demo_render(nc)){ return NULL; } return ncv; @@ -100,7 +100,7 @@ zoom_map(struct notcurses* nc, const char* map){ ncplane_destroy(zncp); return NULL; } - if(notcurses_render(nc)){ + if(demo_render(nc)){ ncvisual_destroy(zncv); ncplane_destroy(zncp); return NULL; @@ -173,7 +173,7 @@ eagles(struct notcurses* nc){ int eaglesmoved; do{ eaglesmoved = 0; - notcurses_render(nc); + demo_render(nc); for(size_t i = 0 ; i < sizeof(e) / sizeof(*e) ; ++i){ if(e[i].xoff >= truex){ continue; diff --git a/src/demo/grid.c b/src/demo/grid.c index f81523c6e..405589bd8 100644 --- a/src/demo/grid.c +++ b/src/demo/grid.c @@ -174,7 +174,7 @@ gridswitch_demo(struct notcurses* nc, struct ncplane *n){ ncplane_putc(n, &lr); // render! - notcurses_render(nc); + demo_render(nc); release_cells(n, &ul, &uc, &ur, &cl, &cc, &cr, &ll, &lc, &lr); nanosleep(&demodelay, NULL); return ret; @@ -245,7 +245,7 @@ gridinv_demo(struct notcurses* nc, struct ncplane *n){ ncplane_putc(n, &lr); // render! - notcurses_render(nc); + demo_render(nc); release_cells(n, &ul, &uc, &ur, &cl, &cc, &cr, &ll, &lc, &lr); nanosleep(&demodelay, NULL); return gridswitch_demo(nc, n); @@ -317,7 +317,7 @@ int grid_demo(struct notcurses* nc){ ncplane_putc(n, &lr); // render! - notcurses_render(nc); + demo_render(nc); release_cells(n, &ul, &uc, &ur, &cl, &cc, &cr, &ll, &lc, &lr); nanosleep(&demodelay, NULL); return gridinv_demo(nc, n); diff --git a/src/demo/hud.c b/src/demo/hud.c new file mode 100644 index 000000000..722415610 --- /dev/null +++ b/src/demo/hud.c @@ -0,0 +1,105 @@ +#include "demo.h" + +// we provide a heads-up display throughout the demo, detailing the demos we're +// about to run, running, and just runned. the user can move this HUD with +// their mouse. it should always be on the top of the z-stack. +struct ncplane* hud = NULL; + +// while the HUD is grabbed by the mouse, these are set to the position where +// the grab started. they are reset once the HUD is released. +static int hud_grab_x = -1; +static int hud_grab_y = -1; +// position of the HUD *when grab started* +static int hud_pos_x; +static int hud_pos_y; + +static const int hud_rows = 5; +static const int hud_cols = 54; + +static int +hud_standard_bg(struct ncplane* n){ + cell c = CELL_SIMPLE_INITIALIZER(' '); + cell_set_bg_rgb(&c, 0, 0x20, 0); + ncplane_set_default(n, &c); + cell_release(n, &c); + return 0; +} + +static int +hud_grabbed_bg(struct ncplane* n){ + cell c = CELL_SIMPLE_INITIALIZER(' '); + cell_set_bg_rgb(&c, 0x40, 0x90, 0x40); + ncplane_set_default(n, &c); + cell_release(n, &c); + return 0; +} + +struct ncplane* hud_create(struct notcurses* nc){ + int dimx, dimy; + notcurses_term_dim_yx(nc, &dimy, &dimx); + //int xoffset = (dimx - hud_cols) / 2; + int xoffset = dimx - hud_cols; + //int yoffset = (dimy - hud_rows); + int yoffset = 0; + struct ncplane* n = notcurses_newplane(nc, hud_rows, hud_cols, yoffset, xoffset, NULL); + if(n == NULL){ + return NULL; + } + hud_standard_bg(n); + return (hud = n); +} + +int hud_destroy(struct ncplane* h){ + hud = NULL; + return ncplane_destroy(h); +} + +// mouse has been pressed on the hud. the caller is responsible for rerendering. +int hud_grab(int y, int x){ + int ret; + if(hud == NULL){ + return -1; + } + // are we in the middle of a grab? + if(hud_grab_x >= 0 && hud_grab_y >= 0){ + int delty = y - hud_grab_y; + int deltx = x - hud_grab_x; + ret = ncplane_move_yx(hud, hud_pos_y + delty, hud_pos_x + deltx); + }else{ + // new grab. stash point of original grab, and location of HUD at original + // grab. any delta while grabbed (relative to the original grab point) + // will see the HUD moved by delta (relative to the original HUD location). + hud_grab_x = x; + hud_grab_y = y; + ncplane_yx(hud, &hud_pos_y, &hud_pos_x); + ret = hud_grabbed_bg(hud); + } + return ret; +} + +int hud_release(void){ + if(hud == NULL){ + return -1; + } + hud_grab_x = -1; + hud_grab_y = -1; + return hud_standard_bg(hud); +} + +int hud_completion_notify(int idx, const demoresult* result){ + // FIXME + return 0; +} + +// inform the HUD of an upcoming demo +int hud_schedule(const char* demoname){ + // FIXME + return 0; +} + +int demo_render(struct notcurses* nc){ + if(hud){ + ncplane_move_top(hud); + } + return notcurses_render(nc); +} diff --git a/src/demo/input.c b/src/demo/input.c index a5cce84d9..53e757cfe 100644 --- a/src/demo/input.c +++ b/src/demo/input.c @@ -57,6 +57,23 @@ pass_along(const ncinput* ni){ return 0; } +static int +handle_mouse(struct notcurses* nc, const ncinput* ni){ + if(ni->id != NCKEY_BUTTON1 && ni->id != NCKEY_RELEASE){ + return 0; + } + int ret; + if(ni->id == NCKEY_RELEASE){ + ret = hud_release(); + }else{ + ret = hud_grab(ni->y, ni->x); + } + if(ret == 0){ + ret = demo_render(nc); + } + return ret; +} + static void * ultramegaok_demo(void* vnc){ ncinput ni; @@ -67,7 +84,7 @@ ultramegaok_demo(void* vnc){ continue; } if(nckey_mouse_p(ni.id)){ - // FIXME + handle_mouse(nc, &ni); }else{ if(ni.id == 'q'){ interrupt_demo(); diff --git a/src/demo/luigi.c b/src/demo/luigi.c index 33f2cb0d2..f9c85d674 100644 --- a/src/demo/luigi.c +++ b/src/demo/luigi.c @@ -191,7 +191,7 @@ int luigi_demo(struct notcurses* nc){ ncplane_move_top(lastseen); } ncplane_move_yx(lastseen, yoff, i); - notcurses_render(nc); + demo_render(nc); nanosleep(&stepdelay, NULL); } for(i = 0 ; i < 3 ; ++i){ diff --git a/src/demo/maxcolor.c b/src/demo/maxcolor.c index 6e6e496aa..c25406003 100644 --- a/src/demo/maxcolor.c +++ b/src/demo/maxcolor.c @@ -207,7 +207,7 @@ int maxcolor_demo(struct notcurses* nc){ ++x; } } - if(notcurses_render(nc)){ + if(demo_render(nc)){ return -1; } nanosleep(&demodelay, NULL); diff --git a/src/demo/outro.c b/src/demo/outro.c index fc83e59dc..8fc5ff066 100644 --- a/src/demo/outro.c +++ b/src/demo/outro.c @@ -10,7 +10,7 @@ static struct ncvisual* chncv; static int perframe(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused))){ static int three = 3; // move up one every three callbacks - notcurses_render(nc); + demo_render(nc); if(y < targy){ return 0; } @@ -127,7 +127,7 @@ outro_message(struct notcurses* nc, int* rows, int* cols){ return NULL; } ncplane_styles_off(non, CELL_STYLE_ITALIC); - if(notcurses_render(nc)){ + if(demo_render(nc)){ return NULL; } cell_release(non, &bgcell); diff --git a/src/demo/panelreel.c b/src/demo/panelreel.c index cfb553ea0..d4f6fe80d 100644 --- a/src/demo/panelreel.c +++ b/src/demo/panelreel.c @@ -218,7 +218,7 @@ handle_input(struct notcurses* nc, struct panelreel* pr, int efd, sigemptyset(&sset); wchar_t key = -1; int pret; - notcurses_render(nc); + demo_render(nc); do{ struct timespec pollspec, cur; clock_gettime(CLOCK_MONOTONIC, &cur); @@ -241,7 +241,7 @@ handle_input(struct notcurses* nc, struct panelreel* pr, int efd, if(read(efd, &val, sizeof(val)) != sizeof(val)){ fprintf(stderr, "Error reading from eventfd %d (%s)\n", efd, strerror(errno)); }else if(key < 0){ panelreel_redraw(pr); - notcurses_render(nc); + demo_render(nc); } } } @@ -381,7 +381,7 @@ int panelreel_demo(struct notcurses* nc){ return -1; } close(efd); - if(notcurses_render(nc)){ + if(demo_render(nc)){ return -1; } return 0; diff --git a/src/demo/sliding.c b/src/demo/sliding.c index 795463643..065aac210 100644 --- a/src/demo/sliding.c +++ b/src/demo/sliding.c @@ -32,7 +32,7 @@ move_square(struct notcurses* nc, struct ncplane* chunk, int* holey, int* holex, targy += deltay; targx += deltax; ncplane_move_yx(chunk, targy, targx); - if(notcurses_render(nc)){ + if(demo_render(nc)){ return -1; } nanosleep(&movetime, NULL); @@ -199,7 +199,7 @@ int sliding_puzzle_demo(struct notcurses* nc){ if(draw_bounding_box(n, wastey, wastex, chunky, chunkx)){ return -1; } - if(notcurses_render(nc)){ + if(demo_render(nc)){ goto done; } struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000000, }; @@ -230,7 +230,7 @@ int sliding_puzzle_demo(struct notcurses* nc){ chunks[i0] = chunks[i1]; ncplane_move_yx(chunks[i0], targy0, targx0); chunks[i1] = t; - if(notcurses_render(nc)){ + if(demo_render(nc)){ goto done; } } diff --git a/src/demo/unicodeblocks.c b/src/demo/unicodeblocks.c index 725d51c3e..68eb4e2b2 100644 --- a/src/demo/unicodeblocks.c +++ b/src/demo/unicodeblocks.c @@ -188,6 +188,9 @@ int unicodeblocks_demo(struct notcurses* nc){ if((nn = notcurses_newplane(nc, BLOCKSIZE / CHUNKSIZE + 2, (CHUNKSIZE * 2) + 2, 3, xstart, NULL)) == NULL){ return -1; } + if(hud){ + ncplane_move_below_unsafe(nn, hud); + } if(draw_block(nn, blockstart)){ return -1; } diff --git a/src/demo/view.c b/src/demo/view.c index 6063a9afb..8d38a642a 100644 --- a/src/demo/view.c +++ b/src/demo/view.c @@ -12,7 +12,7 @@ watch_for_keystroke(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((u return 1; } } - return notcurses_render(nc); + return demo_render(nc); } static int @@ -113,7 +113,7 @@ int view_demo(struct notcurses* nc){ ncplane_destroy(dsplane); return -1; } - notcurses_render(nc); + demo_render(nc); ncplane_move_bottom(dsplane); nanosleep(&demodelay, NULL); if(ncvisual_render(ncv, 0, 0, 0, 0)){ @@ -124,10 +124,10 @@ int view_demo(struct notcurses* nc){ } ncvisual_destroy(ncv); ncvisual_destroy(ncv2); - notcurses_render(nc); + demo_render(nc); nanosleep(&demodelay, NULL); ncplane_move_top(dsplane); - notcurses_render(nc); + demo_render(nc); ncplane_destroy(dsplane); nanosleep(&demodelay, NULL); struct ncplane* ncpl = legend(nc, dimy, dimx); diff --git a/src/demo/witherworm.c b/src/demo/witherworm.c index 8367609ed..da87d3f18 100644 --- a/src/demo/witherworm.c +++ b/src/demo/witherworm.c @@ -257,7 +257,7 @@ snake_thread(void* vnc){ return NULL; } } - if(notcurses_render(nc)){ + if(demo_render(nc)){ return NULL; } for(int s = 0 ; s < snakecount ; ++s){ @@ -653,7 +653,7 @@ int witherworm_demo(struct notcurses* nc){ bytes_out, egcs_out, cols_out)){ return -1; } - if(notcurses_render(nc)){ + if(demo_render(nc)){ return -1; } if(i){ diff --git a/src/demo/xray.c b/src/demo/xray.c index 17d4d24b1..361674e1a 100644 --- a/src/demo/xray.c +++ b/src/demo/xray.c @@ -84,7 +84,7 @@ perframecb(struct notcurses* nc, struct ncvisual* ncv __attribute__ ((unused))){ }while(xoff < dimx); } ++frameno; - notcurses_render(nc); + demo_render(nc); // FIXME we'll need some delay here return 0; } diff --git a/src/poc/rgbbg.c b/src/poc/rgbbg.c index 774568163..66e3316b0 100644 --- a/src/poc/rgbbg.c +++ b/src/poc/rgbbg.c @@ -22,7 +22,7 @@ int main(void){ r = 0; g = 0x80; b = 0; - ncplane_set_fg_rgb(n, 0x80, 0x80, 0x80); + ncplane_set_fg_rgb(n, 0x40, 0x20, 0x40); for(y = 0 ; y < dimy ; ++y){ for(x = 0 ; x < dimx ; ++x){ if(ncplane_set_bg_rgb(n, r, g, b)){