diff --git a/README.md b/README.md index 902d89c1f..8e7313f62 100644 --- a/README.md +++ b/README.md @@ -2184,6 +2184,50 @@ void ncselector_nextitem(struct ncselector* n, char** newitem); void ncselector_destroy(struct ncselector* n, char** item); ``` +### Menus + +Horizontal menu bars are supported, on the top and/or bottom rows of the +screen (menus are bound to a `notcurses` object, not particular `ncplane`s). +If the menu bar is longer than the screen, it will be only partially visible. +Menus may be either visible or invisible by default; set the `hiding` option +to get an invisible menu. In the event of a screen resize, menus will be +automatically moved/resized. + +```c +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 horizontal separator + ncinput shortcut; // shortcut, all should be distinct + }* items; + int itemcount; + }* sections; // array of menu sections + int headercount; // must be positive + uint64_t headerchannels; // styling for header + uint64_t sectionchannels; // styling for sections +} menu_options; + +struct ncmenu; + +// Create a menu with the specified options. Menus are currently bound to an +// overall notcurses object (as opposed to a particular plane), and are +// implemented as ncplanes kept atop other ncplanes. +struct ncmenu* ncmenu_create(struct notcurses* nc, const menu_options* opts); + +// Unroll the specified menu section, making the menu visible if it was +// invisible, and rolling up any menu section that is already unrolled. +int ncmenu_unroll(struct ncmenu* n, int sectionidx); + +// Roll up any unrolled menu section, and hide the menu if using hiding. +int ncmenu_rollup(struct ncmenu* n); + +// Destroy a menu created with ncmenu_create(). +int ncmenu_destroy(struct ncmenu* n); +``` + ### Channels A channel encodes 24 bits of RGB color, using 8 bits for each component. It diff --git a/doc/man/index.html b/doc/man/index.html index bfb0f99a0..6228b333c 100644 --- a/doc/man/index.html +++ b/doc/man/index.html @@ -29,6 +29,7 @@ notcurses_init—initialization
notcurses_input—collecting input
notcurses_lines—drawing lines and boxes on ncplanes
+ notcurses_menu—menus on the top or bottom rows
notcurses_ncplane—operations on ncplane objects
notcurses_ncvisual—operations on ncvisual objects
notcurses_output—drawing text on ncplanes
diff --git a/doc/man/man3/notcurses_cell.3.md b/doc/man/man3/notcurses_cell.3.md index 549b4be71..a389c7912 100644 --- a/doc/man/man3/notcurses_cell.3.md +++ b/doc/man/man3/notcurses_cell.3.md @@ -11,6 +11,7 @@ notcurses_cell - operations on notcurses cells **#include ** ```c +// See DESCRIPTION below for information on EGC encoding typedef struct cell { uint32_t gcluster; uint32_t attrword; diff --git a/doc/man/man3/notcurses_menu.3.md b/doc/man/man3/notcurses_menu.3.md index 7b4496201..a916dd172 100644 --- a/doc/man/man3/notcurses_menu.3.md +++ b/doc/man/man3/notcurses_menu.3.md @@ -10,6 +10,33 @@ notcurses_menu - operations on menus **#include ** +``` +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 headercount; // must be positive + uint64_t headerchannels; // styling for header + uint64_t sectionchannels; // styling for sections +} menu_options; +``` + +**struct ncmenu* ncmenu_create(struct notcurses* nc, const menu_options* opts);** + +**int ncmenu_unroll(struct ncmenu* n, int sectionidx);** + +**int ncmenu_rollup(struct ncmenu* n);** + +**int ncmenu_destroy(struct ncmenu* n);** # DESCRIPTION diff --git a/include/notcurses.h b/include/notcurses.h index 90410ea24..21c668fd8 100644 --- a/include/notcurses.h +++ b/include/notcurses.h @@ -2210,15 +2210,35 @@ API void ncselector_destroy(struct ncselector* n, char** item); 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 - char** items; // argv-style list of UTF8 c strings + struct { + char* desc; // utf-8 menu item, NULL for horizontal separator + ncinput shortcut; // shortcut, all should be distinct + }* items; + int itemcount; }* sections; // array of menu sections int headercount; // must be positive uint64_t headerchannels; // styling for header uint64_t sectionchannels; // styling for sections } menu_options; +// Create a menu with the specified options. Menus are currently bound to an +// overall notcurses object (as opposed to a particular plane), and are +// implemented as ncplanes kept atop other ncplanes. +API struct ncmenu* ncmenu_create(struct notcurses* nc, const menu_options* opts); + +// Unroll the specified menu section, making the menu visible if it was +// invisible, and rolling up any menu section that is already unrolled. +API int ncmenu_unroll(struct ncmenu* n, int sectionidx); + +// Roll up any unrolled menu section, and hide the menu if using hiding. +API int ncmenu_rollup(struct ncmenu* n); + +// Destroy a menu created with ncmenu_create(). +API int ncmenu_destroy(struct ncmenu* n); + #undef API #ifdef __cplusplus diff --git a/src/demo/demo.c b/src/demo/demo.c index 5e79e8da5..f33f116f6 100644 --- a/src/demo/demo.c +++ b/src/demo/demo.c @@ -263,6 +263,18 @@ table_segment(struct ncdirect* nc, const char* str, const char* delim){ return 0; } +static int +table_printf(struct ncdirect* nc, const char* delim, const char* fmt, ...){ + ncdirect_fg_rgb8(nc, 0xD4, 0xAF, 0x37); + va_list va; + va_start(va, fmt); + vfprintf(stdout, fmt, va); + va_end(va); + ncdirect_fg_rgb8(nc, 178, 102, 255); + fputs(delim, stdout); + return 0; +} + static int summary_table(struct ncdirect* nc, const char* spec){ bool failed = false; @@ -313,10 +325,13 @@ summary_table(struct ncdirect* nc, const char* spec){ bprefix(totalbytes, 1, totalbuf, 0); qprefix(totalrenderns, GIG, rtimebuf, 0); table_segment(nc, "", "══╧═╧════════╪══════╪═════════╪═════════╪═══╪═══════╪═══════╝\n"); - printf(" %*ss│%6lu│%*s│ %*ss│%3ld│%7.1f│\n", PREFIXSTRLEN, timebuf, - totalframes, BPREFIXSTRLEN, totalbuf, PREFIXSTRLEN, rtimebuf, - nsdelta ? totalrenderns * 100 / nsdelta : 0, - nsdelta ? totalframes / ((double)nsdelta / GIG) : 0); + table_printf(nc, "│", " %*ss", PREFIXSTRLEN, timebuf); + table_printf(nc, "│", "%6lu", totalframes); + table_printf(nc, "│", "%*s", BPREFIXSTRLEN, totalbuf); + table_printf(nc, "│", " %*ss", PREFIXSTRLEN, rtimebuf); + table_printf(nc, "│", "%3ld", nsdelta ? totalrenderns * 100 / nsdelta : 0); + table_printf(nc, "│", "%7.1f", nsdelta ? totalframes / ((double)nsdelta / GIG) : 0); + printf("\n"); ncdirect_fg_rgb8(nc, 0xff, 0xb0, 0xb0); fflush(stdout); // in case we print to stderr below, we want color from above if(failed){ diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index c3476c960..a21652cfa 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -1013,7 +1013,7 @@ int notcurses_stop(notcurses* nc){ NANOSECS_IN_SEC * (double)nc->stashstats.renders / nc->stashstats.render_ns : 0.0, nc->stashstats.failed_renders, nc->stashstats.failed_renders == 1 ? "" : "s"); - fprintf(stderr, "Emits/elides: def %lu/%lu fg %lu/%lu bg %lu/%lu\n", + fprintf(stderr, "RGB emits/elides: def %lu/%lu fg %lu/%lu bg %lu/%lu\n", nc->stashstats.defaultemissions, nc->stashstats.defaultelisions, nc->stashstats.fgemissions, @@ -1027,7 +1027,7 @@ int notcurses_stop(notcurses* nc){ (nc->stashstats.fgelisions * 100.0) / (nc->stashstats.fgemissions + nc->stashstats.fgelisions), (nc->stashstats.bgemissions + nc->stashstats.bgelisions) == 0 ? 0 : (nc->stashstats.bgelisions * 100.0) / (nc->stashstats.bgemissions + nc->stashstats.bgelisions)); - fprintf(stderr, "Cells emitted: %ju elided: %ju (%.2f%%)\n", + fprintf(stderr, "Cell emits/elides: %ju/%ju (%.2f%%)\n", nc->stashstats.cellemissions, nc->stashstats.cellelisions, (nc->stashstats.cellemissions + nc->stashstats.cellelisions) == 0 ? 0 : (nc->stashstats.cellelisions * 100.0) / (nc->stashstats.cellemissions + nc->stashstats.cellelisions)); diff --git a/src/poc/wcwidth.c b/src/poc/wcwidth.c index e963166f2..498282965 100644 --- a/src/poc/wcwidth.c +++ b/src/poc/wcwidth.c @@ -10,6 +10,9 @@ int main(void){ for(int i = 0 ; i < 128 ; ++i){ wchar_t w = i; printf("width('%02x'): %d\t", i, wcwidth(w)); + if(i % 4 == 3){ + printf("\n"); + } } printf("\n"); return EXIT_SUCCESS;