diff --git a/CMakeLists.txt b/CMakeLists.txt index a3363fcdf..8b03de22d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,26 @@ target_compile_definitions(notcurses-input FORTIFY_SOURCE=2 ) +file(GLOB PLANEREELSRCS CONFIGURE_DEPENDS src/planereel/*.cpp) +add_executable(notcurses-planereel ${PLANEREELSRCS}) +target_include_directories(notcurses-planereel + PRIVATE + include + "${PROJECT_BINARY_DIR}/include" +) +target_link_libraries(notcurses-planereel + PRIVATE + notcurses +) +target_compile_options(notcurses-planereel + PRIVATE + -Wall -Wextra -W -Wshadow +) +target_compile_definitions(notcurses-planereel + PRIVATE + FORTIFY_SOURCE=2 +) + file(GLOB VIEWSRCS CONFIGURE_DEPENDS src/view/*.cpp) add_executable(notcurses-view ${VIEWSRCS}) target_include_directories(notcurses-view @@ -192,7 +212,7 @@ install(FILES DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) -file(GLOB TESTDATA CONFIGURE_DEPENDS tests/*.png tests/*.jpg tests/*.mkv) +file(GLOB TESTDATA CONFIGURE_DEPENDS tests/*.png tests/*.jpg tests/*.mkv tests/*.bmp) install(FILES ${TESTDATA} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/notcurses @@ -212,6 +232,7 @@ install(FILES install(TARGETS notcurses-demo DESTINATION bin) install(TARGETS notcurses-view DESTINATION bin) install(TARGETS notcurses-input DESTINATION bin) +install(TARGETS notcurses-planereel DESTINATION bin) install(TARGETS notcurses LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/README.md b/README.md index 2f514cda5..b64754e6e 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,8 @@ Why use this non-standard library? `static inline` header-only code is used. This facilitates compiler optimizations, and reduces loader time. -* All APIs natively suport UTF-8. The `cell` API is based around Unicode's - [Extended Grapheme Cluster](https://unicode.org/reports/tr29/) concept. +* All APIs natively (and exclusively) support UTF-8. The `cell` API is based + around Unicode's [Extended Grapheme Cluster](https://unicode.org/reports/tr29/) concept. * Visual features including images, fonts, video, high-contrast text, sprites, and transparent regions. All APIs natively support 24-bit color, quantized @@ -1389,6 +1389,145 @@ UI discontinuity when the tablets grow to fill the entire screen (or shrink to not fill it). If it is not desired, however, scrolling of focus can be configured instead. +```c +// A panelreel is an notcurses region devoted to displaying zero or more +// line-oriented, contained panels between which the user may navigate. If at +// least one panel exists, there is an active panel. As much of the active +// panel as is possible is always displayed. If there is space left over, other +// panels are included in the display. Panels can come and go at any time, and +// can grow or shrink at any time. +// +// This structure is amenable to line- and page-based navigation via keystrokes, +// scrolling gestures, trackballs, scrollwheels, touchpads, and verbal commands. + +typedef struct panelreel_options { + // require this many rows and columns (including borders). otherwise, a + // message will be displayed stating that a larger terminal is necessary, and + // input will be queued. if 0, no minimum will be enforced. may not be + // negative. note that panelreel_create() does not return error if given a + // WINDOW smaller than these minima; it instead patiently waits for the + // screen to get bigger. + int min_supported_cols; + int min_supported_rows; + + // use no more than this many rows and columns (including borders). may not be + // less than the corresponding minimum. 0 means no maximum. + int max_supported_cols; + int max_supported_rows; + + // desired offsets within the surrounding WINDOW (top right bottom left) upon + // creation / resize. a panelreel_move() operation updates these. + int toff, roff, boff, loff; + // is scrolling infinite (can one move down or up forever, or is an end + // reached?). if true, 'circular' specifies how to handle the special case of + // an incompletely-filled reel. + bool infinitescroll; + // is navigation circular (does moving down from the last panel move to the + // first, and vice versa)? only meaningful when infinitescroll is true. if + // infinitescroll is false, this must be false. + bool circular; + // notcurses can draw a border around the panelreel, and also around the + // component tablets. inhibit borders by setting all valid bits in the masks. + // partially inhibit borders by setting individual bits in the masks. the + // appropriate attr and pair values will be used to style the borders. + // focused and non-focused tablets can have different styles. you can instead + // draw your own borders, or forgo borders entirely. + unsigned bordermask; // bitfield; 1s will not be drawn (see bordermaskbits) + uint64_t borderchan; // attributes used for panelreel border + unsigned tabletmask; // bitfield; same as bordermask but for tablet borders + uint64_t tabletchan; // tablet border styling channel + uint64_t focusedchan;// focused tablet border styling channel + uint64_t bgchannel; // background colors +} panelreel_options; + +struct tablet; +struct panelreel; + +// Create a panelreel according to the provided specifications. Returns NULL on +// failure. w must be a valid WINDOW*, to which offsets are relative. Note that +// there might not be enough room for the specified offsets, in which case the +// panelreel will be clipped on the bottom and right. A minimum number of rows +// and columns can be enforced via popts. efd, if non-negative, is an eventfd +// that ought be written to whenever panelreel_touch() updates a tablet (this +// is useful in the case of nonblocking input). +struct panelreel* panelreel_create(struct ncplane* nc, + const panelreel_options* popts, int efd); + +// Returns the ncplane on which this panelreel lives. +struct ncplane* panelreel_plane(struct panelreel* pr); + +// Tablet draw callback, provided a tablet (from which the ncplane and userptr +// may be extracted), the first column that may be used, the first row that may +// be used, the first column that may not be used, the first row that may not +// be used, and a bool indicating whether output ought be clipped at the top +// (true) or bottom (false). Rows and columns are zero-indexed, and both are +// relative to the tablet's plane. +// +// Regarding clipping: it is possible that the tablet is only partially +// displayed on the screen. If so, it is either partially present on the top of +// the screen, or partially present at the bottom. In the former case, the top +// is clipped (cliptop will be true), and output ought start from the end. In +// the latter case, cliptop is false, and output ought start from the beginning. +// +// Returns the number of lines of output, which ought be less than or equal to +// maxy - begy, and non-negative (negative values might be used in the future). +typedef int (*tabletcb)(struct tablet* t, int begx, int begy, int maxx, + int maxy, bool cliptop); + +// Add a new tablet to the provided panelreel, having the callback object +// opaque. Neither, either, or both of after and before may be specified. If +// neither is specified, the new tablet can be added anywhere on the reel. If +// one or the other is specified, the tablet will be added before or after the +// specified tablet. If both are specifid, the tablet will be added to the +// resulting location, assuming it is valid (after->next == before->prev); if +// it is not valid, or there is any other error, NULL will be returned. +struct tablet* panelreel_add(struct panelreel* pr, struct tablet* after, + struct tablet *before, tabletcb cb, void* opaque); + +// Return the number of tablets. +int panelreel_tabletcount(const struct panelreel* pr); + +// Indicate that the specified tablet has been updated in a way that would +// change its display. This will trigger some non-negative number of callbacks +// (though not in the caller's context). +int panelreel_touch(struct panelreel* pr, struct tablet* t); + +// Delete the tablet specified by t from the panelreel specified by pr. Returns +// -1 if the tablet cannot be found. +int panelreel_del(struct panelreel* pr, struct tablet* t); + +// Delete the active tablet. Returns -1 if there are no tablets. +int panelreel_del_focused(struct panelreel* pr); + +// Move to the specified location within the containing WINDOW. +int panelreel_move(struct panelreel* pr, int x, int y); + +// Redraw the panelreel in its entirety, for instance after +// clearing the screen due to external corruption, or a SIGWINCH. +int panelreel_redraw(struct panelreel* pr); + +// Return the focused tablet, if any tablets are present. This is not a copy; +// be careful to use it only for the duration of a critical section. +struct tablet* panelreel_focused(struct panelreel* pr); + +// Change focus to the next tablet, if one exists +struct tablet* panelreel_next(struct panelreel* pr); + +// Change focus to the previous tablet, if one exists +struct tablet* panelreel_prev(struct panelreel* pr); + +// Destroy a panelreel allocated with panelreel_create(). Does not destroy the +// underlying WINDOW. Returns non-zero on failure. +int panelreel_destroy(struct panelreel* pr); + +void* tablet_userptr(struct tablet* t); +const void* tablet_userptr_const(const struct tablet* t); + +// Access the ncplane associated with this tablet, if one exists. +struct ncplane* tablet_ncplane(struct tablet* t); +const struct ncplane* tablet_ncplane_const(const struct tablet* t); +``` + #### Panelreel examples Let's say we have a screen of 11 lines, and 3 tablets of one line each. Both @@ -1861,6 +2000,7 @@ Four binaries are built as part of notcurses: * `notcurses-demo`: some demonstration code * `notcurses-view`: renders visual media (images/videos) * `notcurses-input`: decode and print keypresses +* `notcurses-planereels`: play around with panelreels * `notcurses-tester`: unit testing ## Differences from NCURSES diff --git a/include/notcurses.h b/include/notcurses.h index 93f6c8cb3..f4477b233 100644 --- a/include/notcurses.h +++ b/include/notcurses.h @@ -1441,18 +1441,17 @@ typedef struct panelreel_options { // first, and vice versa)? only meaningful when infinitescroll is true. if // infinitescroll is false, this must be false. bool circular; - // outcurses can draw a border around the panelreel, and also around the + // notcurses can draw a border around the panelreel, and also around the // component tablets. inhibit borders by setting all valid bits in the masks. // partially inhibit borders by setting individual bits in the masks. the // appropriate attr and pair values will be used to style the borders. // focused and non-focused tablets can have different styles. you can instead // draw your own borders, or forgo borders entirely. unsigned bordermask; // bitfield; 1s will not be drawn (see bordermaskbits) - cell borderattr; // attributes used for panelreel border + uint64_t borderchan; // attributes used for panelreel border unsigned tabletmask; // bitfield; same as bordermask but for tablet borders - // FIXME should be attrword + channels, as we don't use gcluster here - cell tabletattr; // attributes used for tablet borders - cell focusedattr; // attributes used for focused tablet borders, no color! + uint64_t tabletchan; // tablet border styling channel + uint64_t focusedchan;// focused tablet border styling channel uint64_t bgchannel; // background colors } panelreel_options; @@ -1473,11 +1472,12 @@ API struct panelreel* panelreel_create(struct ncplane* nc, // Returns the ncplane on which this panelreel lives. API struct ncplane* panelreel_plane(struct panelreel* pr); -// Tablet draw callback, provided a ncplane the first column that may be used, -// the first row that may be used, the first column that may not be used, the -// first row that may not be used, and a bool indicating whether output ought -// be clipped at the top (true) or bottom (false). Rows and columns are -// zero-indexed, and both are relative to the panel. +// Tablet draw callback, provided a tablet (from which the ncplane and userptr +// may be extracted), the first column that may be used, the first row that may +// be used, the first column that may not be used, the first row that may not +// be used, and a bool indicating whether output ought be clipped at the top +// (true) or bottom (false). Rows and columns are zero-indexed, and both are +// relative to the tablet's plane. // // Regarding clipping: it is possible that the tablet is only partially // displayed on the screen. If so, it is either partially present on the top of @@ -1487,8 +1487,8 @@ API struct ncplane* panelreel_plane(struct panelreel* pr); // // Returns the number of lines of output, which ought be less than or equal to // maxy - begy, and non-negative (negative values might be used in the future). -typedef int (*tabletcb)(struct ncplane* p, int begx, int begy, int maxx, - int maxy, bool cliptop, void* curry); +typedef int (*tabletcb)(struct tablet* t, int begx, int begy, int maxx, + int maxy, bool cliptop); // Add a new tablet to the provided panelreel, having the callback object // opaque. Neither, either, or both of after and before may be specified. If @@ -1540,6 +1540,10 @@ API int panelreel_destroy(struct panelreel* pr); API void* tablet_userptr(struct tablet* t); API const void* tablet_userptr_const(const struct tablet* t); +// Access the ncplane associated with this tablet, if one exists. +API struct ncplane* tablet_ncplane(struct tablet* t); +API const struct ncplane* tablet_ncplane_const(const struct tablet* t); + #define PREFIXSTRLEN 7 // Does not include a '\0' (xxx.xxU) #define IPREFIXSTRLEN 8 // Does not include a '\0' (xxxx.xxU) #define BPREFIXSTRLEN 9 // Does not include a '\0' (xxxx.xxUi), i == prefix diff --git a/src/demo/demo.c b/src/demo/demo.c index fdd0b7409..c8001c201 100644 --- a/src/demo/demo.c +++ b/src/demo/demo.c @@ -14,7 +14,7 @@ static const char DEFAULT_DEMO[] = "iemlubgswvpo"; static char datadir[PATH_MAX] = "/usr/share/notcurses"; // FIXME char* find_data(const char* datum){ - char* path = malloc(strlen(datadir) + 1 + strlen(datum)); + char* path = malloc(strlen(datadir) + 1 + strlen(datum) + 1); strcpy(path, datadir); strcat(path, "/"); strcat(path, datum); diff --git a/src/demo/outro.c b/src/demo/outro.c index f6cc5aec8..2a7a90085 100644 --- a/src/demo/outro.c +++ b/src/demo/outro.c @@ -91,7 +91,9 @@ int outro(struct notcurses* nc){ ncplane_erase(ncp); ncplane_dim_yx(ncp, &rows, &cols); int averr = 0; - struct ncvisual* ncv = ncplane_visual_open(ncp, "../tests/changes.jpg", &averr); + char* path = find_data("changes.jpg"); + struct ncvisual* ncv = ncplane_visual_open(ncp, path, &averr); + free(path); if(ncv == NULL){ return -1; } diff --git a/src/demo/panelreel.c b/src/demo/panelreel.c index 855d4b4d8..46a3c75e4 100644 --- a/src/demo/panelreel.c +++ b/src/demo/panelreel.c @@ -118,10 +118,10 @@ tabletdown(struct ncplane* w, int begx, int begy, int maxx, int maxy, } static int -tabletdraw(struct ncplane* p, int begx, int begy, int maxx, int maxy, - bool cliptop, void* vtabletctx){ +tabletdraw(struct tablet* t, int begx, int begy, int maxx, int maxy, bool cliptop){ int err = 0; - tabletctx* tctx = vtabletctx; + struct ncplane* p = tablet_ncplane(t); + tabletctx* tctx = tablet_userptr(t); pthread_mutex_lock(&tctx->lock); unsigned rgb = tctx->rgb; int ll; @@ -258,20 +258,20 @@ panelreel_demo_core(struct notcurses* nc, int efd, tabletctx** tctxs){ .min_supported_rows = 5, .bordermask = NCBOXMASK_BOTTOM | NCBOXMASK_TOP | NCBOXMASK_LEFT | NCBOXMASK_RIGHT, - .borderattr = CELL_TRIVIAL_INITIALIZER, - .tabletattr = CELL_TRIVIAL_INITIALIZER, - .focusedattr = CELL_TRIVIAL_INITIALIZER, + .borderchan = 0, + .tabletchan = 0, + .focusedchan = 0, .toff = y, .loff = x, .roff = x, .boff = y, .bgchannel = 0, }; - cell_set_fg_rgb(&popts.focusedattr, 58, 150, 221); - cell_set_bg_rgb(&popts.focusedattr, 97, 214, 214); - cell_set_fg_rgb(&popts.tabletattr, 19, 161, 14); - cell_set_fg_rgb(&popts.borderattr, 136, 23, 152); - cell_set_bg_rgb(&popts.borderattr, 0, 0, 0); + channels_set_fg_rgb(&popts.focusedchan, 58, 150, 221); + channels_set_bg_rgb(&popts.focusedchan, 97, 214, 214); + channels_set_fg_rgb(&popts.tabletchan, 19, 161, 14); + channels_set_fg_rgb(&popts.borderchan, 136, 23, 152); + channels_set_bg_rgb(&popts.borderchan, 0, 0, 0); if(channels_set_bg_alpha(&popts.bgchannel, CELL_ALPHA_TRANS)){ return NULL; } diff --git a/src/demo/sliding.c b/src/demo/sliding.c index bb8d43555..04997f18d 100644 --- a/src/demo/sliding.c +++ b/src/demo/sliding.c @@ -165,7 +165,9 @@ int sliding_puzzle_demo(struct notcurses* nc){ struct ncplane* n = notcurses_stdplane(nc); ncplane_erase(n); int averr = 0; - struct ncvisual* ncv = ncplane_visual_open(n, "../tests/changes.jpg", &averr); + char* path = find_data("changes.jpg"); + struct ncvisual* ncv = ncplane_visual_open(n, path, &averr); + free(path); if(ncv == NULL){ return -1; } diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 0bec5d4b4..8736d56f8 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -715,6 +715,8 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){ free(ret); return NULL; } + ret->stats.fbbytes = 0; + ret->stashstats.fbbytes = 0; reset_stats(&ret->stats); reset_stats(&ret->stashstats); ret->ttyfp = outfp; diff --git a/src/lib/panelreel.c b/src/lib/panelreel.c index 4aa5595c9..a9fc132d9 100644 --- a/src/lib/panelreel.c +++ b/src/lib/panelreel.c @@ -60,7 +60,7 @@ int wresize(ncplane* n, int leny, int lenx){ // bchrs: 6-element array of wide border characters + attributes FIXME static int -draw_borders(ncplane* w, unsigned mask, const cell* attr, +draw_borders(ncplane* w, unsigned mask, uint64_t channel, bool cliphead, bool clipfoot){ int begx, begy, lenx, leny; int ret = 0; @@ -72,7 +72,7 @@ draw_borders(ncplane* w, unsigned mask, const cell* attr, cell ul, ur, ll, lr, hl, vl; cell_init(&ul); cell_init(&ur); cell_init(&hl); cell_init(&ll); cell_init(&lr); cell_init(&vl); - if(cells_rounded_box(w, attr->attrword, attr->channels, &ul, &ur, &ll, &lr, &hl, &vl)){ + if(cells_rounded_box(w, 0, channel, &ul, &ur, &ll, &lr, &hl, &vl)){ return -1; } /*fprintf(stderr, "drawing borders %p %d/%d->%d/%d, mask: %04x, clipping: %c%c\n", @@ -153,7 +153,7 @@ draw_panelreel_borders(const panelreel* pr){ if(begy >= maxy || maxy - begy + 1 < pr->popts.min_supported_cols){ return 0; // no room } - return draw_borders(pr->p, pr->popts.bordermask, &pr->popts.borderattr, false, false); + return draw_borders(pr->p, pr->popts.bordermask, pr->popts.borderchan, false, false); } // Calculate the starting and ending coordinates available for occupation by @@ -167,12 +167,12 @@ tablet_columns(const panelreel* pr, int* begx, int* begy, int* lenx, int* leny, window_coordinates(pr->p, begy, begx, leny, lenx); int maxy = *leny + *begy - 1; int begindraw = *begy + !(pr->popts.bordermask & NCBOXMASK_TOP); - // FIXME i think this fails to account for an absent panelreel bottom? int enddraw = maxy - !(pr->popts.bordermask & NCBOXMASK_TOP); - if(direction){ + if(direction <= 0){ if(frontiery < begindraw){ return -1; } + }else{ if(frontiery > enddraw){ // fprintf(stderr, "FRONTIER: %d ENDDRAW: %d\n", frontiery, enddraw); return -1; @@ -222,7 +222,7 @@ panelreel_draw_tablet(const panelreel* pr, tablet* t, int frontiery, int lenx, leny, begy, begx; ncplane* fp = t->p; if(tablet_columns(pr, &begx, &begy, &lenx, &leny, frontiery, direction)){ -//fprintf(stderr, "no room: %p:%p base %d/%d len %d/%d\n", t, fp, begx, begy, lenx, leny); +//fprintf(stderr, "no room: %p:%p base %d/%d len %d/%d dir %d\n", t, fp, begy, begx, leny, lenx, direction); //fprintf(stderr, "FRONTIER DONE!!!!!!\n"); if(fp){ //fprintf(stderr, "HIDING %p at frontier %d (dir %d) with %d\n", t, frontiery, direction, leny); @@ -280,7 +280,7 @@ panelreel_draw_tablet(const panelreel* pr, tablet* t, int frontiery, bool cbdir = direction < 0 ? true : false; // fprintf(stderr, "calling! lenx/leny: %d/%d cbx/cby: %d/%d cbmaxx/cbmaxy: %d/%d dir: %d\n", // lenx, leny, cbx, cby, cbmaxx, cbmaxy, direction); - int ll = t->cbfxn(fp, cbx, cby, cbmaxx, cbmaxy, cbdir, t->curry); + int ll = t->cbfxn(t, cbx, cby, cbmaxx, cbmaxy, cbdir); //fprintf(stderr, "RETURNRETURNRETURN %p %d (%d, %d, %d) DIR %d\n", // t, ll, cby, cbmaxy, leny, direction); if(ll != leny){ @@ -324,7 +324,7 @@ panelreel_draw_tablet(const panelreel* pr, tablet* t, int frontiery, } } draw_borders(fp, pr->popts.tabletmask, - direction == 0 ? &pr->popts.focusedattr : &pr->popts.tabletattr, + direction == 0 ? pr->popts.focusedchan : pr->popts.tabletchan, cliphead, clipfoot); return cliphead || clipfoot; } @@ -377,17 +377,22 @@ draw_following_tablets(const panelreel* pr, const tablet* otherend){ tablet* working = pr->tablets; int frontiery; // move down past the focused tablet, filling up the reel to the bottom - while(working->next != otherend || otherend->p == NULL){ + do{ +//fprintf(stderr, "following otherend: %p ->p: %p\n", otherend, otherend->p); + // modify frontier based off the one we're at window_coordinates(working->p, &wbegy, &wbegx, &wleny, &wlenx); wmaxy = wbegy + wleny - 1; frontiery = wmaxy + 2; -//fprintf(stderr, "EASTBOUND AND DOWN: %d %d\n", frontiery, wmaxy + 2); +//fprintf(stderr, "EASTBOUND AND DOWN: %p->%p %d %d\n", working, working->next, frontiery, wmaxy + 2); working = working->next; - panelreel_draw_tablet(pr, working, frontiery, 1); - if(working->p == NULL){ // FIXME might be more to hide + if(working == otherend && otherend->p){ break; } - } + panelreel_draw_tablet(pr, working, frontiery, 1); + if(working == otherend){ + otherend = otherend->next; + } + }while(working->p); // FIXME might be more to hide // FIXME keep going forward, hiding those no longer visible return working; } @@ -396,13 +401,15 @@ draw_following_tablets(const panelreel* pr, const tablet* otherend){ // returns the last tablet drawn. static tablet* draw_previous_tablets(const panelreel* pr, const tablet* otherend){ +//fprintf(stderr, "preceding otherend: %p ->p: %p\n", otherend, otherend->p); int wbegy, wbegx, wlenx, wleny; // working tablet window coordinates tablet* upworking = pr->tablets; int frontiery; + // modify frontier based off the one we're at + window_coordinates(upworking->p, &wbegy, &wbegx, &wleny, &wlenx); + frontiery = wbegy - 2; while(upworking->prev != otherend || otherend->p == NULL){ - window_coordinates(upworking->p, &wbegy, &wbegx, &wleny, &wlenx); - frontiery = wbegy - 2; -//fprintf(stderr, "MOVIN' ON UP: %d %d\n", frontiery, wbegy - 2); +//fprintf(stderr, "MOVIN' ON UP: %p->%p %d %d\n", upworking, upworking->prev, frontiery, wbegy - 2); upworking = upworking->prev; panelreel_draw_tablet(pr, upworking, frontiery, -1); if(upworking->p){ @@ -559,6 +566,14 @@ validate_panelreel_opts(ncplane* w, const panelreel_options* popts){ return true; } +ncplane* tablet_ncplane(tablet* t){ + return t->p; +} + +const ncplane* tablet_ncplane_const(const tablet* t){ + return t->p; +} + ncplane* panelreel_plane(panelreel* pr){ return pr->p; } diff --git a/src/planereel/main.cpp b/src/planereel/main.cpp new file mode 100644 index 000000000..16012790d --- /dev/null +++ b/src/planereel/main.cpp @@ -0,0 +1,75 @@ +#include +#include +#include + +// FIXME ought be able to get pr from tablet, methinks? +static struct panelreel* PR; + +int tabletfxn(struct tablet* t, int begx, int begy, int maxx, int maxy, + bool cliptop){ + struct ncplane* p = tablet_ncplane(t); + cell c = CELL_SIMPLE_INITIALIZER(' '); + cell_set_bg(&c, (((uintptr_t)t) % 0x1000000) + cliptop + begx + maxx); + ncplane_set_default(p, &c); + cell_release(p, &c); + return 3 > maxy - begy ? maxy - begy : 3; +} + +int main(void){ + if(setlocale(LC_ALL, "") == nullptr){ + return EXIT_FAILURE; + } + struct notcurses_options opts{}; + struct notcurses* nc = notcurses_init(&opts, stdout); + if(!nc){ + return EXIT_FAILURE; + } + struct ncplane* nstd = notcurses_stdplane(nc); + int dimy, dimx; + ncplane_dim_yx(nstd, &dimy, &dimx); + struct ncplane* n = notcurses_newplane(nc, dimy - 1, dimx, 1, 0, nullptr); + if(!n){ + notcurses_stop(nc); + return EXIT_FAILURE; + } + if(ncplane_set_fg(nstd, 0xb11bb1)){ + notcurses_stop(nc); + return EXIT_FAILURE; + } + if(ncplane_putstr_aligned(nstd, 0, "(a)dd (q)uit", NCALIGN_CENTER) <= 0){ + notcurses_stop(nc); + return EXIT_FAILURE; + } + struct panelreel_options popts{}; + channels_set_fg(&popts.focusedchan, 0xffffff); + channels_set_bg(&popts.focusedchan, 0x00c080); + struct panelreel* pr = panelreel_create(n, &popts, -1); + if(!pr || notcurses_render(nc)){ + notcurses_stop(nc); + return EXIT_FAILURE; + } + PR = pr; // FIXME eliminate + char32_t key; + while((key = notcurses_getc_blocking(nc)) != (char32_t)-1){ + switch(key){ + case 'q': + return notcurses_stop(nc) ? EXIT_FAILURE : EXIT_SUCCESS; + case 'a': + panelreel_add(pr, nullptr, nullptr, tabletfxn, nullptr); + break; + case NCKEY_UP: + panelreel_prev(pr); + break; + case NCKEY_DOWN: + panelreel_next(pr); + break; + default: + break; + } + if(notcurses_render(nc)){ + break; + } + } + notcurses_stop(nc); + return EXIT_FAILURE; +} diff --git a/tests/cell.cpp b/tests/cell.cpp index 5123041ce..79016255b 100644 --- a/tests/cell.cpp +++ b/tests/cell.cpp @@ -11,6 +11,7 @@ class CellTest : public :: testing::Test { } notcurses_options nopts{}; nopts.inhibit_alternate_screen = true; + nopts.suppress_bannner = true; outfp_ = fopen("/dev/tty", "wb"); ASSERT_NE(nullptr, outfp_); nc_ = notcurses_init(&nopts, outfp_); diff --git a/tests/libav.cpp b/tests/libav.cpp index b8285ba5d..c5aa8eec5 100644 --- a/tests/libav.cpp +++ b/tests/libav.cpp @@ -10,6 +10,7 @@ class LibavTest : public :: testing::Test { } notcurses_options nopts{}; nopts.inhibit_alternate_screen = true; + nopts.suppress_bannner = true; outfp_ = fopen("/dev/tty", "wb"); ASSERT_NE(nullptr, outfp_); nc_ = notcurses_init(&nopts, outfp_); diff --git a/tests/ncplane.cpp b/tests/ncplane.cpp index ee954b73b..997e82385 100644 --- a/tests/ncplane.cpp +++ b/tests/ncplane.cpp @@ -11,6 +11,7 @@ class NcplaneTest : public :: testing::Test { } notcurses_options nopts{}; nopts.inhibit_alternate_screen = true; + nopts.suppress_bannner = true; outfp_ = fopen("/dev/tty", "wb"); ASSERT_NE(nullptr, outfp_); nc_ = notcurses_init(&nopts, outfp_); diff --git a/tests/notcurses.cpp b/tests/notcurses.cpp index 33947de12..35942e088 100644 --- a/tests/notcurses.cpp +++ b/tests/notcurses.cpp @@ -13,6 +13,7 @@ class NotcursesTest : public :: testing::Test { } notcurses_options nopts{}; nopts.inhibit_alternate_screen = true; + nopts.suppress_bannner = true; outfp_ = fopen("/dev/tty", "wb"); ASSERT_NE(nullptr, outfp_); nc_ = notcurses_init(&nopts, outfp_); diff --git a/tests/panelreel.cpp b/tests/panelreel.cpp index dc0802627..c59f6bf3c 100644 --- a/tests/panelreel.cpp +++ b/tests/panelreel.cpp @@ -10,6 +10,7 @@ class PanelReelTest : public :: testing::Test { } notcurses_options nopts{}; nopts.inhibit_alternate_screen = true; + nopts.suppress_bannner = true; outfp_ = fopen("/dev/tty", "wb"); ASSERT_NE(nullptr, outfp_); nc_ = notcurses_init(&nopts, outfp_); @@ -78,12 +79,11 @@ TEST_F(PanelReelTest, MovementWithoutTablets) { // EXPECT_EQ(0, panelreel_validate(n_, pr)); } -int panelcb(struct ncplane* p, int begx, int begy, int maxx, int maxy, - bool cliptop, void* curry){ - EXPECT_NE(nullptr, p); +int panelcb(struct tablet* t, int begx, int begy, int maxx, int maxy, bool cliptop){ + EXPECT_NE(nullptr, tablet_ncplane(t)); EXPECT_LT(begx, maxx); EXPECT_LT(begy, maxy); - EXPECT_EQ(nullptr, curry); + EXPECT_EQ(nullptr, tablet_userptr(t)); EXPECT_FALSE(cliptop); // FIXME verify geometry is as expected return 0; diff --git a/tests/zaxis.cpp b/tests/zaxis.cpp index 1e3bd6eb6..25bd4fb2e 100644 --- a/tests/zaxis.cpp +++ b/tests/zaxis.cpp @@ -11,6 +11,7 @@ class ZAxisTest : public :: testing::Test { } notcurses_options nopts{}; nopts.inhibit_alternate_screen = true; + nopts.suppress_bannner = true; outfp_ = fopen("/dev/tty", "wb"); ASSERT_NE(nullptr, outfp_); nc_ = notcurses_init(&nopts, outfp_);