2f9e6a2c67c27a98298e8b2ad7460366ece00b28
[platform/upstream/mesa.git] / src / glut / beos / glutMenu.cpp
1 /***********************************************************
2  *      Copyright (C) 1997, Be Inc.  Copyright (C) 1999, Jake Hamby.
3  *
4  * This program is freely distributable without licensing fees
5  * and is provided without guarantee or warrantee expressed or
6  * implied. This program is -not- in the public domain.
7  *
8  *  FILE:       glutMenu.cpp
9  *
10  *      DESCRIPTION:    code for popup menu handling
11  ***********************************************************/
12
13 /***********************************************************
14  *      Headers
15  ***********************************************************/
16 #include <GL/glut.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include "glutint.h"
20 #include "glutState.h"
21
22 /***********************************************************
23  *      Private variables
24  ***********************************************************/
25 static GlutMenu **menuList = 0;
26 static int menuListSize = 0;
27
28 /***********************************************************
29  *      FUNCTION:       getUnusedMenuSlot
30  *
31  *      DESCRIPTION:  helper function to get a new menu slot
32  ***********************************************************/
33 GlutMenu *__glutGetMenuByNum(int menunum)
34 {
35   if (menunum < 1 || menunum > menuListSize) {
36     return NULL;
37   }
38   return menuList[menunum - 1];
39 }
40
41 /***********************************************************
42  *      FUNCTION:       getUnusedMenuSlot
43  *
44  *      DESCRIPTION:  helper function to get a new menu slot
45  ***********************************************************/
46 static int
47 getUnusedMenuSlot(void)
48 {
49   int i;
50
51   /* Look for allocated, unused slot. */
52   for (i = 0; i < menuListSize; i++) {
53     if (!menuList[i]) {
54       return i;
55     }
56   }
57   /* Allocate a new slot. */
58   menuListSize++;
59   menuList = (GlutMenu **)
60       realloc(menuList, menuListSize * sizeof(GlutMenu *));
61   if (!menuList)
62     __glutFatalError("out of memory.");
63   menuList[menuListSize - 1] = NULL;
64   return menuListSize - 1;
65 }
66
67 /***********************************************************
68  *      FUNCTION:       glutCreateMenu (6.1)
69  *
70  *      DESCRIPTION:  create a new menu
71  ***********************************************************/
72 int APIENTRY 
73 glutCreateMenu(GLUTselectCB selectFunc)
74 {
75   GlutMenu *menu;
76   int menuid;
77
78   menuid = getUnusedMenuSlot();
79   menu = new GlutMenu(menuid, selectFunc);      // constructor sets up members
80   menuList[menuid] = menu;
81   gState.currentMenu = menu;
82   return menuid + 1;
83 }
84
85 /***********************************************************
86  *      FUNCTION:       glutSetMenu (6.2)
87  *                              glutGetMenu
88  *
89  *      DESCRIPTION:  set and get the current menu
90  ***********************************************************/
91 int APIENTRY 
92 glutGetMenu(void)
93 {
94   if (gState.currentMenu) {
95     return gState.currentMenu->id + 1;
96   } else {
97     return 0;
98   }
99 }
100
101 void APIENTRY 
102 glutSetMenu(int menuid)
103 {
104   GlutMenu *menu;
105
106   if (menuid < 1 || menuid > menuListSize) {
107     __glutWarning("glutSetMenu attempted on bogus menu.");
108     return;
109   }
110   menu = menuList[menuid - 1];
111   if (!menu) {
112     __glutWarning("glutSetMenu attempted on bogus menu.");
113     return;
114   }
115   gState.currentMenu = menu;
116 }
117
118 /***********************************************************
119  *      FUNCTION:       glutDestroyMenu (6.3)
120  *
121  *      DESCRIPTION:  destroy the specified menu
122  ***********************************************************/
123 void APIENTRY 
124 glutDestroyMenu(int menunum)
125 {
126   GlutMenu *menu = __glutGetMenuByNum(menunum);
127   menuList[menunum - 1] = 0;
128   if (gState.currentMenu == menu) {
129     gState.currentMenu = 0;
130   }
131   delete menu;
132 }
133
134 /***********************************************************
135  *      FUNCTION:       glutAddMenuEntry (6.4)
136  *
137  *      DESCRIPTION:  add a new menu item
138  ***********************************************************/
139 void
140 glutAddMenuEntry(const char *label, int value)
141 {
142         new GlutMenuItem(gState.currentMenu, false, value, label);
143 }
144
145 /***********************************************************
146  *      FUNCTION:       glutAddSubMenu (6.5)
147  *
148  *      DESCRIPTION:  add a new submenu
149  ***********************************************************/
150 void
151 glutAddSubMenu(const char *label, int menu)
152 {
153         new GlutMenuItem(gState.currentMenu, true, menu-1, label);
154 }
155
156 /***********************************************************
157  *      FUNCTION:       glutChangeToMenuEntry (6.6)
158  *
159  *      DESCRIPTION:  change menuitem into a menu entry
160  ***********************************************************/
161 void
162 glutChangeToMenuEntry(int num, const char *label, int value)
163 {
164   GlutMenuItem *item;
165   int i;
166
167   i = gState.currentMenu->num;
168   item = gState.currentMenu->list;
169   while (item) {
170     if (i == num) {
171       free(item->label);
172       item->label = strdup(label);
173       item->isTrigger = false;
174       item->value = value;
175       return;
176     }
177     i--;
178     item = item->next;
179   }
180   __glutWarning("Current menu has no %d item.", num);
181 }
182
183 /***********************************************************
184  *      FUNCTION:       glutChangeToSubMenu (6.7)
185  *
186  *      DESCRIPTION:  change menuitem into a submenu
187  ***********************************************************/
188 void
189 glutChangeToSubMenu(int num, const char *label, int menu)
190 {
191   GlutMenuItem *item;
192   int i;
193
194   i = gState.currentMenu->num;
195   item = gState.currentMenu->list;
196   while (item) {
197     if (i == num) {
198       free(item->label);
199       item->label = strdup(label);
200       item->isTrigger = true;
201       item->value = menu-1;
202       return;
203     }
204     i--;
205     item = item->next;
206   }
207   __glutWarning("Current menu has no %d item.", num);
208 }
209
210 /***********************************************************
211  *      FUNCTION:       glutRemoveMenuItem (6.8)
212  *
213  *      DESCRIPTION:  remove a menu item
214  ***********************************************************/
215 void
216 glutRemoveMenuItem(int num)
217 {
218   GlutMenuItem *item, **prev;
219   int i;
220
221   i = gState.currentMenu->num;
222   prev = &gState.currentMenu->list;
223   item = gState.currentMenu->list;
224
225   while (item) {
226     if (i == num) {
227       gState.currentMenu->num--;
228
229       /* Patch up menu's item list. */
230       *prev = item->next;
231
232       free(item->label);
233       delete item;
234       return;
235     }
236     i--;
237     prev = &item->next;
238     item = item->next;
239   }
240   __glutWarning("Current menu has no %d item.", num);
241 }
242
243 /***********************************************************
244  *      FUNCTION:       glutAttachMenu (6.9)
245  *                              glutDetachMenu
246  *
247  *      DESCRIPTION:  attach and detach menu from view
248  ***********************************************************/
249 void
250 glutAttachMenu(int button)
251 {
252         gState.currentWindow->menu[button] = gState.currentMenu->id + 1;
253 }
254
255 void
256 glutDetachMenu(int button)
257 {
258         gState.currentWindow->menu[button] = 0;
259 }
260
261 /***********************************************************
262  *      CLASS:          GlutMenu
263  *
264  *      FUNCTION:       CreateBMenu
265  *
266  *      DESCRIPTION:  construct a BPopupMenu for this menu
267  ***********************************************************/
268 BMenu *GlutMenu::CreateBMenu(bool toplevel) {
269         BMenu *bpopup;
270         if(toplevel) {
271                 bpopup = new GlutPopUp(id+1);
272         } else {
273                 bpopup = new BMenu("");
274         }
275         GlutMenuItem *item = list;
276         while (item) {
277                 GlutBMenuItem *bitem;
278                 if(item->isTrigger) {
279                         // recursively call CreateBMenu
280                         bitem = new GlutBMenuItem(menuList[item->value]->CreateBMenu(false));
281                         bitem->SetLabel(item->label);
282                         bitem->menu = 0;        // real menu items start at 1
283                         bitem->value = 0;
284                 } else {
285                         bitem = new GlutBMenuItem(item->label);
286                         bitem->menu = id + 1;
287                         bitem->value = item->value;
288                 }
289                 bpopup->AddItem(bitem, 0);
290                 item = item->next;
291         }
292         return bpopup;
293 }
294
295 /***********************************************************
296  *      CLASS:          GlutMenu
297  *
298  *      FUNCTION:       (destructor)
299  *
300  *      DESCRIPTION:  destroy the menu and its items (but not submenus!)
301  ***********************************************************/
302 GlutMenu::~GlutMenu() {
303         while (list) {
304                 GlutMenuItem *next = list->next;
305                 delete list;
306                 list = next;
307         }
308 }
309
310 /***********************************************************
311  *      CLASS:          GlutMenuItem
312  *
313  *      FUNCTION:       (constructor)
314  *
315  *      DESCRIPTION:  construct the new menu item and add to parent
316  ***********************************************************/
317 GlutMenuItem::GlutMenuItem(GlutMenu *n_menu, bool n_trig, int n_value, const char *n_label)
318 {
319         menu = n_menu;
320         isTrigger = n_trig;
321         value = n_value;
322         label = strdup(n_label);
323         next = menu->list;
324         menu->list = this;
325         menu->num++;
326 }