📄 menu.c
字号:
/* -*- c -*- ------------------------------------------------------------- * * * Copyright 2004 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, * Bostom MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- *//* This program can be compiled for DOS with the OpenWatcom compiler * (http://www.openwatcom.org/): * * wcl -3 -osx -mt getargs.c */#include "biosio.h"#include "string.h"#include "menu.h"#include "heap.h"// Local Variablesstatic pt_menusystem ms; // Pointer to the menusystemstatic char TITLESTR[] = "COMBOOT Menu System for SYSLINUX developed by Murali Krishnan Ganapathy";static char TITLELONG[] = " TITLE too long ";static char ITEMLONG[] = " ITEM too long ";static char ACTIONLONG[] = " ACTION too long ";static char STATUSLONG[] = " STATUS too long ";static char EMPTYSTR[] = "";/* 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; // Top border gotoxy(top,left,page); cprint(TOPLEFT,attr,1,page); gotoxy(top,left+1,page); cprint(TOP,attr,right-left,page); gotoxy(top,right,page); cprint(TOPRIGHT,attr,1,page); // Bottom border gotoxy(bot,left,page); cprint(BOTLEFT,attr,1,page); gotoxy(bot,left+1,page); cprint(BOT,attr,right-left,page); gotoxy(bot,right,page); cprint(BOTRIGHT,attr,1,page); // Left & right borders for (x=top+1; x < bot; x++) { gotoxy(x,left,page); cprint(LEFT,attr,1,page); gotoxy(x,right,page); cprint(RIGHT,attr,1,page); }}int next_visible(pt_menu menu, int index) // Return index of next visible{ int ans; if (index < 0) ans = 0 ; else if (index >= menu->numitems) ans = menu->numitems-1; else ans = index; while ((ans < menu->numitems-1) && ((menu->items[ans]->action == OPT_INVISIBLE) || (menu->items[ans]->action == OPT_SEP))) ans++; return ans;}int prev_visible(pt_menu menu, int index) // Return index of next visible{ int ans; if (index < 0) ans = 0; else if (index >= menu->numitems) ans = menu->numitems-1; else ans = index; while ((ans > 0) && ((menu->items[ans]->action == OPT_INVISIBLE) || (menu->items[ans]->action == OPT_SEP))) ans--; 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; // attribute attr char sep[MENULEN];// and inbetween the item or a seperator is printed pt_menuitem ci; calc_visible(menu); numitems = menu->numvisible; 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->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); printmenuitem(menu->title,ms->normalattr); row = -1; // 1 less than inital value of x for (x=0; x < menu->numitems; x++) { ci = menu->items[x]; if (ci->action == OPT_INVISIBLE) continue; row++; // 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] = LTRT; fchar[2] = HORIZ; fchar[3] = HORIZ; fchar[4] = 0; lchar[0] = HORIZ; lchar[1] = 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 } 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, 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 sep[MENULEN];// and inbetween the item or a seperator is printed pt_menuitem ci; calc_visible(menu); numitems = menu->numvisible; 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->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); printmenuitem(menu->title,ms->normalattr); row = -1; // 1 less than inital value of x for (x=0; x < menu->numitems; x++) { ci = menu->items[x]; if (ci->action == OPT_INVISIBLE) continue; row++; // 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] = LTRT; fchar[2] = HORIZ; fchar[3] = HORIZ; fchar[4] = 0; lchar[0] = HORIZ; lchar[1] = 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 } if (ms->handler) ms->handler(ms,menu->items[curr]);}void cleanupmenu(pt_menu menu, char top,char left){ clearwindow(top,left-2, top+menu->numvisible+1, left+menu->menuwidth+4, ms->menupage, ms->fillchar, ms->fillattr); // Clear the shadow clearwindow(top-1, left-3, top+menu->numvisible, left+menu->menuwidth+3, ms->menupage, ms->fillchar, ms->fillattr); // main window}/* Handle a radio menu */pt_menuitem getradiooption(pt_menu menu, char top, char left, char startopt) // Return item chosen or NULL if ESC was hit.{ int curr,i; char asc,scan; char numitems; pt_menuitem ci; // Current item calc_visible(menu); numitems = menu->numvisible; // 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); while (1) // Forever { printradiomenu(menu,curr,top,left); ci = menu->items[curr]; asc = getch(&scan); switch (scan) { case HOMEKEY: curr = next_visible(menu,0); break; case ENDKEY: curr = prev_visible(menu,numitems-1); break; case PAGEDN: for (i=0; i < 5; i++) curr = next_visible(menu,curr+1); break; case PAGEUP: for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1); break; case UPARROW: curr = prev_visible(menu,curr-1); break; case DNARROW: curr = next_visible(menu,curr+1); break; case LTARROW: case ESCAPE: return NULL; break; case RTARROW: case ENTERA: case ENTERB: if (ci->action == OPT_INACTIVE) break; 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; } // Update status line gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage); cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage); printmenuitem(menu->items[curr]->status,ms->statusattr); } return NULL; // Should never come here}/* Handle one menu */pt_menuitem getmenuoption( pt_menu menu, char top, char left, char startopt) // Return item chosen or NULL if ESC was hit.{ int curr,i; char asc,scan; char numitems; pt_menuitem ci; // Current item calc_visible(menu); numitems = menu->numvisible; // 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); while (1) // Forever { printmenu(menu,curr,top,left); ci = menu->items[curr]; asc = getch(&scan); switch (scan) { case HOMEKEY: curr = next_visible(menu,0); break; case ENDKEY: curr = prev_visible(menu,numitems-1); break; case PAGEDN: for (i=0; i < 5; i++) curr = next_visible(menu,curr+1); break; case PAGEUP: for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1); break; case UPARROW:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -