📄 menu.c
字号:
break; case PAGEDN: for (i=0; i < 5; i++) curr = next_visible(menu,curr+1); first = calc_first_late(menu,curr); break; case PAGEUP: for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1); first = calc_first_early(menu,curr); break; case UPARROW: curr = prev_visible(menu,curr-1); if (curr < first) first = calc_first_early(menu,curr); break; case DNARROW: curr = next_visible(menu,curr+1); if (! isvisible(menu,first,curr)) first = calc_first_late(menu,curr); 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'))) { tmp = find_shortcut(menu,asc,curr); if ((tmp > curr) && (! isvisible(menu,first,tmp))) first = calc_first_late(menu,tmp); if (tmp < curr) first = calc_first_early(menu,tmp); curr = tmp; } else { if (ms->keys_handler) // Call extra keys handler ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc); } 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, 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 t_handler_return hr; // Return value of handler 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 { printmenu(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); break; case PAGEDN: for (i=0; i < 5; i++) curr = next_visible(menu,curr+1); first = calc_first_late(menu,curr); break; case PAGEUP: for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1); first = calc_first_early(menu,curr); break; case UPARROW: curr = prev_visible(menu,curr-1); if (curr < first) first = calc_first_early(menu,curr); break; case DNARROW: curr = next_visible(menu,curr+1); if (! isvisible(menu,first,curr)) first = calc_first_late(menu,curr); 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 // If we are going into a radio menu, dont call handler, return ci if (ci->action == OPT_RADIOMENU) return ci; if (ci->handler != NULL) // Do we have a handler { hr = ci->handler(ms,ci); if (hr.refresh) // Do we need to refresh { // Cleanup menu using old number of items cleanupmenu(menu,top,left,numitems); // Recalculate the number of items numitems = calc_visible(menu,0); // Reprint the menu printmenu(menu,curr,top,left,first); } if (hr.valid) return ci; } else return ci; break; case SPACEKEY: if (ci->action != OPT_CHECKBOX) break; ci->itemdata.checked = !ci->itemdata.checked; if (ci->handler != NULL) // Do we have a handler { hr = ci->handler(ms,ci); if (hr.refresh) // Do we need to refresh { // Cleanup menu using old number of items cleanupmenu(menu,top,left,numitems); // Recalculate the number of items numitems = calc_visible(menu,0); // Reprint the menu printmenu(menu,curr,top,left,first); } } break; default: // Check if this is a shortcut key if (((asc >= 'A') && (asc <= 'Z')) || ((asc >= 'a') && (asc <= 'z')) || ((asc >= '0') && (asc <= '9'))) { tmp = find_shortcut(menu,asc,curr); if ((tmp > curr) && (! isvisible(menu,first,tmp))) first = calc_first_late(menu,tmp); if (tmp < curr) first = calc_first_early(menu,tmp); curr = tmp; } else { if (ms->keys_handler) // Call extra keys handler ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc); } 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(uchar top, uchar left, pt_menu cmenu, uchar startopt, uchar 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; uchar startat,mt; uchar row,col; if (cmenu == NULL) return NULL; startover: // Set the menu height cmenu->menuheight = ms->maxrow - top-3; if (cmenu->menuheight > ms->maxmenuheight) cmenu->menuheight = ms->maxmenuheight; 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,calc_visible(cmenu,0)); return NULL; } // Are we done with the menu system? if ((opt->action != OPT_SUBMENU) && (opt->action != OPT_RADIOMENU)) { cleanupmenu(cmenu,top,left,calc_visible(cmenu,0)); 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,calc_visible(cmenu,0)); 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); 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,calc_visible(cmenu,0)); return choice; }}/* User Callable functions */pt_menuitem showmenus(uchar startmenu){ pt_menuitem rv; uchar 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;}pt_menusystem init_menusystem(const char *title){ int i; ms = NULL; ms = (pt_menusystem) malloc(sizeof(t_menusystem)); if (ms == NULL) return NULL; ms->nummenus = 0; // Initialise all menu pointers for (i=0; i < MAXMENUS; i++) ms->menus[i] = NULL; ms->title = (char *)malloc(TITLELEN+1); if (title == NULL) strcpy(ms->title,TITLESTR); // Copy string else strcpy(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 // Initialise all handlers ms->handler = NULL; ms->keys_handler = NULL; ms->ontimeout=NULL; // No timeout handler // Setup ACTION_{,IN}VALID ACTION_VALID.valid=1; ACTION_VALID.refresh=0; ACTION_INVALID.valid = 0; ACTION_INVALID.refresh = 0; // 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; // How many entries per menu can we display at a time ms->maxmenuheight = ms->maxrow - ms->minrow - 3; if (ms->maxmenuheight > MAXMENUHEIGHT) ms->maxmenuheight= MAXMENUHEIGHT; // Set up the look of the box set_box_type(MENUBOXTYPE); return ms;}void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected){ if (normal != 0xFF) ms->normalattr[0] = normal; if (selected != 0xFF) ms->reverseattr[0] = selected;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -