From 6107528154f4fd4ce676909a96da71ebee39c07b Mon Sep 17 00:00:00 2001 From: hpa Date: Tue, 28 Dec 2004 23:18:27 +0000 Subject: [PATCH] Support menu hotkeys. --- README.menu | 8 +++++-- com32/modules/menu.c | 58 ++++++++++++++++++++++++++++++++++++++++++---- com32/modules/menu.h | 3 ++- com32/modules/readconfig.c | 24 +++++++++++++++---- 4 files changed, 81 insertions(+), 12 deletions(-) diff --git a/README.menu b/README.menu index b6f457a..1e1e825 100644 --- a/README.menu +++ b/README.menu @@ -49,16 +49,20 @@ MENU LABEL label # Soft Cap Linux LABEL softcap - MENU LABEL Soft Cap Linux 9.6.36 + MENU LABEL Soft Cap ^Linux 9.6.36 KERNEL softcap-9.6.36.bzi APPEND whatever # A very dense operating system LABEL brick - MENU LABEL Windows CE/ME/NT + MENU LABEL ^Windows CE/ME/NT KERNEL chain.c32 APPEND hd0 2 + The ^ symbol in a MENU LABEL statement defines a hotkey. + The hotkey will be highlighted in the menu and will move the + menu cursor immediately to that entry. + MENU HIDE (Only valid after a LABEL statement.) diff --git a/com32/modules/menu.c b/com32/modules/menu.c index 064afa5..9b91868 100644 --- a/com32/modules/menu.c +++ b/com32/modules/menu.c @@ -42,7 +42,9 @@ struct menu_attrib { const char *border; /* Border area */ const char *title; /* Title bar */ const char *unsel; /* Unselected menu item */ + const char *hotkey; /* Unselected hotkey */ const char *sel; /* Selected */ + const char *hotsel; /* Selected hotkey */ const char *more; /* [More] tag */ const char *tabmsg; /* Press [Tab] message */ const char *cmdmark; /* Command line marker */ @@ -54,7 +56,9 @@ const struct menu_attrib default_attrib = { .border = "\033[0;30;44m", .title = "\033[1;36;44m", .unsel = "\033[0;37;44m", + .hotkey = "\033[1;37;44m", .sel = "\033[0;30;47m", + .hotsel = "\033[1;30;47m", .more = "\033[0;37;44m", .tabmsg = "\033[0;31;40m", .cmdmark = "\033[1;36;40m", @@ -91,6 +95,35 @@ char *pad_line(const char *text, int align, int width) return buffer; } +/* Display an entry, with possible hotkey highlight. Assumes + that the current attribute is the non-hotkey one, and will + guarantee that as an exit condition as well. */ +void display_entry(const struct menu_entry *entry, const char *attrib, + const char *hotattrib, int width) +{ + const char *p = entry->displayname; + + while ( width ) { + if ( *p ) { + if ( *p == '^' ) { + p++; + if ( *p && (unsigned char)*p == entry->hotkey ) { + fputs(hotattrib, stdout); + putchar(*p++); + fputs(attrib, stdout); + width--; + } + } else { + putchar(*p++); + width--; + } + } else { + putchar(' '); + width--; + } + } +} + void draw_menu(int sel, int top) { int x, y; @@ -118,13 +151,21 @@ void draw_menu(int sel, int top) for ( y = 4 ; y < 4+MENU_ROWS ; y++ ) { int i = (y-4)+top; - const char *txt = (i >= nentries) ? "" : menu_entries[i].displayname; - printf("\033[%d;%dH\272%s %s %s\272", + printf("\033[%d;%dH\272%s ", y, MARGIN+1, - (i == sel) ? menu_attrib->sel : menu_attrib->unsel, - pad_line(txt, 0, WIDTH-2*MARGIN-4), - menu_attrib->border); + (i == sel) ? menu_attrib->sel : menu_attrib->unsel); + + if ( i >= nentries ) { + fputs(pad_line("", 0, WIDTH-2*MARGIN-4), stdout); + } else { + display_entry(&menu_entries[i], + (i == sel) ? menu_attrib->sel : menu_attrib->unsel, + (i == sel) ? menu_attrib->hotsel : menu_attrib->hotkey, + WIDTH-2*MARGIN-4); + } + + printf(" %s\272", menu_attrib->border); } printf("\033[%d;%dH\310", y, MARGIN+1); @@ -320,6 +361,13 @@ const char *run_menu(void) done = 1; break; default: + if ( key > 0 && key < 0xFF ) { + key &= ~0x20; /* Upper case */ + if ( menu_hotkeys[key] ) { + entry = menu_hotkeys[key] - menu_entries; + /* Should we commit at this point? */ + } + } break; } } diff --git a/com32/modules/menu.h b/com32/modules/menu.h index 4766a39..1ae7069 100644 --- a/com32/modules/menu.h +++ b/com32/modules/menu.h @@ -24,13 +24,14 @@ struct menu_entry { char *displayname; char *label; char *cmdline; - int flags; + unsigned char hotkey; }; #define MAX_CMDLINE_LEN 256 #define MAX_ENTRIES 4096 /* Oughta be enough for anybody */ extern struct menu_entry menu_entries[]; +extern struct menu_entry *menu_hotkeys[256]; extern int nentries; extern int defentry; diff --git a/com32/modules/readconfig.c b/com32/modules/readconfig.c index eb64d6a..cfb249a 100644 --- a/com32/modules/readconfig.c +++ b/com32/modules/readconfig.c @@ -32,6 +32,7 @@ char *menu_title = ""; char *ontimeout = NULL; struct menu_entry menu_entries[MAX_ENTRIES]; +struct menu_entry *menu_hotkeys[256]; #define astrdup(x) ({ char *__x = (x); \ size_t __n = strlen(__x) + 1; \ @@ -121,12 +122,23 @@ static void record(struct labeldata *ld, char *append) { char ipoptions[256], *ipp; int i; + struct menu_entry *me = &menu_entries[nentries]; if ( ld->label ) { char *a, *s; - menu_entries[nentries].displayname = - ld->menulabel ? ld->menulabel : ld->label; - menu_entries[nentries].label = ld->label; + me->displayname = ld->menulabel ? ld->menulabel : ld->label; + me->label = ld->label; + me->hotkey = 0; + + if ( ld->menulabel ) { + unsigned char *p = strchr(ld->menulabel, '^'); + if ( p && p[1] ) { + int hotkey = p[1] & ~0x20; + if ( !menu_hotkeys[hotkey] ) { + me->hotkey = hotkey; + } + } + } ipp = ipoptions; *ipp = '\0'; @@ -139,7 +151,7 @@ static void record(struct labeldata *ld, char *append) if ( !a ) a = append; if ( !a || (a[0] == '-' && !a[1]) ) a = ""; s = a[0] ? " " : ""; - asprintf(&menu_entries[nentries].cmdline, "%s%s%s%s", ld->kernel, ipoptions, s, a); + asprintf(&me->cmdline, "%s%s%s%s", ld->kernel, ipoptions, s, a); ld->label = NULL; free(ld->kernel); @@ -147,8 +159,12 @@ static void record(struct labeldata *ld, char *append) free(ld->append); if ( !ld->menuhide ) { + if ( me->hotkey ) + menu_hotkeys[me->hotkey] = me; + if ( ld->menudefault ) defentry = nentries; + nentries++; } } -- 2.7.4