softpipe: use the polygon stipple utility module
[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 }