/*********************************************************** * Copyright (C) 1997, Be Inc. Copyright (C) 1999, Jake Hamby. * * This program is freely distributable without licensing fees * and is provided without guarantee or warrantee expressed or * implied. This program is -not- in the public domain. * * FILE: glutMenu.cpp * * DESCRIPTION: code for popup menu handling ***********************************************************/ /*********************************************************** * Headers ***********************************************************/ #include #include #include #include "glutint.h" #include "glutState.h" /*********************************************************** * Private variables ***********************************************************/ static GlutMenu **menuList = 0; static int menuListSize = 0; /*********************************************************** * FUNCTION: getUnusedMenuSlot * * DESCRIPTION: helper function to get a new menu slot ***********************************************************/ GlutMenu *__glutGetMenuByNum(int menunum) { if (menunum < 1 || menunum > menuListSize) { return NULL; } return menuList[menunum - 1]; } /*********************************************************** * FUNCTION: getUnusedMenuSlot * * DESCRIPTION: helper function to get a new menu slot ***********************************************************/ static int getUnusedMenuSlot(void) { int i; /* Look for allocated, unused slot. */ for (i = 0; i < menuListSize; i++) { if (!menuList[i]) { return i; } } /* Allocate a new slot. */ menuListSize++; menuList = (GlutMenu **) realloc(menuList, menuListSize * sizeof(GlutMenu *)); if (!menuList) __glutFatalError("out of memory."); menuList[menuListSize - 1] = NULL; return menuListSize - 1; } /*********************************************************** * FUNCTION: glutCreateMenu (6.1) * * DESCRIPTION: create a new menu ***********************************************************/ int APIENTRY glutCreateMenu(GLUTselectCB selectFunc) { GlutMenu *menu; int menuid; menuid = getUnusedMenuSlot(); menu = new GlutMenu(menuid, selectFunc); // constructor sets up members menuList[menuid] = menu; gState.currentMenu = menu; return menuid + 1; } /*********************************************************** * FUNCTION: glutSetMenu (6.2) * glutGetMenu * * DESCRIPTION: set and get the current menu ***********************************************************/ int APIENTRY glutGetMenu(void) { if (gState.currentMenu) { return gState.currentMenu->id + 1; } else { return 0; } } void APIENTRY glutSetMenu(int menuid) { GlutMenu *menu; if (menuid < 1 || menuid > menuListSize) { __glutWarning("glutSetMenu attempted on bogus menu."); return; } menu = menuList[menuid - 1]; if (!menu) { __glutWarning("glutSetMenu attempted on bogus menu."); return; } gState.currentMenu = menu; } /*********************************************************** * FUNCTION: glutDestroyMenu (6.3) * * DESCRIPTION: destroy the specified menu ***********************************************************/ void APIENTRY glutDestroyMenu(int menunum) { GlutMenu *menu = __glutGetMenuByNum(menunum); menuList[menunum - 1] = 0; if (gState.currentMenu == menu) { gState.currentMenu = 0; } delete menu; } /*********************************************************** * FUNCTION: glutAddMenuEntry (6.4) * * DESCRIPTION: add a new menu item ***********************************************************/ void glutAddMenuEntry(const char *label, int value) { new GlutMenuItem(gState.currentMenu, false, value, label); } /*********************************************************** * FUNCTION: glutAddSubMenu (6.5) * * DESCRIPTION: add a new submenu ***********************************************************/ void glutAddSubMenu(const char *label, int menu) { new GlutMenuItem(gState.currentMenu, true, menu-1, label); } /*********************************************************** * FUNCTION: glutChangeToMenuEntry (6.6) * * DESCRIPTION: change menuitem into a menu entry ***********************************************************/ void glutChangeToMenuEntry(int num, const char *label, int value) { GlutMenuItem *item; int i; i = gState.currentMenu->num; item = gState.currentMenu->list; while (item) { if (i == num) { free(item->label); item->label = strdup(label); item->isTrigger = false; item->value = value; return; } i--; item = item->next; } __glutWarning("Current menu has no %d item.", num); } /*********************************************************** * FUNCTION: glutChangeToSubMenu (6.7) * * DESCRIPTION: change menuitem into a submenu ***********************************************************/ void glutChangeToSubMenu(int num, const char *label, int menu) { GlutMenuItem *item; int i; i = gState.currentMenu->num; item = gState.currentMenu->list; while (item) { if (i == num) { free(item->label); item->label = strdup(label); item->isTrigger = true; item->value = menu-1; return; } i--; item = item->next; } __glutWarning("Current menu has no %d item.", num); } /*********************************************************** * FUNCTION: glutRemoveMenuItem (6.8) * * DESCRIPTION: remove a menu item ***********************************************************/ void glutRemoveMenuItem(int num) { GlutMenuItem *item, **prev; int i; i = gState.currentMenu->num; prev = &gState.currentMenu->list; item = gState.currentMenu->list; while (item) { if (i == num) { gState.currentMenu->num--; /* Patch up menu's item list. */ *prev = item->next; free(item->label); delete item; return; } i--; prev = &item->next; item = item->next; } __glutWarning("Current menu has no %d item.", num); } /*********************************************************** * FUNCTION: glutAttachMenu (6.9) * glutDetachMenu * * DESCRIPTION: attach and detach menu from view ***********************************************************/ void glutAttachMenu(int button) { gState.currentWindow->menu[button] = gState.currentMenu->id + 1; } void glutDetachMenu(int button) { gState.currentWindow->menu[button] = 0; } /*********************************************************** * CLASS: GlutMenu * * FUNCTION: CreateBMenu * * DESCRIPTION: construct a BPopupMenu for this menu ***********************************************************/ BMenu *GlutMenu::CreateBMenu(bool toplevel) { BMenu *bpopup; if(toplevel) { bpopup = new GlutPopUp(id+1); } else { bpopup = new BMenu(""); } GlutMenuItem *item = list; while (item) { GlutBMenuItem *bitem; if(item->isTrigger) { // recursively call CreateBMenu bitem = new GlutBMenuItem(menuList[item->value]->CreateBMenu(false)); bitem->SetLabel(item->label); bitem->menu = 0; // real menu items start at 1 bitem->value = 0; } else { bitem = new GlutBMenuItem(item->label); bitem->menu = id + 1; bitem->value = item->value; } bpopup->AddItem(bitem, 0); item = item->next; } return bpopup; } /*********************************************************** * CLASS: GlutMenu * * FUNCTION: (destructor) * * DESCRIPTION: destroy the menu and its items (but not submenus!) ***********************************************************/ GlutMenu::~GlutMenu() { while (list) { GlutMenuItem *next = list->next; delete list; list = next; } } /*********************************************************** * CLASS: GlutMenuItem * * FUNCTION: (constructor) * * DESCRIPTION: construct the new menu item and add to parent ***********************************************************/ GlutMenuItem::GlutMenuItem(GlutMenu *n_menu, bool n_trig, int n_value, const char *n_label) { menu = n_menu; isTrigger = n_trig; value = n_value; label = strdup(n_label); next = menu->list; menu->list = this; menu->num++; }