memory allocation routine is implemented, to reduce the memory footprint
of this utility.
-Features currently supported are:
+Menu Features currently supported are:
* menu items,
* submenus,
* disabled items,
* checkboxes,
* invisible items (useful for dynamic menus), and
* Radio menus
-
The keys used are:
* Space to switch state of a checkbox
* Enter to choose the item
* Escape to exit from it
+* Shortcut keys
Features
--------
at a specific location of his choice. This is useful, when the menu's
have lots of options.
* Registering handlers for each menu item
- This is mainly used for checkboxes, where selecting a checkbox, may
- result in disabling another menu item, or de-selecting another
- checkbox.
+ This is mainly used for checkboxes and radiomenu's, where a selection may
+ result in disabling other menu items/checkboxes
* Global Handler
This is called every time the menu is redrawn. The user can display
additional information (usually outside the window where the menu is
being displayed). See the complex.c for an example, where the global
handler is used to display the choices made so far.
+* Shortcut Keys
+ With each item one can register a shortcut key from [A-Za-z0-9].
+ Pressing a key within that range, will take you to the next item
+ with that shortcut key (so you can have multiple items with the
+ same shortcut key). The default shortcut key for each item, is
+ the lower case version of the first char of the item in the range
+ [A-Za-z0-9].
+* Escape Keys
+ Each item entry can have a substring enclosed in < and >. This part
+ is highlighted. Can be used to highlight the shortcut keys. By default
+ if an item has a <, then the first char inside < and > in the range
+ [A-Za-z0-9] is converted to lower case and set as the shortcut key.
+* Ontimeout handler
+ The user can register an ontimeout handler, which gets called if
+ no key has been pressed for a user specific amount of time (default 5 min).
+ For an example see the complex.c file.
Credits
-------
: "ebx", "ecx", "ebp");
}
-static inline void scrollup()
+void putch(char x, char attr, char page)
+{
+ asm_putchar(x,attr,page);
+}
+
+void scrollup()
{
unsigned short dx = (getnumrows()<< 8) + getnumcols();
void csprint(const char *str,char attr)
{
char page = asm_getdisppage();
+ char newattr=0,cha,chb;
char row,col;
asm_getpos(&row,&col,page);
case '\r':
col=0;
break;
- case 0x07: // Bell Char
+ case BELL: // Bell Char
asm_beep();
break;
+ case CHRELATTR: // change attribute (relatively)
+ case CHABSATTR: // change attribute (absolute)
+ cha = *(str+1);
+ chb = *(str+2);
+ if ((((cha >= '0') && (cha <= '9')) ||
+ ((cha >= 'A') && (cha <= 'F'))) &&
+ (((chb >= '0') && (chb <= '9')) ||
+ ((chb >= 'A') && (chb <= 'F')))) // Next two chars are legal
+ {
+ if ((cha >= 'A') && (cha <= 'F'))
+ cha = cha - 'A'+10;
+ else cha = cha - '0';
+ if ((chb >= 'A') && (chb <= 'F'))
+ chb = chb - 'A'+10;
+ else chb = chb - '0';
+ newattr = (cha << 4) + chb;
+ attr = (*str == CHABSATTR ? newattr : attr ^ newattr);
+ str += 2; // Will be incremented again later
+ }
+ break;
default:
asm_putchar(*str, attr, page);
++col;
asm volatile("movb $0x01,%%ah ; int $0x10"
: : "c" ((start << 8) + end) : "eax");
}
-
+
void cursoroff(void)
{
asm_cursorshape(32,32);
#define NULL ((void *)0)
#endif
+#define BELL 0x07
+// CHRELATTR = ^N, CHABSATTR = ^O
+#define CHABSATTR 15
+#define CHRELATTR 14
+
/* BIOS Assisted output routines */
void csprint(const char *str, char attr); // Print a C str (NUL-terminated)
char getdisppage(); // Get current display page
-void clearwindow(char top,char left,char bot,char right, char page,char fillchar, char fillattr);
+void clearwindow(char top, char left, char bot, char right,
+ char page, char fillchar, char fillattr);
void cls(void); /* Clears the entire current screen page */
char inputc(char * scancode); // Return ASCII char by val, and scancode by reference
+
+void putch(char x, char attr, char page); // Print one char
+
void cursoroff(void); /* Turns on cursor */
void cursoron(void); /* Turns off cursor */
{
return readbiosb(0x44a);
}
+
+void scrollup(); //Scroll up display screen by one line
void setvideomode(char mode); // Set the video mode.
char infoline[160];
// Different network options
-static char nonet[] = "network [none]";
-static char dhcpnet[]="network [dhcp]";
-static char statnet[]="network [static]";
+static char nonet[] = "<n>etwork [none]";
+static char dhcpnet[]="<n>etwork [dhcp]";
+static char statnet[]="<n>etwork [static]";
struct {
unsigned int baseurl : 1; // Do we need to specify by url
/* End globals */
+
+TIMEOUTCODE ontimeout()
+{
+ beep();
+ return CODE_WAIT;
+}
+
+
#define INFLINE 22
void msys_handler(t_menusystem *ms, t_menuitem *mi)
// Register the menusystem handler
reg_handler(&msys_handler);
+ // Register the ontimeout handler, with a time out of 10 seconds
+ reg_ontimeout(ontimeout,1000,0);
NETMENU = add_menu(" Init Network ");
- none = add_item("None","Dont start network",OPT_RADIOITEM,"no ",0);
- dhcp = add_item("dhcp","Use DHCP",OPT_RADIOITEM,"dhcp ",0);
- stat = add_item("static","Use static IP I will specify later",OPT_RADIOITEM,"static ",0);
+ none = add_item("<N>one","Dont start network",OPT_RADIOITEM,"no ",0);
+ dhcp = add_item("<d>hcp","Use DHCP",OPT_RADIOITEM,"dhcp ",0);
+ stat = add_item("<s>tatic","Use static IP I will specify later",OPT_RADIOITEM,"static ",0);
TESTING = add_menu(" Testing ");
set_menu_pos(5,55);
- add_item("Memory Test","Perform extensive memory testing",OPT_RUN, "memtest",0);
- add_item("Invisible","You dont see this",OPT_INVISIBLE,"junk",0);
- add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0);
+ add_item("<M>emory Test","Perform extensive memory testing",OPT_RUN, "memtest",0);
+ add_item("<I>nvisible","You dont see this",OPT_INVISIBLE,"junk",0);
+ add_item("<E>xit this menu","Go one level up",OPT_EXITMENU,"exit",0);
RESCUE = add_menu(" Rescue Options ");
- add_item("Linux Rescue","linresc",OPT_RUN,"linresc",0);
- add_item("Dos Rescue","dosresc",OPT_RUN,"dosresc",0);
- add_item("Windows Rescue","winresc",OPT_RUN,"winresc",0);
- add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0);
+ add_item("<L>inux Rescue","linresc",OPT_RUN,"linresc",0);
+ add_item("<D>os Rescue","dosresc",OPT_RUN,"dosresc",0);
+ add_item("<W>indows Rescue","winresc",OPT_RUN,"winresc",0);
+ add_item("<E>xit this menu","Go one level up",OPT_EXITMENU,"exit",0);
PREP = add_menu(" Prep options ");
- baseurl = add_item("baseurl by IP?","Specify gui baseurl by IP address",OPT_CHECKBOX,"baseurl",0);
- mountcd = add_item("mountcd?","Mount the cdrom drive?",OPT_CHECKBOX,"mountcd",0);
+ baseurl = add_item("<b>aseurl by IP?","Specify gui baseurl by IP address",OPT_CHECKBOX,"baseurl",0);
+ mountcd = add_item("<m>ountcd?","Mount the cdrom drive?",OPT_CHECKBOX,"mountcd",0);
network = add_item(dhcpnet,"How to initialise network device?",OPT_RADIOMENU,NULL,NETMENU);
add_sep();
- winrep = add_item("Reinstall windows","Re-install the windows side of a dual boot setup",OPT_CHECKBOX,"winrepair",0);
- linrep = add_item("Reinstall linux","Re-install the linux side of a dual boot setup",OPT_CHECKBOX,"linrepair",0);
+ winrep = add_item("Reinstall <w>indows","Re-install the windows side of a dual boot setup",OPT_CHECKBOX,"winrepair",0);
+ linrep = add_item("Reinstall <l>inux","Re-install the linux side of a dual boot setup",OPT_CHECKBOX,"linrepair",0);
add_sep();
- runprep = add_item("Run prep now","Execute prep with the above options",OPT_RUN,"prep",0);
- add_item("Exit this menu","Go up one level",OPT_EXITMENU,"exitmenu",0);
+ runprep = add_item("<R>un prep now","Execute prep with the above options",OPT_RUN,"prep",0);
+ add_item("<E>xit this menu","Go up one level",OPT_EXITMENU,"exitmenu",0);
baseurl->handler = &checkbox_handler;
mountcd->handler = &checkbox_handler;
winrep->handler = &checkbox_handler;
flags.linrep = 0;
MAIN = add_menu(" Main Menu ");
- add_item("Prepare","prep",OPT_RUN,"prep",0);
- add_item("Prep options...","Options for prep image",OPT_SUBMENU,NULL,PREP);
- add_item("Rescue options...","Troubleshoot a system",OPT_SUBMENU,NULL,RESCUE);
- add_item("Testing...","Options to test hardware",OPT_SUBMENU,NULL,TESTING);
- add_item("Exit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0);
+ add_item("<P>repare","prep",OPT_RUN,"prep",0);
+ add_item("<P>rep options...","Options for prep image",OPT_SUBMENU,NULL,PREP);
+ add_item("<R>escue options...","Troubleshoot a system",OPT_SUBMENU,NULL,RESCUE);
+ add_item("<T>esting...","Options to test hardware",OPT_SUBMENU,NULL,TESTING);
+ add_item("<E>xit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0);
csprint("Press any key within 5 seconds to show menu...",0x07);
- if (!checkkeypress(200,25)) // Granularity of 200 milliseconds
+ if (!checkkeypress(100,50)) // Granularity of 100 milliseconds
{
csprint("Sorry! Time's up.\r\n",0x07);
return 1;
curr = showmenus(MAIN);
if (curr)
{
- if (curr->action == OPT_EXIT) return 0;
if (curr->action == OPT_RUN)
{
strcpy(cmd,curr->data);
if (syslinux)
runcommand(cmd);
else csprint(cmd,0x07);
- return 1;
+ return 1; // Should not happen when run from SYSLINUX
}
}
+ // If user quits the menu system, control comes here
+ // If you want to execute some specific command uncomment the next two lines
+
+ // if (syslinux) runcommand(YOUR_COMMAND_HERE);
+ // else csprint(YOUR_COMMAND_HERE,0x07);
+
+ // Return to prompt
return 0;
}
/* Basic Menu routines */
+// This is same as inputc except it honors the ontimeout handler
+// and calls it when needed. For the callee, there is no difference
+// as this will not return unless a key has been pressed.
+char getch(char *scan)
+{
+ unsigned long i;
+ TIMEOUTCODE c;
+
+ // Wait until keypress if no handler specified
+ if (ms->ontimeout==NULL) return inputc(scan);
+
+ while (1) // Forever do
+ {
+ for (i=0; i < ms->tm_numsteps; i++)
+ {
+ if (checkkbdbuf()) return inputc(scan);
+ sleep(ms->tm_stepsize);
+ }
+ c = ms->ontimeout();
+ switch(c)
+ {
+ case CODE_ENTER: // Pretend user hit enter
+ *scan = ENTERA;
+ return '\015'; // \015 octal = 13
+ case CODE_ESCAPE: // Pretend user hit escape
+ *scan = ESCAPE;
+ return '\033'; // \033 octal = 27
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+/* Print a menu item */
+/* attr[0] is non-hilite attr, attr[1] is highlight attr */
+void printmenuitem(const char *str,char* attr)
+{
+ char page = getdisppage();
+ char row,col;
+ int hlite=NOHLITE; // Initially no highlighting
+
+ getpos(&row,&col,page);
+ while ( *str ) {
+ switch (*str)
+ {
+ case '\b':
+ --col;
+ break;
+ case '\n':
+ ++row;
+ break;
+ case '\r':
+ col=0;
+ break;
+ 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], page);
+ ++col;
+ }
+ if (col > getnumcols())
+ {
+ ++row;
+ col=0;
+ }
+ if (row > getnumrows())
+ {
+ scrollup();
+ row= getnumrows();
+ }
+ gotoxy(row,col,page);
+ str++;
+ }
+}
+
void drawbox(char top, char left, char bot, char right,char attr, char page)
{
char x;
return ans;
}
+int find_shortcut(pt_menu menu,char shortcut, int index)
+// Find the next index with specified shortcut key
+{
+ int ans;
+ pt_menuitem mi;
+
+ // Garbage in garbage out
+ if ((index <0) || (index >= menu->numitems)) return index;
+ ans = index+1;
+ // Go till end of menu
+ while (ans < menu->numitems)
+ {
+ mi = menu->items[ans];
+ if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP)
+ || (mi->shortcut != shortcut))
+ ans ++;
+ else return ans;
+ }
+ // Start at the beginning and try again
+ ans = 0;
+ while (ans < index)
+ {
+ mi = menu->items[ans];
+ if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP)
+ || (mi->shortcut != shortcut))
+ ans ++;
+ else return ans;
+ }
+ return index; // Sorry not found
+}
+
void printmenu(pt_menu menu, int curr, char top, char left)
{
int x,row; // x = index, row = position from top
int numitems,menuwidth;
char fchar[5],lchar[5]; // The first and last char in for each entry
const char *str; // and inbetween the item or a seperator is printed
- char attr; // all in the attribute attr
+ char *attr; // attribute attr
char sep[MENULEN];// and inbetween the item or a seperator is printed
pt_menuitem ci;
clearwindow(top,left-2, top+numitems+1, left+menuwidth+1,
ms->menupage, ms->fillchar, ms->shadowattr);
drawbox(top-1, left-3, top+numitems, left+menuwidth,
- ms->normalattr, ms->menupage);
+ ms->normalattr[NOHLITE], ms->menupage);
memset(sep,HORIZ,menuwidth); // String containing the seperator string
sep[menuwidth-1] = 0;
// Menu title
x = (menuwidth - strlen(menu->title) - 1) >> 1;
gotoxy(top-1,left+x,ms->menupage);
- csprint(menu->title,ms->normalattr);
+ printmenuitem(menu->title,ms->normalattr);
row = -1; // 1 less than inital value of x
for (x=0; x < menu->numitems; x++)
{
break;
case OPT_SEP:
fchar[0] = '\b'; fchar[1] = LTRT; fchar[2] = HORIZ; fchar[3] = HORIZ; fchar[4] = 0;
- lchar[0] = HORIZ; lchar[1] = RTLT; lchar[3] = 0;
+ lchar[0] = HORIZ; lchar[1] = RTLT; lchar[2] = 0;
str = sep;
break;
case OPT_EXITMENU:
break;
}
gotoxy(top+row,left-2,ms->menupage);
- cprint(ms->spacechar,attr,menuwidth+2,ms->menupage); // Wipe area with spaces
+ cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces
gotoxy(top+row,left-2,ms->menupage);
- csprint(fchar,attr); // Print first part
+ csprint(fchar,attr[NOHLITE]); // Print first part
gotoxy(top+row,left,ms->menupage);
- csprint(str,attr); // Print main part
+ printmenuitem(str,attr); // Print main part
gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any
- csprint(lchar,attr); // Print last part
+ csprint(lchar,attr[NOHLITE]); // Print last part
}
if (ms->handler) ms->handler(ms,menu->items[curr]);
}
int numitems,menuwidth;
char fchar[5],lchar[5]; // The first and last char in for each entry
const char *str; // and inbetween the item or a seperator is printed
- char attr; // all in the attribute attr
+ char *attr; // all in the attribute attr
char sep[MENULEN];// and inbetween the item or a seperator is printed
pt_menuitem ci;
clearwindow(top,left-2, top+numitems+1, left+menuwidth+1,
ms->menupage, ms->fillchar, ms->shadowattr);
drawbox(top-1, left-3, top+numitems, left+menuwidth,
- ms->normalattr, ms->menupage);
+ ms->normalattr[NOHLITE], ms->menupage);
memset(sep,HORIZ,menuwidth); // String containing the seperator string
sep[menuwidth-1] = 0;
// Menu title
x = (menuwidth - strlen(menu->title) - 1) >> 1;
gotoxy(top-1,left+x,ms->menupage);
- csprint(menu->title,ms->normalattr);
+ printmenuitem(menu->title,ms->normalattr);
row = -1; // 1 less than inital value of x
for (x=0; x < menu->numitems; x++)
{
break;
}
gotoxy(top+row,left-2,ms->menupage);
- cprint(ms->spacechar,attr,menuwidth+2,ms->menupage); // Wipe area with spaces
+ cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces
gotoxy(top+row,left-2,ms->menupage);
- csprint(fchar,attr); // Print first part
+ csprint(fchar,attr[NOHLITE]); // Print first part
gotoxy(top+row,left,ms->menupage);
- csprint(str,attr); // Print main part
+ printmenuitem(str,attr); // Print main part
gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any
- csprint(lchar,attr); // Print last part
+ csprint(lchar,attr[NOHLITE]); // Print last part
}
if (ms->handler) ms->handler(ms,menu->items[curr]);
}
numitems = menu->numvisible;
// Setup status line
gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
- cprint(ms->spacechar,ms->reverseattr,ms->numcols,ms->menupage);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
// Initialise current menu item
curr = next_visible(menu,startopt);
gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
- cprint(ms->spacechar,ms->statusattr,ms->numcols,1);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1);
gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
- csprint(menu->items[curr]->status,ms->statusattr);
+ printmenuitem(menu->items[curr]->status,ms->statusattr);
while (1) // Forever
{
printradiomenu(menu,curr,top,left);
ci = menu->items[curr];
- asc = inputc(&scan);
+
+ asc = getch(&scan);
switch (scan)
{
case HOMEKEY:
if (ci->action == OPT_SEP) break;
return ci;
break;
+ default:
+ // Check if this is a shortcut key
+ if (((asc >= 'A') && (asc <= 'Z')) ||
+ ((asc >= 'a') && (asc <= 'z')) ||
+ ((asc >= '0') && (asc <= '9')))
+ curr = find_shortcut(menu,asc,curr);
+ break;
}
- // Adjust within range
- //if (curr < 0) curr=next_visible(menu,0);
- //if (curr >= numitems) curr = prev_visible(menu,numitems -1);
// Update status line
gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
- cprint(ms->spacechar,ms->statusattr,ms->numcols,ms->menupage);
- csprint(menu->items[curr]->status,ms->statusattr);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
+ printmenuitem(menu->items[curr]->status,ms->statusattr);
}
return NULL; // Should never come here
}
numitems = menu->numvisible;
// Setup status line
gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
- cprint(ms->spacechar,ms->reverseattr,ms->numcols,ms->menupage);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
// Initialise current menu item
curr = next_visible(menu,startopt);
gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
- cprint(ms->spacechar,ms->statusattr,ms->numcols,1);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1);
gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
- csprint(menu->items[curr]->status,ms->statusattr);
+ printmenuitem(menu->items[curr]->status,ms->statusattr);
while (1) // Forever
{
printmenu(menu,curr,top,left);
ci = menu->items[curr];
- asc = inputc(&scan);
+ asc = getch(&scan);
switch (scan)
{
case HOMEKEY:
// Call handler to see it anything needs to be done
if (ci->handler != NULL) ci->handler(ms,ci);
break;
+ default:
+ // Check if this is a shortcut key
+ if (((asc >= 'A') && (asc <= 'Z')) ||
+ ((asc >= 'a') && (asc <= 'z')) ||
+ ((asc >= '0') && (asc <= '9')))
+ curr = find_shortcut(menu,asc,curr);
+ break;
}
- // Adjust within range
- //if (curr < 0) curr=next_visible(menu,0);
- //if (curr >= numitems) curr = prev_visible(menu,numitems -1);
// Update status line
gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
- cprint(ms->spacechar,ms->statusattr,ms->numcols,ms->menupage);
- csprint(menu->items[curr]->status,ms->statusattr);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
+ printmenuitem(menu->items[curr]->status,ms->statusattr);
}
return NULL; // Should never come here
}
ms->title = TITLESTR; // Copy pointers
else ms->title = title;
- ms->normalattr = NORMALATTR;
- ms->reverseattr= REVERSEATTR;
- ms->inactattr = INACTATTR;
- ms->revinactattr = REVINACTATTR;
+ // Timeout settings
+ ms->tm_stepsize = TIMEOUTSTEPSIZE;
+ ms->tm_numsteps = TIMEOUTNUMSTEPS;
+
+ ms->normalattr[NOHLITE] = NORMALATTR;
+ ms->normalattr[HLITE] = NORMALHLITE;
+
+ ms->reverseattr[NOHLITE] = REVERSEATTR;
+ ms->reverseattr[HLITE] = REVERSEHLITE;
+
+ ms->inactattr[NOHLITE] = INACTATTR;
+ ms->inactattr[HLITE] = INACTHLITE;
+
+ ms->revinactattr[NOHLITE] = REVINACTATTR;
+ ms->revinactattr[HLITE] = REVINACTHLITE;
+
+ ms->statusattr[NOHLITE] = STATUSATTR;
+ ms->statusattr[HLITE] = STATUSHLITE;
- ms->statusattr = STATUSATTR;
ms->statline = STATLINE;
ms->tfillchar= TFILLCHAR;
ms->titleattr= TITLEATTR;
ms->menupage = MENUPAGE; // Usually no need to change this at all
ms->handler = NULL; // No handler function
+ ms->ontimeout=NULL; // No timeout handler
// Figure out the size of the screen we are in now.
// By default we use the whole screen for our menu
void set_normal_attr(char normal, char selected, char inactivenormal, char inactiveselected)
{
- if (normal != 0xFF) ms->normalattr = normal;
- if (selected != 0xFF) ms->reverseattr = selected;
- if (inactivenormal != 0xFF) ms->inactattr = inactivenormal;
- if (inactiveselected != 0xFF) ms->revinactattr = inactiveselected;
+ if (normal != 0xFF) ms->normalattr[0] = normal;
+ if (selected != 0xFF) ms->reverseattr[0] = selected;
+ if (inactivenormal != 0xFF) ms->inactattr[0] = inactivenormal;
+ if (inactiveselected != 0xFF) ms->revinactattr[0] = inactiveselected;
}
-void set_status_info(char statusattr, char statline)
+void set_normal_hlite(char normal, char selected, char inactivenormal, char inactiveselected)
{
- if (statusattr != 0xFF) ms->statusattr = statusattr;
+ if (normal != 0xFF) ms->normalattr[1] = normal;
+ if (selected != 0xFF) ms->reverseattr[1] = selected;
+ if (inactivenormal != 0xFF) ms->inactattr[1] = inactivenormal;
+ if (inactiveselected != 0xFF) ms->revinactattr[1] = inactiveselected;
+}
+
+
+void set_status_info(char statusattr, char statushlite, char statline)
+{
+ if (statusattr != 0xFF) ms->statusattr[NOHLITE] = statusattr;
+ if (statushlite!= 0xFF) ms->statusattr[HLITE] = statushlite;
// statline is relative to minrow
if (statline >= ms->numrows) statline = ms->numrows - 1;
ms->statline = statline; // relative to ms->minrow, 0 based
ms->handler = NULL;
}
+void reg_ontimeout(t_timeout_handler handler, unsigned int numsteps, unsigned int stepsize)
+{
+ ms->ontimeout = handler;
+ if (numsteps != 0) ms->tm_numsteps = numsteps;
+ if (stepsize != 0) ms->tm_stepsize = stepsize;
+}
+
+void unreg_ontimeout()
+{
+ ms->ontimeout = NULL;
+}
+
+
void calc_visible(pt_menu menu)
{
int ans,i;
mi->action = OPT_SEP;
mi->index = m->numitems++;
mi->parindex = ms->nummenus-1;
+ mi->shortcut = 0;
return mi;
}
{
pt_menuitem mi;
pt_menu m;
+ const char *str;
+ char inhlite=0; // Are we inside hlite area
m = (ms->menus[ms->nummenus-1]);
mi = NULL;
} else mi->status = EMPTYSTR;
mi->action = action;
+ str = mi->item;
+ mi->shortcut = 0;
+ inhlite = 0; // We have not yet seen an ENABLEHLITE char
+ // Find the first char in [A-Za-z0-9] after ENABLEHLITE and not arg to control char
+ while (*str)
+ {
+ if (*str == ENABLEHLITE)
+ {
+ inhlite=1;
+ }
+ if (*str == DISABLEHLITE)
+ {
+ inhlite = 0;
+ }
+ if ( (inhlite == 1) &&
+ (((*str >= 'A') && (*str <= 'Z')) ||
+ ((*str >= 'a') && (*str <= 'z')) ||
+ ((*str >= '0') && (*str <= '9'))))
+ {
+ mi->shortcut=*str;
+ break;
+ }
+ ++str;
+ }
+ if ((mi->shortcut >= 'A') && (mi->shortcut <= 'Z')) // Make lower case
+ mi->shortcut = mi->shortcut -'A'+'a';
if (data) {
if (strlen(data) > ACTIONLEN - 2) {
} else {
mi->data = data;
}
- } else mi->data = EMPTYSTR;
+ } else mi->data = EMPTYSTR;
switch (action)
{
mi->parindex = ms->nummenus-1;
return mi;
}
+
+// Set the shortcut key for the current item
+void set_shortcut(char shortcut)
+{
+ pt_menuitem mi;
+ pt_menu m;
+
+ m = (ms->menus[ms->nummenus-1]);
+ if (m->numitems <= 0) return;
+ mi = m->items[(unsigned int) m->numitems-1];
+ mi->shortcut = shortcut;
+}
#include "biosio.h"
#include "string.h"
+// TIMEOUT PARAMETERS
+/* If no key is pressed within TIMEOUTNUMSTEPS * TIMEOUTSTEPSIZE milliseconds
+ and if a timeout handler is registered, then that will be called.
+ The handler should either either take control from there on, or return without
+ producing any change in the current video settings.
+
+ For e.g. the handler could
+ * Could just quit the menu program
+ * beep and return.
+
+ TIMEOUTSTEPSIZE is the interval for which the program sleeps without checking for
+ any keystroke. So increasing this will make the response of the system slow.
+ Decreasing this will make a lot of interrupt calls using up your CPU. Default
+ value of TIMEOUTSTEPSIZE of 0.1 seconds should be right in most cases.
+
+ TIMEOUTNUMSTEPS of 3000 corresponds to a wait time of 300 seconds or 5 minutes
+*/
+
+#define TIMEOUTSTEPSIZE 10
+#define TIMEOUTNUMSTEPS 30000L
+
// Scancodes of some keys
#define ESCAPE 1
#define ENTERA 28
#define SPACEKEY 57 // Scan code for SPACE
// Attributes
-#define NORMALATTR 0x17
-#define REVERSEATTR 0x70
-#define INACTATTR 0x18
-#define REVINACTATTR 0x78
-#define STATUSATTR 0x74
-#define FILLCHAR 177
-#define FILLATTR 0x01
-#define SHADOWATTR 0x00
-#define SPACECHAR ' '
-
-#define TFILLCHAR ' '
-#define TITLEATTR 0x70
+#define NORMALATTR 0x17
+#define NORMALHLITE 0x1F // Normal Highlight attribute
+#define REVERSEATTR 0x70
+#define REVERSEHLITE 0x78 // Reverse Hightlight attribute
+#define INACTATTR 0x18
+#define INACTHLITE 0x10 // Inactive Highlight attribute
+#define REVINACTATTR 0x78
+#define REVINACTHLITE 0x70 // Reverse Inactive Highlight attr
+
+#define STATUSATTR 0x74
+#define STATUSHLITE 0x7B // Status highlight
+
+#define FILLCHAR 177
+#define FILLATTR 0x01
+#define SHADOWATTR 0x00
+#define SPACECHAR ' '
+
+#define TFILLCHAR ' '
+#define TITLEATTR 0x70
+
+#define ENABLEHLITE '<' // Char which turns on highlight
+#define DISABLEHLITE '>' // Char which turns off highlight
+#define NOHLITE 0 // The offset into attrib array for non-hilite
+#define HLITE 1 // The offset for Hlite attrib
// Single line Box drawing Chars
#define RADIOMENU 2
typedef enum {OPT_INACTIVE, OPT_SUBMENU, OPT_RUN, OPT_EXITMENU, OPT_CHECKBOX,
- OPT_RADIOMENU, OPT_EXIT, OPT_SEP, OPT_INVISIBLE,
+ OPT_RADIOMENU, OPT_SEP, OPT_INVISIBLE,
OPT_RADIOITEM} t_action;
typedef union {
typedef void (*t_item_handler)(struct s_menusystem *, struct s_menuitem *);
typedef void (*t_menusystem_handler)(struct s_menusystem *, struct s_menuitem *);
+// TIMEOUT is the list of possible values which can be returned by the handler
+// instructing the menusystem what to do. The default is CODE_WAIT
+typedef enum {CODE_WAIT, CODE_ENTER, CODE_ESCAPE } TIMEOUTCODE;
+typedef TIMEOUTCODE (*t_timeout_handler)(void);
+
typedef struct s_menuitem {
const char *item;
const char *status;
t_item_handler handler; // Pointer to function of type menufn
t_action action;
t_itemdata itemdata; // Data depends on action value
+ char shortcut; // one of [A-Za-z0-9] shortcut for this menu item
char index; // Index within the menu array
char parindex; // Index of the menu in which this item appears.
} t_menuitem;
pt_menu menus[MAXMENUS];
const char *title;
t_menusystem_handler handler; // Handler function called every time a menu is re-printed.
+ t_timeout_handler ontimeout; // Timeout handler
+ unsigned int tm_stepsize; // Timeout step size (in milliseconds)
+ unsigned long tm_numsteps; // Time to wait for key press=numsteps * stepsize milliseconds
+
char nummenus;
- char normalattr;
- char reverseattr;
- char inactattr;
- char revinactattr;
- char statusattr;
+ char normalattr[2]; // [0] is non-hlite attr, [1] is hlite attr
+ char reverseattr[2];
+ char inactattr[2];
+ char revinactattr[2];
+ char statusattr[2];
char fillchar;
char fillattr;
char spacechar;
void set_normal_attr(char normal, char selected, char inactivenormal, char inactiveselected);
-void set_status_info(char statusattr, char statline);
+void set_normal_hlite(char normal, char selected, char inactivenormal, char inactiveselected);
+
+void set_status_info(char statusattr, char statushlite, char statline);
void set_title_info(char tfillchar, char titleattr);
void unreg_handler();
+void reg_ontimeout(t_timeout_handler, unsigned int numsteps, unsigned int stepsize);
+// Set timeout handler, set 0 for default values.
+// So stepsize=0 means numsteps is measured in centiseconds.
+void unreg_ontimeout();
+
// Create a new menu and return its position
char add_menu(const char *title); // This pointer value is stored internally
+void set_menu_pos(char row,char col); // Set the position of this menu.
+
// Add item to the "current" menu // pointer values are stored internally
pt_menuitem add_item(const char *item, const char *status, t_action action, const char *data, char itemdata);
-void set_menu_pos(char row,char col); // Set the position of this menu.
+void set_shortcut(char shortcut); // Set the shortcut key for the current item
// Add a separator to the "current" menu
pt_menuitem add_sep();
curr = showmenus(MAIN); // Initial menu is the one with index MAIN
if (curr)
{
- if (curr->action == OPT_EXIT) return 0;
if (curr->action == OPT_RUN)
{
if (syslinux) runcommand(curr->data);