2 /* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. */
3 /* Copyright (c) Nate Robins, 1997. */
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. */
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. */
21 void (GLUTCALLBACK
*__glutMenuStatusFunc
) (int, int, int);
22 //GLUTmenu *__glutMappedMenu;
23 //GLUTwindow *__glutMenuWindow;
24 GLUTmenuItem
*__glutItemSelected
;
25 unsigned __glutMenuButton
;
27 static GLUTmenu
**menuList
= NULL
;
28 static int menuListSize
= 0;
29 static UINT uniqueMenuHandler
= 1;
31 /* DEPRICATED, use glutMenuStatusFunc instead. */
33 glutMenuStateFunc(GLUTmenuStateCB menuStateFunc
)
35 __glutMenuStatusFunc
= (GLUTmenuStatusCB
) menuStateFunc
;
39 glutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc
)
41 __glutMenuStatusFunc
= menuStatusFunc
;
45 __glutSetMenu(GLUTmenu
* menu
)
47 __glutCurrentMenu
= menu
;
51 unmapMenu(GLUTmenu
* menu
)
54 unmapMenu(menu
->cascade
);
58 menu
->highlighted
= NULL
;
62 __glutFinishMenu(Window win
, int x
, int y
)
65 unmapMenu(__glutMappedMenu
);
67 /* XXX Put in a GdiFlush just in case. Probably unnecessary. -mjk */
70 if (__glutMenuStatusFunc
) {
71 __glutSetWindow(__glutMenuWindow
);
72 __glutSetMenu(__glutMappedMenu
);
74 /* Setting __glutMappedMenu to NULL permits operations that
75 change menus or destroy the menu window again. */
76 __glutMappedMenu
= NULL
;
78 __glutMenuStatusFunc(GLUT_MENU_NOT_IN_USE
, x
, y
);
80 /* Setting __glutMappedMenu to NULL permits operations that
81 change menus or destroy the menu window again. */
82 __glutMappedMenu
= NULL
;
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
);
93 __glutMenuWindow
= NULL
;
97 mapMenu(GLUTmenu
* menu
, int x
, int y
)
100 // TrackPopupMenu((HMENU) menu->win, TPM_LEFTALIGN |
101 // (__glutMenuButton == TPM_RIGHTBUTTON) ? TPM_RIGHTBUTTON : TPM_LEFTBUTTON,
102 // x, y, 0, __glutCurrentWindow->win, NULL);
106 __glutStartMenu(GLUTmenu
* menu
, GLUTwindow
* window
,
107 int x
, int y
, int x_win
, int y_win
)
109 assert(__glutMappedMenu
== NULL
);
110 __glutMappedMenu
= menu
;
111 __glutMenuWindow
= window
;
112 __glutItemSelected
= NULL
;
113 if (__glutMenuStatusFunc
) {
115 __glutSetWindow(window
);
116 __glutMenuStatusFunc(GLUT_MENU_IN_USE
, x_win
, y_win
);
122 __glutGetUniqueMenuItem(GLUTmenu
* menu
, UINT unique
)
130 if (item
->unique
== unique
) {
133 if (item
->isTrigger
) {
134 GLUTmenuItem
*subitem
;
135 subitem
= __glutGetUniqueMenuItem(menuList
[item
->value
], unique
);
147 __glutGetMenuItem(GLUTmenu
* menu
, Window win
, int *which
)
155 if (item
->win
== win
) {
159 if (item
->isTrigger
) {
160 GLUTmenuItem
*subitem
;
162 subitem
= __glutGetMenuItem(menuList
[item
->value
],
175 __glutGetMenu(Window win
)
179 menu
= __glutMappedMenu
;
181 if (win
== menu
->win
) {
184 menu
= menu
->cascade
;
190 __glutGetMenuByNum(int menunum
)
192 if (menunum
< 1 || menunum
> menuListSize
) {
195 return menuList
[menunum
- 1];
199 getUnusedMenuSlot(void)
203 /* Look for allocated, unused slot. */
204 for (i
= 0; i
< menuListSize
; i
++) {
209 /* Allocate a new slot. */
212 menuList
= (GLUTmenu
**)
213 realloc(menuList
, menuListSize
* sizeof(GLUTmenu
*));
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
*));
221 __glutFatalError("out of memory.");
223 menuList
[menuListSize
- 1] = NULL
;
224 return menuListSize
- 1;
228 menuModificationError(void)
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.");
236 glutCreateMenu(GLUTselectCB selectFunc
)
241 if (__glutMappedMenu
) {
242 menuModificationError();
244 menuid
= getUnusedMenuSlot();
245 menu
= (GLUTmenu
*) malloc(sizeof(GLUTmenu
));
247 __glutFatalError("out of memory.");
252 menu
->select
= selectFunc
;
254 menu
->cascade
= NULL
;
255 menu
->highlighted
= NULL
;
258 // menu->win = (HWND) CreatePopupMenu();
259 menuList
[menuid
] = menu
;
266 glutDestroyMenu(int menunum
)
268 GLUTmenu
*menu
= __glutGetMenuByNum(menunum
);
269 GLUTmenuItem
*item
, *next
;
271 if (__glutMappedMenu
) {
272 menuModificationError();
274 assert(menu
->id
== menunum
- 1);
275 //todo DestroyMenu( (HMENU) menu->win);
276 menuList
[menunum
- 1] = NULL
;
277 /* free all menu entries */
280 assert(item
->menu
== menu
);
286 if (__glutCurrentMenu
== menu
) {
287 __glutCurrentMenu
= NULL
;
295 if (__glutCurrentMenu
) {
296 return __glutCurrentMenu
->id
+ 1;
303 glutSetMenu(int menuid
)
307 if (menuid
< 1 || menuid
> menuListSize
) {
308 __glutWarning("glutSetMenu attempted on bogus menu.");
311 menu
= menuList
[menuid
- 1];
313 __glutWarning("glutSetMenu attempted on bogus menu.");
320 setMenuItem(GLUTmenuItem
* item
, const char *label
,
321 int value
, Bool isTrigger
)
326 item
->label
= __glutStrdup(label
);
328 __glutFatalError("out of memory.");
330 item
->isTrigger
= isTrigger
;
331 item
->len
= (int) strlen(label
);
333 item
->unique
= uniqueMenuHandler
++;
336 // AppendMenu((HMENU) menu->win, MF_POPUP, (UINT)item->win, label);
338 // AppendMenu((HMENU) menu->win, MF_STRING, item->unique, label);
343 glutAddMenuEntry(const char *label
, int value
)
347 if (__glutMappedMenu
) {
348 menuModificationError();
350 entry
= (GLUTmenuItem
*) malloc(sizeof(GLUTmenuItem
));
352 __glutFatalError("out of memory.");
354 entry
->menu
= __glutCurrentMenu
;
355 setMenuItem(entry
, label
, value
, FALSE
);
356 __glutCurrentMenu
->num
++;
357 entry
->next
= __glutCurrentMenu
->list
;
358 __glutCurrentMenu
->list
= entry
;
362 glutAddSubMenu(const char *label
, int menu
)
364 GLUTmenuItem
*submenu
;
367 if (__glutMappedMenu
) {
368 menuModificationError();
370 submenu
= (GLUTmenuItem
*) malloc(sizeof(GLUTmenuItem
));
372 __glutFatalError("out of memory.");
374 __glutCurrentMenu
->submenus
++;
375 submenu
->menu
= __glutCurrentMenu
;
376 popupmenu
= __glutGetMenuByNum(menu
);
378 submenu
->win
= popupmenu
->win
;
380 setMenuItem(submenu
, label
, /* base 0 */ menu
- 1, TRUE
);
381 __glutCurrentMenu
->num
++;
382 submenu
->next
= __glutCurrentMenu
->list
;
383 __glutCurrentMenu
->list
= submenu
;
387 glutChangeToMenuEntry(int num
, const char *label
, int value
)
392 if (__glutMappedMenu
) {
393 menuModificationError();
395 i
= __glutCurrentMenu
->num
;
396 item
= __glutCurrentMenu
->list
;
399 if (item
->isTrigger
) {
400 /* If changing a submenu trigger to a menu entry, we
401 need to account for submenus. */
402 item
->menu
->submenus
--;
403 /* Nuke the Win32 menu. */
405 // DestroyMenu((HMENU) item->win);
409 item
->label
= strdup(label
);
411 __glutFatalError("out of memory");
412 item
->isTrigger
= FALSE
;
413 item
->len
= (int) strlen(label
);
415 item
->unique
= uniqueMenuHandler
++;
417 // ModifyMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1,
418 // MF_BYPOSITION | MFT_STRING, item->unique, label);
425 __glutWarning("Current menu has no %d item.", num
);
429 glutChangeToSubMenu(int num
, const char *label
, int menu
)
435 if (__glutMappedMenu
) {
436 menuModificationError();
438 i
= __glutCurrentMenu
->num
;
439 item
= __glutCurrentMenu
->list
;
442 if (!item
->isTrigger
) {
443 /* If changing a menu entry to as submenu trigger, we
444 need to account for submenus. */
445 item
->menu
->submenus
++;
447 // item->win = (HWND) CreatePopupMenu();
451 item
->label
= strdup(label
);
453 __glutFatalError("out of memory");
454 item
->isTrigger
= TRUE
;
455 item
->len
= (int) strlen(label
);
456 item
->value
= menu
- 1;
457 item
->unique
= uniqueMenuHandler
++;
458 popupmenu
= __glutGetMenuByNum(menu
);
460 item
->win
= popupmenu
->win
;
462 // ModifyMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1,
463 // MF_BYPOSITION | MF_POPUP, (UINT) item->win, label);
469 __glutWarning("Current menu has no %d item.", num
);
473 glutRemoveMenuItem(int num
)
475 GLUTmenuItem
*item
, **prev
;
478 if (__glutMappedMenu
) {
479 menuModificationError();
481 i
= __glutCurrentMenu
->num
;
482 prev
= &__glutCurrentMenu
->list
;
483 item
= __glutCurrentMenu
->list
;
486 /* Found the menu item in list to remove. */
487 __glutCurrentMenu
->num
--;
489 /* Patch up menu's item list. */
492 // RemoveMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1, MF_BYPOSITION);
502 __glutWarning("Current menu has no %d item.", num
);
506 glutAttachMenu(int button
)
508 if (__glutCurrentWindow
== __glutGameModeWindow
) {
509 __glutWarning("cannot attach menus in game mode.");
512 if (__glutMappedMenu
) {
513 menuModificationError();
515 if (__glutCurrentWindow
->menu
[button
] < 1) {
516 __glutCurrentWindow
->buttonUses
++;
518 __glutCurrentWindow
->menu
[button
] = __glutCurrentMenu
->id
+ 1;
522 glutDetachMenu(int button
)
524 if (__glutMappedMenu
) {
525 menuModificationError();
527 if (__glutCurrentWindow
->menu
[button
] > 0) {
528 __glutCurrentWindow
->buttonUses
--;
529 __glutCurrentWindow
->menu
[button
] = 0;