70 if(
n->footercols + 2 > cols){
71 cols =
n->footercols + 2;
73 if(
n->secondarycols + 2 > cols){
74 cols =
n->secondarycols + 2;
76 if(
n->longop +
n->longdesc + 5 > cols){
77 cols =
n->longop +
n->longdesc + 5;
94 size_t riserwidth =
n->titlecols + 4;
98 ncplane_hline(
n->ncp, &transchar, offx);
101 ncplane_rounded_box_sized(
n->ncp, 0,
n->boxchannels, 3, riserwidth, 0);
102 n->ncp->channels =
n->titlechannels;
103 ncplane_printf_yx(
n->ncp, 1, offx + 1,
" %s ",
n->title);
107 ncplane_hline(
n->ncp, &transchar, offx);
110 unsigned bodywidth = ncselector_body_width(
n);
115 for(
unsigned y = yoff + 1 ;
y < dimy ; ++
y){
117 ncplane_hline(
n->ncp, &transchar, xoff);
121 ncplane_rounded_box_sized(
n->ncp, 0,
n->boxchannels, dimy - yoff, bodywidth, 0);
123 n->ncp->channels =
n->boxchannels;
127 ncplane_putchar_yx(
n->ncp, 2, dimx - 1,
'|');
129 if(bodywidth < dimx){
133 ncplane_putchar_yx(
n->ncp, 2, dimx - bodywidth,
'-');
136 if((
n->titlecols + 4 != dimx) &&
n->titlecols >
n->secondarycols){
140 ncplane_putchar_yx(
n->ncp, 2, dimx - (
n->titlecols + 4),
'-');
147 int xloc = bodywidth - (
n->secondarycols + 1) + xoff;
148 if(
n->secondarycols < bodywidth - 2){
151 n->ncp->channels =
n->footchannels;
152 ncplane_putstr_yx(
n->ncp, yoff, xloc,
n->secondary);
155 int xloc = bodywidth - (
n->footercols + 1) + xoff;
156 if(
n->footercols < bodywidth - 2){
159 n->ncp->channels =
n->footchannels;
160 ncplane_putstr_yx(
n->ncp, dimy - 1, xloc,
n->footer);
165 for(
unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
167 ncplane_putc(
n->ncp, &transc);
169 const int bodyoffset = dimx - bodywidth + 2;
170 if(
n->maxdisplay &&
n->maxdisplay <
n->itemcount){
171 n->ncp->channels =
n->descchannels;
172 n->arrowx = bodyoffset +
n->longop;
176 ncplane_putchar_yx(
n->ncp, yoff,
n->arrowx,
'<');
182 unsigned printidx =
n->startdisp;
183 unsigned printed = 0;
184 for(yoff += 1 ; yoff < (int)dimy - 2 ; ++yoff){
185 if(
n->maxdisplay && printed ==
n->maxdisplay){
189 for(
int i = xoff + 1 ; i < (int)dimx - 1 ; ++i){
191 ncplane_putc(
n->ncp, &transc);
193 n->ncp->channels =
n->opchannels;
194 if(printidx ==
n->selected){
195 n->ncp->channels = (uint64_t)ncchannels_bchannel(
n->opchannels) << 32u | ncchannels_fchannel(
n->opchannels);
197 ncplane_printf_yx(
n->ncp, yoff, bodyoffset + (
n->longop -
n->items[printidx].opcolumns),
"%s",
n->items[printidx].option);
198 n->ncp->channels =
n->descchannels;
199 if(printidx ==
n->selected){
200 n->ncp->channels = (uint64_t)ncchannels_bchannel(
n->descchannels) << 32u | ncchannels_fchannel(
n->descchannels);
202 ncplane_printf_yx(
n->ncp, yoff, bodyoffset +
n->longop,
" %s",
n->items[printidx].desc);
203 if(++printidx ==
n->itemcount){
210 for(
int i = xoff + 1 ; i < (int)dimx - 1 ; ++i){
212 ncplane_putc(
n->ncp, &transc);
214 if(
n->maxdisplay &&
n->maxdisplay <
n->itemcount){
215 n->ncp->channels =
n->descchannels;
219 ncplane_putchar_yx(
n->ncp, yoff,
n->arrowx,
'>');
228ncselector_dim_yx(
const ncselector*
n,
unsigned* ncdimy,
unsigned* ncdimx){
229 unsigned rows = 0, cols = 0;
239 rows += (!
n->maxdisplay ||
n->maxdisplay >
n->itemcount ?
n->itemcount :
n->maxdisplay) - 1;
244 cols = ncselector_body_width(
n);
246 if(
n->titlecols + 4 > cols){
247 cols =
n->titlecols + 4;
255 while(
n->itemcount--){
256 free(
n->items[
n->itemcount].option);
257 free(
n->items[
n->itemcount].desc);
259 if(ncplane_set_widget(
n->ncp,
NULL,
NULL) == 0){
273 *item =
n->items[
n->selected].option;
274 n->items[
n->selected].option =
NULL;
276 ncselector_destroy_internal(
n);
282 logerror(
"won't use the standard plane");
289 unsigned itemcount = 0;
302 memset(ns, 0,
sizeof(*ns));
303 if(
opts->defidx &&
opts->defidx >= itemcount){
304 logerror(
"default index %u too large (%u items)",
opts->defidx, itemcount);
333 if(!(ns->
items = malloc(
sizeof(*ns->
items) * itemcount))){
345 unsigned cols = unsafe;
370 ncselector_dim_yx(ns, &dimy, &dimx);
371 if(ncplane_resize_simple(
n, dimy, dimx)){
374 if(ncplane_set_widget(ns->
ncp, ns, (
void(*)(
void*))ncselector_destroy_internal)){
393 unsigned origdimy, origdimx;
394 ncselector_dim_yx(
n, &origdimy, &origdimx);
395 size_t newsize =
sizeof(*
n->items) * (
n->itemcount + 1);
403 n->items[
n->itemcount].desc = strdup(
desc);
408 unsigned cols = usafecols;
409 n->items[
n->itemcount].opcolumns = cols;
410 if(cols >
n->longop){
414 n->items[
n->itemcount].desccolumns = cols;
415 if(cols >
n->longdesc){
420 ncselector_dim_yx(
n, &dimy, &dimx);
421 if(origdimx < dimx || origdimy < dimy){
422 ncplane_resize_simple(
n->ncp, dimy, dimx);
424 return ncselector_draw(
n);
428 unsigned origdimy, origdimx;
429 ncselector_dim_yx(
n, &origdimy, &origdimx);
431 int maxop = 0, maxdesc = 0;
432 for(
unsigned idx = 0 ;
idx <
n->itemcount ; ++
idx){
433 if(strcmp(
n->items[
idx].option, item) == 0){
436 if(idx < n->itemcount - 1){
437 memmove(
n->items +
idx,
n->items +
idx + 1,
sizeof(*
n->items) * (
n->itemcount -
idx - 1));
459 n->longdesc = maxdesc;
461 ncselector_dim_yx(
n, &dimy, &dimx);
462 if(origdimx > dimx || origdimy > dimy){
463 ncplane_resize_simple(
n->ncp, dimy, dimx);
465 return ncselector_draw(
n);
475 if(
n->itemcount == 0){
478 return n->items[
n->selected].option;
482 const char* ret =
NULL;
483 if(
n->itemcount == 0){
486 if(
n->selected ==
n->startdisp){
487 if(
n->startdisp-- == 0){
488 n->startdisp =
n->itemcount - 1;
491 if(
n->selected == 0){
492 n->selected =
n->itemcount;
495 ret =
n->items[
n->selected].option;
501 const char* ret =
NULL;
502 if(
n->itemcount == 0){
505 unsigned lastdisp =
n->startdisp;
506 lastdisp +=
n->maxdisplay &&
n->maxdisplay <
n->itemcount ?
n->maxdisplay :
n->itemcount;
508 lastdisp %=
n->itemcount;
509 if(lastdisp ==
n->selected){
510 if(++
n->startdisp ==
n->itemcount){
515 if(
n->selected ==
n->itemcount){
518 ret =
n->items[
n->selected].option;
524 const int items_shown = ncplane_dim_y(
n->ncp) - 4 - (
n->title ? 2 : 0);
526 int y = nc->
y,
x = nc->
x;
530 if(
y ==
n->uarrowy &&
x ==
n->arrowx){
533 }
else if(
y ==
n->darrowy &&
x ==
n->arrowx){
536 }
else if(
n->uarrowy <
y && y < n->darrowy){
542 int cury = (
n->selected +
n->itemcount -
n->startdisp) %
n->itemcount;
543 int click =
y -
n->uarrowy - 1;
569 for(
int i = 0 ; i < items_shown ; ++i){
576 for(
int i = 0 ; i < items_shown ; ++i){
598 if(
n->footercols + 2 > cols){
599 cols =
n->footercols + 2;
601 if(
n->secondarycols + 2 > cols){
602 cols =
n->secondarycols + 2;
604 if(
n->longitem + 7 > cols){
605 cols =
n->longitem + 7;
622 size_t riserwidth =
n->titlecols + 4;
626 ncplane_hline(
n->ncp, &transchar, offx);
628 ncplane_rounded_box_sized(
n->ncp, 0,
n->boxchannels, 3, riserwidth, 0);
629 n->ncp->channels =
n->titlechannels;
630 ncplane_printf_yx(
n->ncp, 1, offx + 1,
" %s ",
n->title);
634 ncplane_hline(
n->ncp, &transchar, offx);
637 unsigned bodywidth = ncmultiselector_body_width(
n);
642 for(
unsigned y = yoff + 1 ;
y < dimy ; ++
y){
644 ncplane_hline(
n->ncp, &transchar, xoff);
648 ncplane_rounded_box_sized(
n->ncp, 0,
n->boxchannels, dimy - yoff, bodywidth, 0);
650 n->ncp->channels =
n->boxchannels;
652 if(bodywidth < dimx){
655 if((
n->titlecols + 4 != dimx) &&
n->titlecols >
n->secondarycols){
662 int xloc = bodywidth - (
n->secondarycols + 1) + xoff;
663 if(
n->secondarycols < bodywidth - 2){
666 n->ncp->channels =
n->footchannels;
667 ncplane_putstr_yx(
n->ncp, yoff, xloc,
n->secondary);
670 int xloc = bodywidth - (
n->footercols + 1) + xoff;
671 if(
n->footercols < bodywidth - 2){
674 n->ncp->channels =
n->footchannels;
675 ncplane_putstr_yx(
n->ncp, dimy - 1, xloc,
n->footer);
680 for(
unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
682 ncplane_putc(
n->ncp, &transc);
684 const int bodyoffset = dimx - bodywidth + 2;
685 if(
n->maxdisplay &&
n->maxdisplay <
n->itemcount){
686 n->ncp->channels =
n->descchannels;
687 n->arrowx = bodyoffset + 1;
693 unsigned printidx =
n->startdisp;
694 unsigned printed = 0;
696 for(yoff += 1 ; yoff < dimy - 2 ; ++yoff){
697 if(
n->maxdisplay && printed ==
n->maxdisplay){
701 for(
unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
703 ncplane_putc(
n->ncp, &transc);
705 n->ncp->channels =
n->descchannels;
706 if(printidx ==
n->current){
707 n->ncp->channels = (uint64_t)ncchannels_bchannel(
n->descchannels) << 32u | ncchannels_fchannel(
n->descchannels);
712 ncplane_putchar_yx(
n->ncp, yoff, bodyoffset,
n->items[printidx].selected ?
'X' :
'-');
714 n->ncp->channels =
n->opchannels;
715 if(printidx ==
n->current){
716 n->ncp->channels = (uint64_t)ncchannels_bchannel(
n->opchannels) << 32u | ncchannels_fchannel(
n->opchannels);
718 ncplane_printf(
n->ncp,
" %s ",
n->items[printidx].option);
719 n->ncp->channels =
n->descchannels;
720 if(printidx ==
n->current){
721 n->ncp->channels = (uint64_t)ncchannels_bchannel(
n->descchannels) << 32u | ncchannels_fchannel(
n->descchannels);
723 ncplane_printf(
n->ncp,
"%s",
n->items[printidx].desc);
724 if(++printidx ==
n->itemcount){
731 for(
unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){
733 ncplane_putc(
n->ncp, &transc);
735 if(
n->maxdisplay &&
n->maxdisplay <
n->itemcount){
736 n->ncp->channels =
n->descchannels;
744 const char* ret =
NULL;
745 if(
n->itemcount == 0){
748 if(
n->current ==
n->startdisp){
749 if(
n->startdisp-- == 0){
750 n->startdisp =
n->itemcount - 1;
754 n->current =
n->itemcount;
757 ret =
n->items[
n->current].option;
758 ncmultiselector_draw(
n);
763 const char* ret =
NULL;
764 if(
n->itemcount == 0){
767 unsigned lastdisp =
n->startdisp;
768 lastdisp +=
n->maxdisplay &&
n->maxdisplay <
n->itemcount ?
n->maxdisplay :
n->itemcount;
770 lastdisp %=
n->itemcount;
771 if(lastdisp ==
n->current){
772 if(++
n->startdisp ==
n->itemcount){
777 if(
n->current ==
n->itemcount){
780 ret =
n->items[
n->current].option;
781 ncmultiselector_draw(
n);
786 const int items_shown = ncplane_dim_y(
n->ncp) - 4 - (
n->title ? 2 : 0);
788 int y = nc->
y,
x = nc->
x;
792 if(
y ==
n->uarrowy &&
x ==
n->arrowx){
795 }
else if(
y ==
n->darrowy &&
x ==
n->arrowx){
798 }
else if(
n->uarrowy <
y && y < n->darrowy){
804 int cury = (
n->current +
n->itemcount -
n->startdisp) %
n->itemcount;
805 int click =
y -
n->uarrowy - 1;
818 n->items[
n->current].selected = !
n->items[
n->current].selected;
819 ncmultiselector_draw(
n);
829 for(
int i = 0 ; i < items_shown ; ++i){
836 for(
int i = 0 ; i < items_shown ; ++i){
855ncmultiselector_dim_yx(
const ncmultiselector*
n,
unsigned* ncdimy,
unsigned* ncdimx){
856 unsigned rows = 0, cols = 0;
868 rows += (!
n->maxdisplay ||
n->maxdisplay >
n->itemcount ?
n->itemcount :
n->maxdisplay) - 1;
873 cols = ncmultiselector_body_width(
n);
875 if(
n->titlecols + 4 > cols){
876 cols =
n->titlecols + 4;
887 logerror(
"won't use the standard plane");
897 unsigned itemcount = 0;
907 memset(ns, 0,
sizeof(*ns));
926 if(!(ns->
items = malloc(
sizeof(*ns->
items) * itemcount))){
938 unsigned cols = unsafe;
946 unsigned cols2 = unsafe;
961 if(ncmultiselector_dim_yx(ns, &dimy, &dimx)){
964 if(ncplane_resize_simple(ns->
ncp, dimy, dimx)){
970 ncmultiselector_draw(ns);
987 while(
n->itemcount--){
988 free(
n->items[
n->itemcount].option);
989 free(
n->items[
n->itemcount].desc);
991 if(ncplane_set_widget(
n->ncp,
NULL,
NULL) == 0){
1003 if(
n->itemcount != count ||
n->itemcount < 1){
1007 selected[count] =
n->items[count].selected;
#define logerror(fmt,...)
#define NCKEY_SCROLL_DOWN
int ncplane_cursor_move_yx(ncplane *n, int y, int x)
ncplane * notcurses_stdplane(notcurses *nc)
int ncplane_destroy(ncplane *ncp)
int ncplane_putegc_yx(ncplane *n, int y, int x, const char *gclust, size_t *sbytes)
int ncstrwidth(const char *egcs, int *validbytes, int *validwidth)
bool ncplane_translate_abs(const ncplane *n, int *restrict y, int *restrict x)
notcurses * ncplane_notcurses(const ncplane *n)
void ncplane_erase(ncplane *n)
ncplane * ncplane_parent(ncplane *n)
void ncplane_dim_yx(const ncplane *n, unsigned *rows, unsigned *cols)
const struct ncplane_options * opts
#define NCALPHA_TRANSPARENT
#define NCCELL_TRIVIAL_INITIALIZER
void ncselector_destroy(ncselector *n, char **item)
void ncmultiselector_destroy(ncmultiselector *n)
int ncmultiselector_selected(ncmultiselector *n, bool *selected, unsigned count)
const char * ncselector_nextitem(ncselector *n)
ncplane * ncmultiselector_plane(ncmultiselector *n)
ncplane * ncselector_plane(ncselector *n)
const char * ncmultiselector_nextitem(ncmultiselector *n)
bool ncselector_offer_input(ncselector *n, const ncinput *nc)
ncselector * ncselector_create(ncplane *n, const ncselector_options *opts)
int ncselector_delitem(ncselector *n, const char *item)
int ncselector_additem(ncselector *n, const struct ncselector_item *item)
const char * ncselector_selected(const ncselector *n)
const char * ncmultiselector_previtem(ncmultiselector *n)
const char * ncselector_previtem(ncselector *n)
ncmultiselector * ncmultiselector_create(ncplane *n, const ncmultiselector_options *opts)
bool ncmultiselector_offer_input(ncmultiselector *n, const ncinput *nc)
struct ncmselector_int * items
struct ncselector_int * items