aboutsummaryrefslogtreecommitdiffstats
path: root/com32
diff options
context:
space:
mode:
authorPierre-Alexandre Meyer <pierre@mouraf.org>2009-09-07 14:48:03 -0700
committerPierre-Alexandre Meyer <pierre@mouraf.org>2009-09-07 14:48:03 -0700
commit19b1efa9f4702a695f185596a26c1a33b5c5ed23 (patch)
tree3332f1671f9808a4390d6e63ab298953aff857de /com32
parentd6f6fee0a9e9ccd4fdd922c2d7d917f4dce3aa8f (diff)
downloadsyslinux-19b1efa9f4702a695f185596a26c1a33b5c5ed23.tar.gz
syslinux-19b1efa9f4702a695f185596a26c1a33b5c5ed23.tar.xz
syslinux-19b1efa9f4702a695f185596a26c1a33b5c5ed23.zip
cmenu: optimize redraw to be faster
cmenu currently redraws everything after each key press. This doesn't scale well, especially over serial. Instead, redraw only the previous/current selected entries. A full redraw is still needed when scrolling though. Misc.: add CTRL-L combo to force a redraw of the current menu. Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
Diffstat (limited to 'com32')
-rw-r--r--com32/cmenu/libmenu/menu.c181
1 files changed, 118 insertions, 63 deletions
diff --git a/com32/cmenu/libmenu/menu.c b/com32/cmenu/libmenu/menu.c
index 3ddf0576..dea19750 100644
--- a/com32/cmenu/libmenu/menu.c
+++ b/com32/cmenu/libmenu/menu.c
@@ -81,32 +81,6 @@ static int getch()
return KEY_NONE;
}
-/*
- * Print a menu item
- *
- * attr[0] is non-hilite attr, attr[1] is highlight attr
- */
-void printmenuitem(const char *str, uchar * attr)
-{
- int hlite = NOHLITE; // Initially no highlighting
-
- while (*str) {
- switch (*str) {
- case BELL: // No Bell Char
- break;
- case ENABLEHLITE: // Switch on highlighting
- hlite = HLITE;
- break;
- case DISABLEHLITE: // Turn off highlighting
- hlite = NOHLITE;
- break;
- default:
- putch(*str, attr[hlite]);
- }
- str++;
- }
-}
-
int find_shortcut(pt_menu menu, uchar shortcut, int index)
// Find the next index with specified shortcut key
{
@@ -157,42 +131,61 @@ static void reset_ui(void)
cursoroff();
}
-// print the menu starting from FIRST
-// will print a maximum of menu->menuheight items
-static void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first, bool radio)
+/*
+ * Print a menu item
+ *
+ * attr[0] is non-hilite attr, attr[1] is highlight attr
+ */
+void printmenuitem(const char *str, uchar * attr)
+{
+ int hlite = NOHLITE; // Initially no highlighting
+
+ while (*str) {
+ switch (*str) {
+ case BELL: // No Bell Char
+ break;
+ case ENABLEHLITE: // Switch on highlighting
+ hlite = HLITE;
+ break;
+ case DISABLEHLITE: // Turn off highlighting
+ hlite = NOHLITE;
+ break;
+ default:
+ putch(*str, attr[hlite]);
+ }
+ str++;
+ }
+}
+
+
+/**
+ * print_line - Print a whole line in a menu
+ * @menu: current menu to handle
+ * @curr: index of the current entry highlighted
+ * @top: top coordinate of the @menu
+ * @left: left coordinate of the @menu
+ * @x: index in the menu of curr
+ * @row: row currently displayed
+ * @radio: radio item?
+ **/
+static void print_line(pt_menu menu, int curr, uchar top, uchar left,
+ int x, int row, bool radio)
{
- int x, row; // x = index, row = position from top
- int numitems, menuwidth;
- char fchar[6], lchar[6]; // The first and last char in for each entry
- const char *str; // and inbetween the item or a seperator is printed
- char sep[MENULEN]; // Separator (OPT_SEP)
- uchar *attr; // attribute attr
pt_menuitem ci;
+ char fchar[6], lchar[6]; // The first and last char in for each entry
+ const char *str; // Item string (cf printmenuitem)
+ char sep[MENULEN]; // Separator (OPT_SEP)
+ uchar *attr; // Attribute
+ int menuwidth = menu->menuwidth + 3;
- numitems = calc_visible(menu, first);
- if (numitems > menu->menuheight)
- numitems = menu->menuheight;
+ if (row >= menu->menuheight)
+ return;
- menuwidth = menu->menuwidth + 3;
- clearwindow(top, left - 2, top + numitems + 1, left + menuwidth + 1,
- ms->fillchar, ms->shadowattr);
- drawbox(top - 1, left - 3, top + numitems, left + menuwidth,
- ms->normalattr[NOHLITE]);
- memset(sep, ms->box_horiz, menuwidth); // String containing the seperator string
+ ci = menu->items[x];
+
+ memset(sep, ms->box_horiz, menuwidth);
sep[menuwidth - 1] = 0;
- // Menu title
- x = (menuwidth - strlen(menu->title) - 1) >> 1;
- gotoxy(top - 1, left + x);
- printmenuitem(menu->title, ms->normalattr);
- row = -1; // 1 less than inital value of x
- for (x = first; x < menu->numitems; x++) {
- ci = menu->items[x];
- if (ci->action == OPT_INVISIBLE)
- continue;
- row++;
- if (row >= numitems)
- break; // Already have enough number of items
// Setup the defaults now
if (radio) {
fchar[0] = '\b';
@@ -261,14 +254,57 @@ static void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first
default: // Just to keep the compiler happy
break;
}
+
+ // Wipe area with spaces
gotoxy(top + row, left - 2);
- cprint(ms->spacechar, attr[NOHLITE], menuwidth + 2); // Wipe area with spaces
+ cprint(ms->spacechar, attr[NOHLITE], menuwidth + 2);
+
+ // Print first part
gotoxy(top + row, left - 2);
- csprint(fchar, attr[NOHLITE]); // Print first part
+ csprint(fchar, attr[NOHLITE]);
+
+ // Print main part
gotoxy(top + row, left);
- printmenuitem(str, attr); // Print main part
- gotoxy(top + row, left + menuwidth - 1); // Last char if any
- csprint(lchar, attr[NOHLITE]); // Print last part
+ printmenuitem(str, attr);
+
+ // Print last part
+ gotoxy(top + row, left + menuwidth - 1);
+ csprint(lchar, attr[NOHLITE]);
+}
+
+// print the menu starting from FIRST
+// will print a maximum of menu->menuheight items
+static void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first, bool radio)
+{
+ int x, row; // x = index, row = position from top
+ int numitems, menuwidth;
+ pt_menuitem ci;
+
+ numitems = calc_visible(menu, first);
+ if (numitems > menu->menuheight)
+ numitems = menu->menuheight;
+
+ menuwidth = menu->menuwidth + 3;
+ clearwindow(top, left - 2, top + numitems + 1, left + menuwidth + 1,
+ ms->fillchar, ms->shadowattr);
+ drawbox(top - 1, left - 3, top + numitems, left + menuwidth,
+ ms->normalattr[NOHLITE]);
+
+ // Menu title
+ x = (menuwidth - strlen(menu->title) - 1) >> 1;
+ gotoxy(top - 1, left + x);
+ printmenuitem(menu->title, ms->normalattr);
+
+ // All lines in the menu
+ row = -1; // 1 less than inital value of x
+ for (x = first; x < menu->numitems; x++) {
+ ci = menu->items[x];
+ if (ci->action == OPT_INVISIBLE)
+ continue;
+ row++;
+ if (row >= numitems)
+ break; // Already have enough number of items
+ print_line(menu, curr, top, left, x, row, radio);
}
// Check if we need to MOREABOVE and MOREBELOW to be added
// reuse x
@@ -310,8 +346,9 @@ void cleanupmenu(pt_menu menu, uchar top, uchar left, int numitems)
static pt_menuitem getmenuoption(pt_menu menu, uchar top, uchar left, uchar startopt, bool radio)
// Return item chosen or NULL if ESC was hit.
{
- int curr, i, first, tmp;
+ int prev, prev_first, curr, i, first, tmp;
int asc = 0;
+ bool redraw = true; // Need to draw the menu the first time
uchar numitems;
pt_menuitem ci; // Current item
t_handler_return hr; // Return value of handler
@@ -323,18 +360,36 @@ static pt_menuitem getmenuoption(pt_menu menu, uchar top, uchar left, uchar star
// Initialise current menu item
curr = next_visible(menu, startopt);
+ prev = curr;
gotoxy(ms->minrow + ms->statline, ms->mincol);
cprint(ms->spacechar, ms->statusattr[NOHLITE], ms->numcols);
gotoxy(ms->minrow + ms->statline, ms->mincol);
printmenuitem(menu->items[curr]->status, ms->statusattr);
first = calc_first_early(menu, curr);
+ prev_first = first;
while (1) // Forever
{
- printmenu(menu, curr, top, left, first, radio);
+ /* Redraw everything if:
+ * + we need to scroll (take care of scroll bars, ...)
+ * + menuoption
+ */
+ if (prev_first != first || redraw) {
+ printmenu(menu, curr, top, left, first, radio);
+ } else {
+ /* Redraw only the highlighted entry */
+ print_line(menu, curr, top, left, prev, prev - first, radio);
+ print_line(menu, curr, top, left, curr, curr - first, radio);
+ }
+ redraw = false;
+ prev = curr;
+ prev_first = first;
ci = menu->items[curr];
asc = getch();
switch (asc) {
+ case KEY_CTRL('L'):
+ redraw = true;
+ break;
case KEY_HOME:
curr = next_visible(menu, 0);
first = calc_first_early(menu, curr);