📄 menu.c
字号:
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_CHECKBOX) break; if (ci->action == OPT_SEP) break; if (ci->action == OPT_EXITMENU) return NULL; // As if we hit Esc return ci; break; case SPACEKEY: if (ci->action != OPT_CHECKBOX) break; ci->itemdata.checked = !ci->itemdata.checked; // 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; } // 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 the entire system of menu's. */pt_menuitem runmenusystem(char top, char left, pt_menu cmenu, char startopt, char menutype) /* * cmenu * Which menu should be currently displayed * top,left * What is the position of the top,left corner of the menu * startopt * which menu item do I start with * menutype * NORMALMENU or RADIOMENU * * Return Value: * Returns a pointer to the final item chosen, or NULL if nothing chosen. */{ pt_menuitem opt,choice; char startat,mt; char row,col; if (cmenu == NULL) return NULL; startover: if (menutype == NORMALMENU) opt = getmenuoption(cmenu,top,left,startopt); else // menutype == RADIOMENU opt = getradiooption(cmenu,top,left,startopt); if (opt == NULL) { // User hit Esc cleanupmenu(cmenu,top,left); return NULL; } // Are we done with the menu system? if ((opt->action != OPT_SUBMENU) && (opt->action != OPT_RADIOMENU)) { cleanupmenu(cmenu,top,left); return opt; // parent cleanup other menus } // Either radiomenu or submenu // Do we have a valid menu number? The next hack uses the fact that // itemdata.submenunum = itemdata.radiomenunum (since enum data type) if (opt->itemdata.submenunum >= ms->nummenus) // This is Bad.... { gotoxy(12,12,ms->menupage); // Middle of screen csprint("ERROR: Invalid submenu requested.",0x07); cleanupmenu(cmenu,top,left); return NULL; // Pretend user hit esc } // Call recursively for submenu // Position the submenu below the current item, // covering half the current window (horizontally) row = ms->menus[(unsigned int)opt->itemdata.submenunum]->row; col = ms->menus[(unsigned int)opt->itemdata.submenunum]->col; if (row == 0xFF) row = top+opt->index+2; if (col == 0xFF) col = left+3+(cmenu->menuwidth >> 1); mt = (opt->action == OPT_SUBMENU ? NORMALMENU : RADIOMENU ); startat = 0; if ((opt->action == OPT_RADIOMENU) && (opt->data != NULL)) startat = ((t_menuitem *)opt->data)->index; choice = runmenusystem(row, col, ms->menus[(unsigned int)opt->itemdata.submenunum], startat, mt ); if (opt->action == OPT_RADIOMENU) { if (choice != NULL) opt->data = (void *)choice; // store choice in data field if (opt->handler != NULL) opt->handler(ms,opt); // Call handler choice = NULL; // Pretend user hit esc } if (choice==NULL) // User hit Esc in submenu { // Startover startopt = opt->index; goto startover; } else { cleanupmenu(cmenu,top,left); return choice; }}/* User Callable functions */pt_menuitem showmenus(char startmenu){ pt_menuitem rv; char oldpage,tpos; // Setup screen for menusystem oldpage = getdisppage(); setdisppage(ms->menupage); cls(); clearwindow(ms->minrow, ms->mincol, ms->maxrow, ms->maxcol, ms->menupage, ms->fillchar, ms->fillattr); tpos = (ms->numcols - strlen(ms->title) - 1) >> 1; // center it on line gotoxy(ms->minrow,ms->mincol,ms->menupage); cprint(ms->tfillchar,ms->titleattr,ms->numcols,ms->menupage); gotoxy(ms->minrow,ms->mincol+tpos,ms->menupage); csprint(ms->title,ms->titleattr); cursoroff(); // Doesn't seem to work? // Go, main menu cannot be a radio menu rv = runmenusystem(ms->minrow+MENUROW, ms->mincol+MENUCOL, ms->menus[(unsigned int)startmenu], 0, NORMALMENU); // Hide the garbage we left on the screen cursoron(); if (oldpage == ms->menupage) cls(); else setdisppage(oldpage); // Return user choice return rv;}void init_menusystem(const char *title){ int i; ms = NULL; ms = (pt_menusystem) malloc(sizeof(t_menusystem)); if (ms == NULL) return; ms->nummenus = 0; // Initialise all menu pointers for (i=0; i < MAXMENUS; i++) ms->menus[i] = NULL; if (title == NULL) ms->title = TITLESTR; // Copy pointers else ms->title = title; // 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->statline = STATLINE; ms->tfillchar= TFILLCHAR; ms->titleattr= TITLEATTR; ms->fillchar = FILLCHAR; ms->fillattr = FILLATTR; ms->spacechar= SPACECHAR; ms->shadowattr = SHADOWATTR; 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 ms->minrow = ms->mincol = 0; ms->numcols = getnumcols(); ms->numrows = getnumrows(); ms->maxcol = ms->numcols - 1; ms->maxrow = ms->numrows - 1;}void set_normal_attr(char normal, char selected, char inactivenormal, char 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_normal_hlite(char normal, char selected, char inactivenormal, char inactiveselected){ 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}void set_title_info(char tfillchar, char titleattr){ if (tfillchar != 0xFF) ms->tfillchar = tfillchar; if (titleattr != 0xFF) ms->titleattr = titleattr;}void set_misc_info(char fillchar, char fillattr,char spacechar, char shadowattr){ if (fillchar != 0xFF) ms->fillchar = fillchar; if (fillattr != 0xFF) ms->fillattr = fillattr; if (spacechar != 0xFF) ms->spacechar = spacechar; if (shadowattr!= 0xFF) ms->shadowattr= shadowattr;}void set_window_size(char top, char left, char bot, char right) // Set the window which menusystem should use{ char nr,nc; if ((top > bot) || (left > right)) return; // Sorry no change will happen here nr = getnumrows(); nc = getnumcols(); if (bot >= nr) bot = nr-1; if (right >= nc) right = nc-1; ms->minrow = top; ms->mincol = left; ms->maxrow = bot; ms->maxcol = right; ms->numcols = right - left + 1; ms->numrows = bot - top + 1; if (ms->statline >= ms->numrows) ms->statline = ms->numrows - 1; // Clip statline if need be}void reg_handler( t_menusystem_handler handler){ ms->handler = handler;}void unreg_handler(){ 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; if (menu == NULL) return; ans = 0; for (i=0; i < menu->numitems; i++) if (menu->items[i]->action != OPT_INVISIBLE) ans++; menu->numvisible = ans;}char add_menu(const char *title) // Create a new menu and return its position{ int num,i; pt_menu m; num = ms->nummenus; if (num >= MAXMENUS) return -1; m = NULL; m = (pt_menu) malloc(sizeof(t_menu)); if (m == NULL) return -1; ms->menus[num] = m; m->numitems = 0; m->row = 0xFF; m->col = 0xFF; for (i=0; i < MAXMENUSIZE; i++) m->items[i] = NULL; if (title) { if (strlen(title) > MENULEN - 2) m->title = TITLELONG; else m->title = title; } else m->title = EMPTYSTR; m ->menuwidth = strlen(m->title); ms->nummenus ++; return ms->nummenus - 1;}void set_menu_pos(char row,char col) // Set the position of this menu.{ pt_menu m; m = ms->menus[ms->nummenus-1]; m->row = row; m->col = col;}pt_menuitem add_sep() // Add a separator to current menu{ pt_menuitem mi; pt_menu m; m = (ms->menus[ms->nummenus-1]); mi = NULL; mi = (pt_menuitem) malloc(sizeof(t_menuitem)); if (mi == NULL) return NULL; m->items[(unsigned int)m->numitems] = mi; mi->handler = NULL; // No handler mi->item = mi->status = mi->data = EMPTYSTR; mi->action = OPT_SEP; mi->index = m->numitems++; mi->parindex = ms->nummenus-1; mi->shortcut = 0; return mi;}// Add item to the "current" menupt_menuitem add_item(const char *item, const char *status, t_action action, const char *data, char itemdata) { 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; mi = (pt_menuitem) malloc(sizeof(t_menuitem)); if (mi == NULL) return NULL; m->items[(unsigned int) m->numitems] = mi; mi->handler = NULL; // No handler if (item) { if (strlen(item) > MENULEN - 2) { mi->item = ITEMLONG; } else { mi->item = item; if (strlen(item) > m->menuwidth) m->menuwidth = strlen(item); } } else mi->item = EMPTYSTR; if (status) { if (strlen(status) > STATLEN - 2) { mi->status = STATUSLONG; } else { mi->status = status; } } 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) { mi->data = ACTIONLONG; } else { mi->data = data; } } else mi->data = EMPTYSTR; switch (action) { case OPT_SUBMENU: mi->itemdata.submenunum = itemdata; break; case OPT_CHECKBOX: mi->itemdata.checked = itemdata; break; case OPT_RADIOMENU: mi->itemdata.radiomenunum = itemdata; mi->data = NULL; // No selection made break; default: // to keep the compiler happy break; } mi->index = m->numitems++; mi->parindex = ms->nummenus-1; return mi;}// Set the shortcut key for the current itemvoid 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -