📄 menu.c
字号:
/* -*- c -*- ------------------------------------------------------------- * * * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, Inc., 53 Temple Place Ste 330, * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */#include "menu.h"#include <stdlib.h>// Local Variablesstatic pt_menusystem ms; // Pointer to the menusystemchar TITLESTR[] = "COMBOOT Menu System for SYSLINUX developed by Murali Krishnan Ganapathy";char TITLELONG[] = " TITLE too long ";char ITEMLONG[] = " ITEM too long ";char ACTIONLONG[] = " ACTION too long ";char STATUSLONG[] = " STATUS too long ";char EMPTYSTR[] = "";/* Forward declarations */int calc_visible(pt_menu menu,int first);int next_visible(pt_menu menu,int index); int prev_visible(pt_menu menu,int index); int next_visible_sep(pt_menu menu,int index); int prev_visible_sep(pt_menu menu,int index); int calc_first_early(pt_menu menu,int curr);int calc_first_late(pt_menu menu,int curr);int isvisible(pt_menu menu,int first, int curr);/* 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,uchar* attr){ uchar page = getdisppage(); uchar 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++; }}int find_shortcut(pt_menu menu,uchar 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}// print the menu starting from FIRST// will print a maximum of menu->menuheight itemsvoid printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first){ 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 uchar *attr; // attribute attr char sep[MENULEN];// and inbetween the item or a seperator is printed 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->menupage, ms->fillchar, ms->shadowattr); drawbox(top-1,left-3,top+numitems,left+menuwidth, ms->menupage,ms->normalattr[NOHLITE],ms->menubt); memset(sep,ms->box_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); 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 lchar[0] = fchar[0] = ' '; lchar[1] = fchar[1] = '\0'; // fchar and lchar are just spaces str = ci->item; // Pointer to item string attr = (x==curr ? ms->reverseattr : ms->normalattr); // Normal attributes switch (ci->action) // set up attr,str,fchar,lchar for everything { case OPT_INACTIVE: attr = (x==curr? ms->revinactattr : ms->inactattr); break; case OPT_SUBMENU: lchar[0] = SUBMENUCHAR; lchar[1] = 0; break; case OPT_RADIOMENU: lchar[0] = RADIOMENUCHAR; lchar[1] = 0; break; case OPT_CHECKBOX: lchar[0] = (ci->itemdata.checked ? CHECKED : UNCHECKED); lchar[1] = 0; break; case OPT_SEP: fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0; lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[2] = 0; str = sep; break; case OPT_EXITMENU: fchar[0] = EXITMENUCHAR; fchar[1] = 0; break; default: // Just to keep the compiler happy break; } gotoxy(top+row,left-2,ms->menupage); cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces gotoxy(top+row,left-2,ms->menupage); csprint(fchar,attr[NOHLITE]); // Print first part gotoxy(top+row,left,ms->menupage); printmenuitem(str,attr); // Print main part gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any csprint(lchar,attr[NOHLITE]); // Print last part } // Check if we need to MOREABOVE and MOREBELOW to be added // reuse x row = 0; x = next_visible_sep(menu,0); // First item if (! isvisible(menu,first,x)) // There is more above { row = 1; gotoxy(top,left+menuwidth,ms->menupage); cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage); } x = prev_visible_sep(menu,menu->numitems); // last item if (! isvisible(menu,first,x)) // There is more above { row = 1; gotoxy(top+numitems-1,left+menuwidth,ms->menupage); cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage); } // Add a scroll box x = ((numitems-1)*curr)/(menu->numitems); if ((x>0) && (row==1)) { gotoxy(top+x,left+menuwidth,ms->menupage); cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage); } if (ms->handler) ms->handler(ms,menu->items[curr]);}// Difference between this and regular menu, is that only // OPT_INVISIBLE, OPT_SEP are honoured void printradiomenu(pt_menu menu, int curr, uchar top, uchar left, int first){ 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 uchar *attr; // all in the attribute attr char sep[MENULEN];// and inbetween the item or a seperator is printed 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->menupage, ms->fillchar, ms->shadowattr); drawbox(top-1,left-3,top+numitems,left+menuwidth, ms->menupage,ms->normalattr[NOHLITE],ms->menubt); memset(sep,ms->box_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); 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; // Setup the defaults now fchar[0] = RADIOUNSEL; fchar[1]='\0'; // Unselected ( ) lchar[0] = '\0'; // Nothing special after str = ci->item; // Pointer to item string attr = ms->normalattr; // Always same attribute fchar[0] = (x==curr ? RADIOSEL : RADIOUNSEL); switch (ci->action) // set up attr,str,fchar,lchar for everything { case OPT_INACTIVE: attr = ms->inactattr; break; case OPT_SEP: fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0; lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[3] = 0; str = sep; break; default: // To keep the compiler happy break; } gotoxy(top+row,left-2,ms->menupage); cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces gotoxy(top+row,left-2,ms->menupage); csprint(fchar,attr[NOHLITE]); // Print first part gotoxy(top+row,left,ms->menupage); printmenuitem(str,attr); // Print main part gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any csprint(lchar,attr[NOHLITE]); // Print last part } // Check if we need to MOREABOVE and MOREBELOW to be added // reuse x row = 0; x = next_visible_sep(menu,0); // First item if (! isvisible(menu,first,x)) // There is more above { row = 1; gotoxy(top,left+menuwidth,ms->menupage); cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage); } x = prev_visible_sep(menu,menu->numitems); // last item if (! isvisible(menu,first,x)) // There is more above { row = 1; gotoxy(top+numitems-1,left+menuwidth,ms->menupage); cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage); } // Add a scroll box x = ((numitems-1)*curr)/(menu->numitems); if ((x > 0) && (row == 1)) { gotoxy(top+x,left+menuwidth,ms->menupage); cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage); } if (ms->handler) ms->handler(ms,menu->items[curr]);}void cleanupmenu(pt_menu menu, uchar top,uchar left,int numitems){ if (numitems > menu->menuheight) numitems = menu->menuheight; clearwindow(top,left-2, top+numitems+1, left+menu->menuwidth+4, ms->menupage, ms->fillchar, ms->fillattr); // Clear the shadow clearwindow(top-1, left-3, top+numitems, left+menu->menuwidth+3, ms->menupage, ms->fillchar, ms->fillattr); // main window}/* Handle a radio menu */pt_menuitem getradiooption(pt_menu menu, uchar top, uchar left, uchar startopt) // Return item chosen or NULL if ESC was hit.{ int curr,i,first,tmp; uchar asc,scan; uchar numitems; pt_menuitem ci; // Current item numitems = calc_visible(menu,0); // Setup status line gotoxy(ms->minrow+ms->statline,ms->mincol,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[NOHLITE],ms->numcols,1); gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); printmenuitem(menu->items[curr]->status,ms->statusattr); first = calc_first_early(menu,curr); while (1) // Forever { printradiomenu(menu,curr,top,left,first); ci = menu->items[curr]; asc = getch(&scan); switch (scan) { case HOMEKEY: curr = next_visible(menu,0); first = calc_first_early(menu,curr); break; case ENDKEY: curr = prev_visible(menu,numitems-1); first = calc_first_late(menu,curr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -