source: trunk/src/opengl/glut/win32_menu.c

Last change on this file was 3086, checked in by sandervl, 25 years ago

update

File size: 11.8 KB
Line 
1/* $Id: win32_menu.c,v 1.6 2000-03-11 17:07:46 sandervl Exp $ */
2/* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. */
3/* Copyright (c) Nate Robins, 1997. */
4
5/* This program is freely distributable without licensing fees
6 and is provided without guarantee or warrantee expressed or
7 implied. This program is -not- in the public domain. */
8
9/* This file completely re-implements glut_menu.c and glut_menu2.c
10 for Win32. Note that neither glut_menu.c nor glut_menu2.c are
11 compiled into Win32 GLUT. */
12
13#include <stdlib.h>
14#include <string.h>
15#include <stdio.h>
16#include <errno.h>
17#include <assert.h>
18
19#include "glutint.h"
20
21void (* GLUTCALLBACK __glutMenuStatusFunc) (int, int, int);
22extern GLUTmenu *__glutMappedMenu;
23extern GLUTwindow *__glutMenuWindow;
24GLUTmenuItem *__glutItemSelected;
25unsigned __glutMenuButton;
26
27static GLUTmenu **menuList = NULL;
28static int menuListSize = 0;
29static UINT uniqueMenuHandler = 1;
30
31/* DEPRICATED, use glutMenuStatusFunc instead. */
32void GLAPIENTRY
33glutMenuStateFunc(GLUTmenuStateCB menuStateFunc)
34{
35 __glutMenuStatusFunc = (GLUTmenuStatusCB) menuStateFunc;
36}
37
38void GLAPIENTRY
39glutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc)
40{
41 __glutMenuStatusFunc = menuStatusFunc;
42}
43
44void
45__glutSetMenu(GLUTmenu * menu)
46{
47 __glutCurrentMenu = menu;
48}
49
50static void
51unmapMenu(GLUTmenu * menu)
52{
53 if (menu->cascade) {
54 unmapMenu(menu->cascade);
55 menu->cascade = NULL;
56 }
57 menu->anchor = NULL;
58 menu->highlighted = NULL;
59}
60
61void
62__glutFinishMenu(Window win, int x, int y)
63{
64
65 unmapMenu(__glutMappedMenu);
66
67 /* XXX Put in a GdiFlush just in case. Probably unnecessary. -mjk */
68 GdiFlush();
69
70 if (__glutMenuStatusFunc) {
71 __glutSetWindow(__glutMenuWindow);
72 __glutSetMenu(__glutMappedMenu);
73
74 /* Setting __glutMappedMenu to NULL permits operations that
75 change menus or destroy the menu window again. */
76 __glutMappedMenu = NULL;
77
78 __glutMenuStatusFunc(GLUT_MENU_NOT_IN_USE, x, y);
79 }
80 /* Setting __glutMappedMenu to NULL permits operations that
81 change menus or destroy the menu window again. */
82 __glutMappedMenu = NULL;
83
84 /* If an item is selected and it is not a submenu trigger,
85 generate menu callback. */
86 if (__glutItemSelected && !__glutItemSelected->isTrigger) {
87 __glutSetWindow(__glutMenuWindow);
88 /* When menu callback is triggered, current menu should be
89 set to the callback menu. */
90 __glutSetMenu(__glutItemSelected->menu);
91 __glutItemSelected->menu->select(__glutItemSelected->value);
92 }
93 __glutMenuWindow = NULL;
94}
95
96static void
97mapMenu(GLUTmenu * menu, int x, int y)
98{
99 TrackPopupMenu(menu->win, TPM_LEFTALIGN |
100 (__glutMenuButton == TPM_RIGHTBUTTON ?
101 TPM_RIGHTBUTTON : TPM_LEFTBUTTON),
102 x, y, 0, __glutCurrentWindow->win, NULL);
103}
104
105void
106__glutStartMenu(GLUTmenu * menu, GLUTwindow * window,
107 int x, int y, int x_win, int y_win)
108{
109 assert(__glutMappedMenu == NULL);
110 __glutMappedMenu = menu;
111 __glutMenuWindow = window;
112 __glutItemSelected = NULL;
113 if (__glutMenuStatusFunc) {
114 __glutSetMenu(menu);
115 __glutSetWindow(window);
116 __glutMenuStatusFunc(GLUT_MENU_IN_USE, x_win, y_win);
117 }
118 mapMenu(menu, x, y);
119}
120
121GLUTmenuItem *
122__glutGetUniqueMenuItem(GLUTmenu * menu, UINT unique)
123{
124 GLUTmenuItem *item;
125 int i;
126
127 i = menu->num;
128 item = menu->list;
129 while (item) {
130 if (item->unique == unique) {
131 return item;
132 }
133 if (item->isTrigger) {
134 GLUTmenuItem *subitem;
135 subitem = __glutGetUniqueMenuItem(menuList[item->value], unique);
136 if (subitem) {
137 return subitem;
138 }
139 }
140 i--;
141 item = item->next;
142 }
143 return NULL;
144}
145
146GLUTmenuItem *
147__glutGetMenuItem(GLUTmenu * menu, Window win, int *which)
148{
149 GLUTmenuItem *item;
150 int i;
151
152 i = menu->num;
153 item = menu->list;
154 while (item) {
155 if (item->win == win) {
156 *which = i;
157 return item;
158 }
159 if (item->isTrigger) {
160 GLUTmenuItem *subitem;
161
162 subitem = __glutGetMenuItem(menuList[item->value],
163 win, which);
164 if (subitem) {
165 return subitem;
166 }
167 }
168 i--;
169 item = item->next;
170 }
171 return NULL;
172}
173
174GLUTmenu *
175__glutGetMenu(Window win)
176{
177 GLUTmenu *menu;
178
179 menu = __glutMappedMenu;
180 while (menu) {
181 if (win == menu->win) {
182 return menu;
183 }
184 menu = menu->cascade;
185 }
186 return NULL;
187}
188
189GLUTmenu *
190__glutGetMenuByNum(int menunum)
191{
192 if (menunum < 1 || menunum > menuListSize) {
193 return NULL;
194 }
195 return menuList[menunum - 1];
196}
197
198static int
199getUnusedMenuSlot(void)
200{
201 int i;
202
203 /* Look for allocated, unused slot. */
204 for (i = 0; i < menuListSize; i++) {
205 if (!menuList[i]) {
206 return i;
207 }
208 }
209 /* Allocate a new slot. */
210 menuListSize++;
211 if (menuList) {
212 menuList = (GLUTmenu **)
213 realloc(menuList, menuListSize * sizeof(GLUTmenu *));
214 } else {
215 /* XXX Some realloc's do not correctly perform a malloc
216 when asked to perform a realloc on a NULL pointer,
217 though the ANSI C library spec requires this. */
218 menuList = (GLUTmenu **) malloc(sizeof(GLUTmenu *));
219 }
220 if (!menuList) {
221 __glutFatalError("out of memory.");
222 }
223 menuList[menuListSize - 1] = NULL;
224 return menuListSize - 1;
225}
226
227static void
228menuModificationError(void)
229{
230 /* XXX Remove the warning after GLUT 3.0. */
231 __glutWarning("The following is a new check for GLUT 3.0; update your code.");
232 __glutFatalError("menu manipulation not allowed while menus in use.");
233}
234
235int GLAPIENTRY
236glutCreateMenu(GLUTselectCB selectFunc)
237{
238 GLUTmenu *menu;
239 int menuid;
240
241 if (__glutMappedMenu) {
242 menuModificationError();
243 }
244 menuid = getUnusedMenuSlot();
245 menu = (GLUTmenu *) malloc(sizeof(GLUTmenu));
246 if (!menu) {
247 __glutFatalError("out of memory.");
248 }
249 menu->id = menuid;
250 menu->num = 0;
251 menu->submenus = 0;
252 menu->select = selectFunc;
253 menu->list = NULL;
254 menu->cascade = NULL;
255 menu->highlighted = NULL;
256 menu->anchor = NULL;
257 menu->win = CreatePopupMenu();
258 menuList[menuid] = menu;
259 __glutSetMenu(menu);
260 return menuid + 1;
261}
262
263void GLAPIENTRY
264glutDestroyMenu(int menunum)
265{
266 GLUTmenu *menu = __glutGetMenuByNum(menunum);
267 GLUTmenuItem *item, *next;
268
269 if (__glutMappedMenu) {
270 menuModificationError();
271 }
272 assert(menu->id == menunum - 1);
273 DestroyMenu(menu->win);
274 menuList[menunum - 1] = NULL;
275 /* free all menu entries */
276 item = menu->list;
277 while (item) {
278 assert(item->menu == menu);
279 next = item->next;
280 free(item->label);
281 free(item);
282 item = next;
283 }
284 if (__glutCurrentMenu == menu) {
285 __glutCurrentMenu = NULL;
286 }
287 free(menu);
288}
289
290int GLAPIENTRY
291glutGetMenu(void)
292{
293 if (__glutCurrentMenu) {
294 return __glutCurrentMenu->id + 1;
295 } else {
296 return 0;
297 }
298}
299
300void GLAPIENTRY
301glutSetMenu(int menuid)
302{
303 GLUTmenu *menu;
304
305 if (menuid < 1 || menuid > menuListSize) {
306 __glutWarning("glutSetMenu attempted on bogus menu.");
307 return;
308 }
309 menu = menuList[menuid - 1];
310 if (!menu) {
311 __glutWarning("glutSetMenu attempted on bogus menu.");
312 return;
313 }
314 __glutSetMenu(menu);
315}
316
317static void
318setMenuItem(GLUTmenuItem * item, const char *label,
319 int value, Bool isTrigger)
320{
321 GLUTmenu *menu;
322
323 menu = item->menu;
324 item->label = __glutStrdup(label);
325 if (!item->label) {
326 __glutFatalError("out of memory.");
327 }
328 item->isTrigger = isTrigger;
329 item->len = (int) strlen(label);
330 item->value = value;
331 item->unique = uniqueMenuHandler++;
332 if (isTrigger) {
333 AppendMenu(menu->win, MF_POPUP, (UINT)item->win, label);
334 } else {
335 AppendMenu(menu->win, MF_STRING, item->unique, label);
336 }
337}
338
339void GLAPIENTRY
340glutAddMenuEntry(const char *label, int value)
341{
342 GLUTmenuItem *entry;
343
344 if (__glutMappedMenu) {
345 menuModificationError();
346 }
347 entry = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
348 if (!entry) {
349 __glutFatalError("out of memory.");
350 }
351 entry->menu = __glutCurrentMenu;
352 setMenuItem(entry, label, value, FALSE);
353 __glutCurrentMenu->num++;
354 entry->next = __glutCurrentMenu->list;
355 __glutCurrentMenu->list = entry;
356}
357
358void GLAPIENTRY
359glutAddSubMenu(const char *label, int menu)
360{
361 GLUTmenuItem *submenu;
362 GLUTmenu *popupmenu;
363
364 if (__glutMappedMenu) {
365 menuModificationError();
366 }
367 submenu = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
368 if (!submenu) {
369 __glutFatalError("out of memory.");
370 }
371 __glutCurrentMenu->submenus++;
372 submenu->menu = __glutCurrentMenu;
373 popupmenu = __glutGetMenuByNum(menu);
374 if (popupmenu) {
375 submenu->win = popupmenu->win;
376 }
377 setMenuItem(submenu, label, /* base 0 */ menu - 1, TRUE);
378 __glutCurrentMenu->num++;
379 submenu->next = __glutCurrentMenu->list;
380 __glutCurrentMenu->list = submenu;
381}
382
383void GLAPIENTRY
384glutChangeToMenuEntry(int num, const char *label, int value)
385{
386 GLUTmenuItem *item;
387 int i;
388
389 if (__glutMappedMenu) {
390 menuModificationError();
391 }
392 i = __glutCurrentMenu->num;
393 item = __glutCurrentMenu->list;
394 while (item) {
395 if (i == num) {
396 if (item->isTrigger) {
397 /* If changing a submenu trigger to a menu entry, we
398 need to account for submenus. */
399 item->menu->submenus--;
400 /* Nuke the Win32 menu. */
401 DestroyMenu(item->win);
402 }
403 free(item->label);
404
405 item->label = strdup(label);
406 if (!item->label)
407 __glutFatalError("out of memory");
408 item->isTrigger = FALSE;
409 item->len = (int) strlen(label);
410 item->value = value;
411 item->unique = uniqueMenuHandler++;
412 ModifyMenu(__glutCurrentMenu->win, (UINT) i - 1,
413 MF_BYPOSITION | MFT_STRING, item->unique, label);
414 return;
415 }
416 i--;
417 item = item->next;
418 }
419 __glutWarning("Current menu has no %d item.", num);
420}
421
422void GLAPIENTRY
423glutChangeToSubMenu(int num, const char *label, int menu)
424{
425 GLUTmenu *popupmenu;
426 GLUTmenuItem *item;
427 int i;
428
429 if (__glutMappedMenu) {
430 menuModificationError();
431 }
432 i = __glutCurrentMenu->num;
433 item = __glutCurrentMenu->list;
434 while (item) {
435 if (i == num) {
436 if (!item->isTrigger) {
437 /* If changing a menu entry to as submenu trigger, we
438 need to account for submenus. */
439 item->menu->submenus++;
440 item->win = CreatePopupMenu();
441 }
442 free(item->label);
443
444 item->label = strdup(label);
445 if (!item->label)
446 __glutFatalError("out of memory");
447 item->isTrigger = TRUE;
448 item->len = (int) strlen(label);
449 item->value = menu - 1;
450 item->unique = uniqueMenuHandler++;
451 popupmenu = __glutGetMenuByNum(menu);
452 if (popupmenu)
453 item->win = popupmenu->win;
454 ModifyMenu(__glutCurrentMenu->win, (UINT) i - 1,
455 MF_BYPOSITION | MF_POPUP, (UINT) item->win, label);
456 return;
457 }
458 i--;
459 item = item->next;
460 }
461 __glutWarning("Current menu has no %d item.", num);
462}
463
464void GLAPIENTRY
465glutRemoveMenuItem(int num)
466{
467 GLUTmenuItem *item, **prev;
468 int i;
469
470 if (__glutMappedMenu) {
471 menuModificationError();
472 }
473 i = __glutCurrentMenu->num;
474 prev = &__glutCurrentMenu->list;
475 item = __glutCurrentMenu->list;
476 while (item) {
477 if (i == num) {
478 /* Found the menu item in list to remove. */
479 __glutCurrentMenu->num--;
480
481 /* Patch up menu's item list. */
482 *prev = item->next;
483
484 RemoveMenu(__glutCurrentMenu->win, (UINT) i - 1, MF_BYPOSITION);
485
486 free(item->label);
487 free(item);
488 return;
489 }
490 i--;
491 prev = &item->next;
492 item = item->next;
493 }
494 __glutWarning("Current menu has no %d item.", num);
495}
496
497void GLAPIENTRY
498glutAttachMenu(int button)
499{
500 if (__glutCurrentWindow == __glutGameModeWindow) {
501 __glutWarning("cannot attach menus in game mode.");
502 return;
503 }
504 if (__glutMappedMenu) {
505 menuModificationError();
506 }
507 if (__glutCurrentWindow->menu[button] < 1) {
508 __glutCurrentWindow->buttonUses++;
509 }
510 __glutCurrentWindow->menu[button] = __glutCurrentMenu->id + 1;
511}
512
513void GLAPIENTRY
514glutDetachMenu(int button)
515{
516 if (__glutMappedMenu) {
517 menuModificationError();
518 }
519 if (__glutCurrentWindow->menu[button] > 0) {
520 __glutCurrentWindow->buttonUses--;
521 __glutCurrentWindow->menu[button] = 0;
522 }
523}
524
Note: See TracBrowser for help on using the repository browser.