From a57f0f234c345108e5de1f94fe857094a47c611a Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 30 Jan 2020 22:16:03 -0500 Subject: [PATCH] selector styling --- include/notcurses.h | 8 ++++++++ src/lib/internal.h | 5 +++++ src/lib/selector.c | 37 +++++++++++++++++++++++++++++++------ src/poc/selector.c | 11 +++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/include/notcurses.h b/include/notcurses.h index c91331f06..9c0ccb7fd 100644 --- a/include/notcurses.h +++ b/include/notcurses.h @@ -2125,6 +2125,14 @@ typedef struct selector_options { unsigned itemcount; // number of initial items and descriptions // maximum number of options to display at once, 0 to use all available space unsigned maxdisplay; + // exhaustive styling options + uint64_t opchannels; // option channels + uint64_t descchannels; // description channels + uint64_t titlechannels;// title channels + uint64_t footchannels; // secondary and footer channels + uint64_t boxchannels; // border channels + uint64_t bgchannels; // base cell channels + const char* base_egc; // base EGC, NULL is interpreted as "" for convenience } selector_options; struct ncselector; diff --git a/src/lib/internal.h b/src/lib/internal.h index 5fab38bf4..0ac6bd723 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -135,6 +135,11 @@ typedef struct ncselector { char* title; // can be NULL, in which case there's no riser char* secondary; // can be NULL char* footer; // can be NULL + uint64_t opchannels; // option channels + uint64_t descchannels; // description channels + uint64_t titlechannels; // title channels + uint64_t footchannels; // secondary and footer channels + uint64_t boxchannels; // border channels } ncselector; typedef struct ncdirect { diff --git a/src/lib/selector.c b/src/lib/selector.c index e313f1c67..7ac62d9c1 100644 --- a/src/lib/selector.c +++ b/src/lib/selector.c @@ -35,8 +35,9 @@ ncselector_draw(ncselector* n){ size_t riserwidth = strlen(n->title) + 4; int offx = ncplane_align(n->ncp, NCALIGN_RIGHT, riserwidth); ncplane_cursor_move_yx(n->ncp, 0, offx); - ncplane_rounded_box_sized(n->ncp, 0, channels, 3, riserwidth, 0); + ncplane_rounded_box_sized(n->ncp, 0, n->boxchannels, 3, riserwidth, 0); ncplane_cursor_move_yx(n->ncp, 1, offx + 2); + n->ncp->channels = n->titlechannels; ncplane_putstr(n->ncp, n->title); // FIXME allow styling configuration yoff += 2; } @@ -45,7 +46,19 @@ ncselector_draw(ncselector* n){ ncplane_cursor_move_yx(n->ncp, yoff, xoff); int dimy, dimx; ncplane_dim_yx(n->ncp, &dimy, &dimx); - ncplane_rounded_box_sized(n->ncp, 0, channels, dimy - yoff, bodywidth, 0); + ncplane_rounded_box_sized(n->ncp, 0, n->boxchannels, dimy - yoff, bodywidth, 0); + if(n->secondary){ + // FIXME move it to the left a bit *iff* there's room to do so + int xloc = ncplane_align(n->ncp, NCALIGN_RIGHT, strlen(n->secondary) + 1); + n->ncp->channels = n->footchannels; + ncplane_putstr_yx(n->ncp, yoff, xloc, n->secondary); + } + if(n->footer){ + // FIXME move it to the left a bit *iff* there's room to do so + int xloc = ncplane_align(n->ncp, NCALIGN_RIGHT, strlen(n->footer) + 2); + n->ncp->channels = n->footchannels; + ncplane_putstr_yx(n->ncp, dimy - 1, xloc, n->footer); + } unsigned printidx = n->startdisp; int bodyoffset = dimx - bodywidth + 2; unsigned printed = 0; @@ -56,9 +69,11 @@ ncselector_draw(ncselector* n){ if(printidx == n->selected){ ncplane_styles_on(n->ncp, CELL_STYLE_REVERSE); } - ncplane_printf_yx(n->ncp, yoff, bodyoffset, "%*.*s %s", (int)n->longop, - (int)n->longop, n->items[printidx].option, - n->items[printidx].desc); + n->ncp->channels = n->opchannels; + ncplane_printf_yx(n->ncp, yoff, bodyoffset, "%*.*s", (int)n->longop, + (int)n->longop, n->items[printidx].option); + n->ncp->channels = n->descchannels; + ncplane_printf_yx(n->ncp, yoff, bodyoffset + n->longop, " %s", n->items[printidx].desc); if(printidx == n->selected){ ncplane_styles_off(n->ncp, CELL_STYLE_REVERSE); } @@ -113,6 +128,12 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const selector_options* ns->longop = 0; ns->maxdisplay = opts->maxdisplay; ns->longdesc = 0; + ns->opchannels = opts->opchannels; + ns->boxchannels = opts->boxchannels; + ns->descchannels = opts->descchannels; + ns->titlechannels = opts->titlechannels; + ns->footchannels = opts->footchannels; + ns->boxchannels = opts->boxchannels; if(opts->itemcount){ if(!(ns->items = malloc(sizeof(*ns->items) * opts->itemcount))){ free(ns->title); free(ns->secondary); free(ns->footer); @@ -145,6 +166,11 @@ ncselector* ncselector_create(ncplane* n, int y, int x, const selector_options* if(!(ns->ncp = ncplane_new(n->nc, dimy, dimx, y, x, NULL))){ goto freeitems; } + if(ncplane_set_base(ns->ncp, opts->bgchannels, 0, + opts->base_egc ? opts->base_egc : "")){ + ncplane_destroy(ns->ncp); + goto freeitems; + } ncselector_draw(ns); // deal with error here? return ns; @@ -205,7 +231,6 @@ char* ncselector_selected(const ncselector* n){ } void ncselector_previtem(ncselector* n, char** newitem){ -fprintf(stderr, "MAX: %u COUNT: %u SELECTED: %u START: %u\n", n->maxdisplay, n->itemcount, n->selected, n->startdisp); if(n->selected == n->startdisp && n->maxdisplay && n->maxdisplay < n->itemcount){ if(n->startdisp-- == 0){ n->startdisp = n->itemcount - 1; diff --git a/src/poc/selector.c b/src/poc/selector.c index a24f82242..88c504412 100644 --- a/src/poc/selector.c +++ b/src/poc/selector.c @@ -33,6 +33,17 @@ int main(void){ sopts.items = items; sopts.itemcount = sizeof(items) / sizeof(*items); sopts.title = "this is an awfully long example of a selector title"; + sopts.secondary = "pick one (you will die regardless)"; + sopts.footer = "press q to exit (there is no exit)"; + channels_set_fg(&sopts.boxchannels, 0x20e040); + channels_set_fg(&sopts.opchannels, 0xe08040); + channels_set_fg(&sopts.descchannels, 0x80e040); + channels_set_fg(&sopts.footchannels, 0xe00040); + channels_set_fg(&sopts.titlechannels, 0xffff80); + channels_set_fg(&sopts.bgchannels, 0x002000); + channels_set_bg(&sopts.bgchannels, 0x002000); + channels_set_fg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND); + channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND); ncplane_set_fg(notcurses_stdplane(nc), 0x40f040); ncplane_putstr_aligned(notcurses_stdplane(nc), 0, NCALIGN_RIGHT, "selector widget demo"); struct ncselector* ns = ncselector_create(notcurses_stdplane(nc), 3, 0, &sopts);