// Source: menus.cpp // Author: Michele Estebon // Date: 11/26/96 // For: CS1704: Introduction to Data Structures and Software Design // Last revision: 11/26/96 /************************************************************************ Menuing functions using Curses for PC library // Creates menus based on menu.ini, a file containing the elements/items of // the menus to be created. // Provides calls to /* InitMenus must be called to create a list of menu items on which the functions can operate Resetmwin resets a menu window to highlight the first item and refreshed main window ActivateMenu brings a menu into view MenuUp MenuDn these functions allow the menus to visually represent MenuRt the current menu item. MenuLt SelectionMade resets the active window and returns user option DestroyMenus kills all menu windows and destroys menu list */ /*-- INCLUDES ----------------------------------------------------------*/ #include "menus.h" #include "globals.h" #include #include "curses.h" #include #include #include "display.h" /*-- LOCAL FUNCTION PROTOTYPES ------------------------------------------*/ winptr GetWindow (menus menu); items GetItems (menus menu); void DrawMenubar (winptr &menubar, menus menulist); Boolean CreateMenus (menus &menulist ); Boolean CreateMain (ifstream &infile, menus &menulist ); Boolean CreateSub (ifstream &infile, menus &menulist ) ; Boolean Createmwins (menus &menulist ); items MenuUp (menus currmenu, items); items MenuDn (menus currmenu, items); void MenuRt (menus currmenu, items subitem, winptr &mainwin ); void MenuLt (menus &currmenu, items &subitem, winptr &mainwin, menus menuhead, menus menutoe ); itemkey SelectionMade (winptr &mainwin, menus currmenu, items subitem ); itemkey NoSelection (winptr &mainwin, menus currmenu, items subitem ); void GetLastSub(menus currmenu, items &subitem); void DestroySub (items &sublist ) ; menus SearchMenu (menus menulist, int searchval); //--------------------------------------------------------------------------\\ // FN: menumode // IN: menulist, opstr, mainwin // OUT: // CALLS: // PRE: // POST: //--------------------------------------------------------------------------\\ int menumode( menus menulist, int key, winptr &mainwin, winptr &IOwin ) { menus currmenu = null; int opt; winptr menuwin; items sublist = null; Nobuff(); currmenu = SearchMenu(menulist, key); if (currmenu != null) { menuwin = GetWindow(currmenu); sublist = GetItems(currmenu); if ( (sublist!=null) && (menuwin!=null) ) { ActivateMenu(menuwin); keypad(menuwin,TRUE); opt = wgetch(menuwin); while (opt!=FORCEQUIT) { wrefresh(menuwin); switch (opt) { case KEY_UP: sublist = MenuUp(currmenu,sublist); break; case KEY_DOWN: sublist = MenuDn(currmenu, sublist); break; case KEYRT: No_imp(IOwin); break; case KEYLT: No_imp(IOwin); break; case KEY_DC : return(NoSelection(mainwin, currmenu, sublist)); break; case KEYRETURN:return(SelectionMade(mainwin, currmenu, sublist)); break; default: beep(); } // switch opt opt = wgetch(menuwin); } // while Resetmwin(currmenu); } // if sublist else IOerr(IOwin, NO_OPTIONS); } // if currmenu else IOerr(IOwin, BAD_OPT); Buffin(); return (NO_OPT); } //--------------------------------------------------------------------------\\ // FN: SearchMenu // IN: menulist, opstr, mainwin // OUT: // CALLS: // PRE: // POST: //--------------------------------------------------------------------------\\ menus SearchMenu (menus menulist, int searchval) { menus current = menulist; while (current!=null) { if (current->sub.key == searchval) return (current); current = current->rt; } return (null); } //--------------------------------------------------------------------------\\ // FN: menumode // IN: // OUT: // CALLS: // PRE: // POST: //--------------------------------------------------------------------------\\ winptr GetWindow(menus menu) { return (menu->window); } //--------------------------------------------------------------------------\\ // FN: GetItems // IN: // OUT: // CALLS: // PRE: // POST: //--------------------------------------------------------------------------\\ items GetItems (menus menu) { return (menu->sub.down); } //--------------------------------------------------------------------------\\ // FN: InitMenus // IN: mainwin // OUT: ptr to menulist // CALLS: CreateMenus, Createmwins // PRE: menu.ini must contain necessary menu items in proper format // POST: menu windows are created and ready for a refresh //--------------------------------------------------------------------------\\ Boolean InitMenus( winptr &mainwin, menus &menulist, winptr &menubar ) { if ((CreateMenus(menulist)) && (Createmwins(menulist)) ) { DrawMenubar(menubar, menulist); return (TRUE); } else return (FALSE); } //--------------------------------------------------------------------------\\ // FN: // IN: // OUT: // CALLS: // PRE: // POST: // ****** //--------------------------------------------------------------------------\\ void CustomMenu( winptr &newmenu, int length) { newmenu = newwin(length+1, MAXCHAR+2, FIRSTyPOS, SEEPOS); wattrset(newmenu, B_BLUE | F_GRAY | A_HIGH ); wclear(newmenu); } //--------------------------------------------------------------------------\\ // FN: DrawMenubar // IN: menubar, menulist // OUT: --- // CALLS: mvwaddstr, wrefresh (curses.h) // PRE: menubar window has been initialized and is ready for input // POST: menubar displays main items of menu // ****** Draws main menu items to menubar //--------------------------------------------------------------------------\\ void DrawMenubar(winptr &menubar, menus menulist) { int x = 1; menus list = menulist; wattrset(menubar, B_BLUE | F_GRAY | A_HIGH); wclear(menubar); while (list!=null) { mvwaddstr(menubar, 0,x, list->sub.name); list = list->rt; x += MWIDTH; } wrefresh(menubar); } //--------------------------------------------------------------------------\\ // FN: CreateMenus // IN: menulist // OUT: menulist, boolean fn value (TRUE if successful menu init) // CALLS: CreateMain, CreateSub, open (fstream.h) // PRE: menu.ini must contain necessary menu items in proper format // POST: // Creates menulist from menufile (.ini file) //--------------------------------------------------------------------------\\ Boolean CreateMenus( menus &menulist ) { ifstream infile; Boolean menuOK = TRUE; infile.open( menufile ); if ( (infile) && (CreateMain(infile, menulist)) && (CreateSub(infile, menulist)) ) infile.close(); else menuOK = FALSE; return (menuOK); } //--------------------------------------------------------------------------\\ // FN: CreateMain // IN: infile, menulist // OUT: menulist, boolean fn value (TRUE if successful menu init) // CALLS: strcpy (string.h), atoi ( ) // PRE: menu.ini must contain necessary menu items in proper format // POST: menulist contains main items for menu bar // Creates main menu from menufile (.ini file) //--------------------------------------------------------------------------\\ Boolean CreateMain( ifstream &infile, menus &menulist ) { menus currmenu = menulist; menus newitem; Boolean menuOK = TRUE; string input; while ( (menuOK) && (infile>>input) && (input[0] != TERM) ) { newitem = new mainitem; if (menulist==null) menulist = newitem; newitem->itemcnt = atoi(input); if (infile.getline(input,MAXCHAR)) { strcpy( newitem->sub.name, input ); if (currmenu!=null) { currmenu->rt = newitem; newitem->lt = currmenu; } else newitem->lt = null; newitem->rt = null; newitem->window = null; newitem->sub.up = null; newitem->sub.down = null; currmenu = newitem; } // if infile else menuOK = FALSE; // menu failure } // while infile.ignore(200,'\n'); return (menuOK); } // CreateMain //--------------------------------------------------------------------------\\ // FN: CreateSub // IN: infile, menulist // OUT: menulist, boolean fn value (TRUE if successful menu init) // CALLS: strcpy (string.h) // PRE: menu.ini must contain necessary menu items in proper format // POST: sublist for menus are created // ****** Creates sub menu list from menu.ini //--------------------------------------------------------------------------\\ Boolean CreateSub( ifstream &infile, menus &menulist ) { menus currmenu = menulist; items subitem = null; items newsub = null; Boolean menuOK = TRUE; string input; int count, keyct = 0; while (currmenu != null) { currmenu->sub.key = ++keyct; for (count=0; count < (currmenu->itemcnt); count++) { if (infile.getline(input,MAXCHAR)) { newsub = new (item); strcpy(newsub->name, input); if (count == 0) { currmenu->sub.down = newsub; newsub->up = null; } else { subitem->down = newsub; newsub->up = subitem; } if (newsub->name[0] != DIVIDER) newsub->key = ++keyct; else newsub->key=0; newsub->down = null; newsub->pos = count; } else return (menuOK = FALSE); subitem = newsub; } currmenu = (currmenu->rt); } return (menuOK); } // CreateSub //--------------------------------------------------------------------------\\ // FN: Createmwins // IN: menulist // OUT: menulist // CALLS: Resetmwin, newwin (curses.h) // PRE: menulist contains all items in menu. // POST: main menu items contain ptrs to corresponding menu windows //--------------------------------------------------------------------------\\ Boolean Createmwins( menus &menulist ) { int x = 1; menus currmenu = menulist; winptr win = null; items subitem = null; while (currmenu != null) { win = newwin(currmenu->itemcnt, MAXCHAR+2, FIRSTyPOS, x); if (win == null) return (FALSE); wattrset(win, B_BLUE | F_GRAY | A_HIGH ); wclear(win); currmenu->window = win; Resetmwin(currmenu); x += MAXCHAR+2; currmenu=currmenu->rt; } return (TRUE); } //--------------------------------------------------------------------------\\ // FN: Resetmwin // IN: currmenu, mainwin // OUT: --- // CALLS: mvwaddstr (curses.h), Reversetxt, Normaltxt // PRE: menus have been init'd // POST: current menu window has first item highlighted and ready for refresh. // ***** highlights first menuwin item and "hides" it behind mainwin //--------------------------------------------------------------------------\\ void Resetmwin( menus& currmenu ) { items subitem; winptr win; win = currmenu->window; subitem = currmenu->sub.down; if (subitem != null) { Reversetxt(win); mvwaddstr( win, subitem->pos, 1, subitem->name); subitem = subitem->down; } Normaltxt(win); wattrset(win, B_BLUE | F_GRAY | A_HIGH ); while (subitem != null) { mvwaddstr( win, subitem->pos, 1, subitem->name); subitem = subitem->down; } touchwin(win); } //--------------------------------------------------------------------------\\ // FN: ActivateMenu // IN: currmenu // OUT: --- // CALLS: touchwin (curses.h), wrefresh (curses.h) // PRE: user has chosen to enter menumode // POST: user selected menu is displayed to console // ***** displays current menu window for user manipulation //--------------------------------------------------------------------------\\ void ActivateMenu( winptr &menuwin ) { touchwin(menuwin); wrefresh(menuwin); } //--------------------------------------------------------------------------\\ // FN: MenuUp // IN: win, subitem // OUT: curmenu // CALLS: mvwaddstr, wrefresh (curses.h), Normaltxt, Reversetxt // PRE: Window is activated // POST: Highlighted item in window reflects item pointed to in currmenu // and ptrs are updated. // ***** redraws currmenu item in normal text, moves to previous menuitem // ***** redraws that in highlighted text to (y,x) = (item.pos,currmenu.pos) // ***** and refreshes menu window. //--------------------------------------------------------------------------\\ items MenuUp( menus currmenu , items subitem ) { winptr win; if (subitem != null) { win = currmenu->window; mvwaddstr( win, subitem->pos, 1, subitem->name); subitem = subitem->up; if (subitem == null) GetLastSub( currmenu, subitem ); if (subitem->name[0] == DIVIDER) subitem = subitem->up; Reversetxt(win); mvwaddstr( win, subitem->pos, 1, subitem->name); ResetColors(win, MENUCOLORS); wrefresh(win); } return (subitem); } //--------------------------------------------------------------------------\\ // FN: // IN: // OUT: // CALLS: // PRE: // POST: // ***** //--------------------------------------------------------------------------\\ void GetLastSub(menus currmenu, items &subitem) { subitem = currmenu->sub.down; while (subitem->down!=null) subitem = subitem->down; } //--------------------------------------------------------------------------\\ // FN: MenuDn // IN: currmenu, subitem // OUT: subitem // CALLS: mvwaddstr, touchwin, wrefresh (curses.h), Normaltxt, Reversetxt // PRE: User selected down arrow key. Window has been activated // POST: Highlighted item in window reflects item pointed to in currmenu // and ptrs are updated. // ***** redraws currmenu item in normal text, moves to next menuitem // redraws that in highlighted text to (y,x) = (item.pos,currmenu.pos) // and refreshes menu window. //--------------------------------------------------------------------------\\ items MenuDn( menus currmenu , items subitem ) { winptr win; if (subitem != null) { win = currmenu->window; mvwaddstr( win, subitem->pos, 1, subitem->name); subitem = subitem->down; if (subitem == null) subitem = currmenu->sub.down; if (subitem->name[0] == DIVIDER) subitem = subitem->down; Reversetxt(win); mvwaddstr( win, subitem->pos, 1, subitem->name); ResetColors(win, MENUCOLORS); wrefresh(win); } return (subitem); } //--------------------------------------------------------------------------\\ // FN: MenuRt // IN: curmenu, menuhead, mainwin // OUT: curmenu // CALLS: // PRE: User selected right arrow key. // POST: curr window is reset, next (rt) window has been activated. // and ptrs are updated. // ***** Resets current window, moves to next menuhead item and activates // that window. //--------------------------------------------------------------------------\\ void MenuRt( menus currmenu, items subitem, winptr &mainwin ) { Resetmwin(currmenu); ResetWin(mainwin); currmenu = currmenu->rt; if (currmenu == null) ; // currmenu = menuhead; subitem = currmenu->sub.down; ActivateMenu(currmenu->window); } //--------------------------------------------------------------------------\\ // FN: MenuLt // IN: currmenu, mainwin, menuhead, menutoe // OUT: curmenu, subitem // CALLS: Resetmwin, ResetMain, ActivateMenu // PRE: User selected left arrow key. // POST: curr window is reset, next (left) window has been activated. // and Ptrs are updated // ***** Resets current window, moves to prev menuhead item and activates // that window. //--------------------------------------------------------------------------\\ void MenuLt( menus &currmenu, items &subitem, winptr mainwin, menus menuhead, menus menutoe ) { Resetmwin(currmenu); ResetWin(mainwin); currmenu = currmenu->lt; if (currmenu == null) currmenu = menutoe; subitem = currmenu->sub.down; ActivateMenu(currmenu->window); } //--------------------------------------------------------------------------\\ // FN: SelectionMade // IN: currmenu, mainwin // OUT: fn returns menukey // CALLS: Resetmwin, ResetMain // PRE: user selection == key // POST: curmenu win is reset, refreshes mainwin, returns menukey //--------------------------------------------------------------------------\\ itemkey SelectionMade( winptr &mainwin, menus currmenu, items subitem ) { Resetmwin( currmenu ); return (subitem->key); } //--------------------------------------------------------------------------\\ // FN: NoSelection // IN: menulist, mainwin // OUT: fn returns blank character // CALLS: Resetmwin, ResetMain // PRE: user selection == key // POST: curmenu win is reset, refreshes mainwin, returns menukey //--------------------------------------------------------------------------\\ itemkey NoSelection( winptr &mainwin, menus currmenu, items subitem ) { Resetmwin(currmenu); return (NOCOM); } //--------------------------------------------------------------------------\\ // FN: DestroyMenus (recursive function) // IN: menulist // OUT: // CALLS: DestroySub, DestroyMenus // PRE: --- // POST: menulist is destroyed and menulist set to null. Reference to // menu windows are destroyed //--------------------------------------------------------------------------\\ void DestroyMenus( menus &menulist ) { menus oldmenu = menulist; while (menulist != null) { menulist = menulist->rt; DestroySub(oldmenu->sub.down); if (oldmenu->window!=null) delwin(oldmenu->window); delete oldmenu; oldmenu = menulist; } } //--------------------------------------------------------------------------\\ // FN: DestroySub (recursive function) // IN: sublist // OUT: --- // CALLS: DestroySub, DestroyMenus // PRE: --- // POST: menulist is destroyed and menulist set to null. Reference to // menu windows are destroyed //--------------------------------------------------------------------------\\ void DestroySub( items &sublist ) { items oldsub = sublist; while (sublist != null) { sublist = sublist->down; delete oldsub; oldsub = sublist; } } void ResetColors(winptr &win, int color) { wattroff(win, A_REVERSE); wattrset(win, color); }