diff --git a/doc/man/man3/notcurses_menu.3.md b/doc/man/man3/notcurses_menu.3.md index 8705be404..909a5cad8 100644 --- a/doc/man/man3/notcurses_menu.3.md +++ b/doc/man/man3/notcurses_menu.3.md @@ -13,21 +13,23 @@ notcurses_menu - operations on menus ```c struct ncmenu; -typedef struct menu_options { - bool bottom; // on the bottom row, as opposed to top row - bool hiding; // hide the menu when not being used - struct { - char* name; // utf-8 c string - struct { - char* desc; // utf-8 menu item, NULL for separator - ncinput shortcut; // shortcut, all should be distinct - }* items; - int itemcount; - }* sections; // array of menu sections - int sectioncount; // must be positive +struct ncmenu_section { + char* name; // utf-8 c string + struct ncmenu_item { + char* desc; // utf-8 menu item, NULL for horizontal separator + ncinput shortcut; // shortcut, all should be distinct + }* items; + int itemcount; +}; + +typedef struct ncmenu_options { + bool bottom; // on the bottom row, as opposed to top row + bool hiding; // hide the menu when not being used + struct ncmenu_section* sections; // array of 'sectioncount' menu_sections + int sectioncount; // must be positive uint64_t headerchannels; // styling for header uint64_t sectionchannels; // styling for sections -} menu_options; +} ncmenu_options; ``` **struct ncmenu* ncmenu_create(struct notcurses* nc, const menu_options* opts);** diff --git a/src/lib/internal.h b/src/lib/internal.h index be5ea1d2b..e62e37002 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -126,6 +126,7 @@ typedef struct renderstate { typedef struct ncmenu { ncplane* ncp; struct ncmenu_section* sections; + bool bottom; // are we on the bottom (vs top)? int sectioncount; // must be positive int unrolledsection; // currently unrolled section, -1 if none int headerwidth; // minimum space necessary to display all sections diff --git a/src/lib/menu.c b/src/lib/menu.c index 4abf54631..6dbad7adf 100644 --- a/src/lib/menu.c +++ b/src/lib/menu.c @@ -38,7 +38,7 @@ dup_menu_section(struct ncmenu_section* dst, const struct ncmenu_section* src){ // Duplicates all menu sections in opts, adding their length to '*totalwidth'. static int -dup_menu_items(ncmenu* ncm, const ncmenu_options* opts, int* totalwidth){ +dup_menu_items(ncmenu* ncm, const ncmenu_options* opts, int* totalwidth, int* totalheight){ ncm->sections = NULL; if((ncm->sectioncount = opts->sectioncount) == 0){ ++*totalwidth; // one character margin on right @@ -48,6 +48,7 @@ dup_menu_items(ncmenu* ncm, const ncmenu_options* opts, int* totalwidth){ if(ncm->sections == NULL){ return -1; } + int maxheight = 0; for(int i = 0 ; i < opts->sectioncount ; ++i){ int cols = mbswidth(opts->sections[i].name); if(cols < 0 || (ncm->sections[i].name = strdup(opts->sections[i].name)) == NULL){ @@ -63,7 +64,11 @@ dup_menu_items(ncmenu* ncm, const ncmenu_options* opts, int* totalwidth){ } return -1; } + if(ncm->sections[i].itemcount > maxheight){ + maxheight = ncm->sections[i].itemcount; + } } + *totalheight += maxheight + 2; // two rows of border return 0; } @@ -71,9 +76,11 @@ static int write_header(ncmenu* ncm){ ncm->ncp->channels = ncm->headerchannels; ncplane_set_base(ncm->ncp, ncm->headerchannels, 0, " "); + int dimy = ncplane_dim_y(ncm->ncp); int xoff = 1; // 1 character margin on left + int ypos = ncm->bottom ? dimy - 1 : 0; for(int i = 0 ; i < ncm->sectioncount ; ++i){ - if(ncplane_putstr_yx(ncm->ncp, 0, xoff, ncm->sections[i].name) < 0){ + if(ncplane_putstr_yx(ncm->ncp, ypos, xoff, ncm->sections[i].name) < 0){ return -1; } xoff += mbswidth(ncm->sections[i].name) + 2; @@ -97,14 +104,15 @@ ncmenu* ncmenu_create(notcurses* nc, const ncmenu_options* opts){ ret->sections = NULL; int dimy, dimx; ncplane_dim_yx(notcurses_stdplane(nc), &dimy, &dimx); - int ypos = opts->bottom ? dimy - 1 : 0; if(ret){ + ret->bottom = opts->bottom; // FIXME maximum width could be more than section headers, due to items! - if(dup_menu_items(ret, opts, &totalwidth) == 0){ + if(dup_menu_items(ret, opts, &totalwidth, &totalheight) == 0){ ret->headerwidth = totalwidth; if(totalwidth < dimx){ totalwidth = dimx; } + int ypos = opts->bottom ? dimy - totalheight : 0; ret->ncp = ncplane_new(nc, totalheight, totalwidth, ypos, 0, NULL); if(ret->ncp){ ret->unrolledsection = -1; @@ -124,9 +132,10 @@ int ncmenu_unroll(ncmenu* n, int sectionidx){ if(sectionidx < 0 || sectionidx >= n->sectioncount){ return -1; } - if(ncmenu_rollup(n)){ // roll up any unroled section + if(ncmenu_rollup(n)){ // roll up any unrolled section return -1; } + n->unrolledsection = sectionidx; // FIXME return 0; } diff --git a/src/poc/menu.c b/src/poc/menu.c index 9fd5b5328..db2632a44 100644 --- a/src/poc/menu.c +++ b/src/poc/menu.c @@ -10,8 +10,15 @@ run_menu(struct notcurses* nc, struct ncmenu* ncm){ ncinput ni; notcurses_render(nc); while((keypress = notcurses_getc_blocking(nc, &ni)) != (char32_t)-1){ - switch(keypress){ - // FIXME + if(ni.alt){ + switch(keypress){ + case 'd': case 'D': + ncmenu_unroll(ncm, 0); + break; + case 'f': case 'F': + ncmenu_unroll(ncm, 1); + break; + } } if(keypress == 'q'){ ncmenu_destroy(ncm); @@ -54,7 +61,7 @@ int main(void){ mopts.sections = sections; mopts.sectioncount = sizeof(sections) / sizeof(*sections); channels_set_fg(&mopts.headerchannels, 0x00ff00); - channels_set_bg(&mopts.headerchannels, 0x880000); + channels_set_bg(&mopts.headerchannels, 0x440000); struct ncmenu* top = ncmenu_create(nc, &mopts); notcurses_render(nc);