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 GLUTmenuItem
*__glutItemSelected
;
23 unsigned __glutMenuButton
;
25 static GLUTmenu
**menuList
= NULL
;
26 static int menuListSize
= 0;
27 static UINT uniqueMenuHandler
= 1;
29 /* DEPRICATED, use glutMenuStatusFunc instead. */
31 glutMenuStateFunc(GLUTmenuStateCB menuStateFunc
)
33 __glutMenuStatusFunc
= (GLUTmenuStatusCB
) menuStateFunc
;
37 glutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc
)
39 __glutMenuStatusFunc
= menuStatusFunc
;
43 __glutSetMenu(GLUTmenu
* menu
)
45 __glutCurrentMenu
= menu
;
49 unmapMenu(GLUTmenu
* menu
)
52 unmapMenu(menu
->cascade
);
56 menu
->highlighted
= NULL
;
60 __glutFinishMenu(Window win
, int x
, int y
)
63 unmapMenu(__glutMappedMenu
);
65 /* XXX Put in a GdiFlush just in case. Probably unnecessary. -mjk */
68 if (__glutMenuStatusFunc
) {
69 __glutSetWindow(__glutMenuWindow
);
70 __glutSetMenu(__glutMappedMenu
);
72 /* Setting __glutMappedMenu to NULL permits operations that
73 change menus or destroy the menu window again. */
74 __glutMappedMenu
= NULL
;
76 __glutMenuStatusFunc(GLUT_MENU_NOT_IN_USE
, x
, y
);
78 /* Setting __glutMappedMenu to NULL permits operations that
79 change menus or destroy the menu window again. */
80 __glutMappedMenu
= NULL
;
82 /* If an item is selected and it is not a submenu trigger,
83 generate menu callback. */
84 if (__glutItemSelected
&& !__glutItemSelected
->isTrigger
) {
85 __glutSetWindow(__glutMenuWindow
);
86 /* When menu callback is triggered, current menu should be
87 set to the callback menu. */
88 __glutSetMenu(__glutItemSelected
->menu
);
89 __glutItemSelected
->menu
->select(__glutItemSelected
->value
);
91 __glutMenuWindow
= NULL
;
95 mapMenu(GLUTmenu
* menu
, int x
, int y
)
97 TrackPopupMenu((HMENU
) menu
->win
, TPM_LEFTALIGN
|
98 ((__glutMenuButton
== TPM_RIGHTBUTTON
) ? TPM_RIGHTBUTTON
: TPM_LEFTBUTTON
),
99 x
, y
, 0, __glutCurrentWindow
->win
, NULL
);
103 __glutStartMenu(GLUTmenu
* menu
, GLUTwindow
* window
,
104 int x
, int y
, int x_win
, int y_win
)
106 assert(__glutMappedMenu
== NULL
);
107 __glutMappedMenu
= menu
;
108 __glutMenuWindow
= window
;
109 __glutItemSelected
= NULL
;
110 if (__glutMenuStatusFunc
) {
112 __glutSetWindow(window
);
113 __glutMenuStatusFunc(GLUT_MENU_IN_USE
, x_win
, y_win
);
119 __glutGetUniqueMenuItem(GLUTmenu
* menu
, UINT unique
)
127 if (item
->unique
== unique
) {
130 if (item
->isTrigger
) {
131 GLUTmenuItem
*subitem
;
132 subitem
= __glutGetUniqueMenuItem(menuList
[item
->value
], unique
);
144 __glutGetMenuItem(GLUTmenu
* menu
, Window win
, int *which
)
152 if (item
->win
== win
) {
156 if (item
->isTrigger
) {
157 GLUTmenuItem
*subitem
;
159 subitem
= __glutGetMenuItem(menuList
[item
->value
],
172 __glutGetMenu(Window win
)
176 menu
= __glutMappedMenu
;
178 if (win
== menu
->win
) {
181 menu
= menu
->cascade
;
187 __glutGetMenuByNum(int menunum
)
189 if (menunum
< 1 || menunum
> menuListSize
) {
192 return menuList
[menunum
- 1];
196 getUnusedMenuSlot(void)
200 /* Look for allocated, unused slot. */
201 for (i
= 0; i
< menuListSize
; i
++) {
206 /* Allocate a new slot. */
209 menuList
= (GLUTmenu
**)
210 realloc(menuList
, menuListSize
* sizeof(GLUTmenu
*));
212 /* XXX Some realloc's do not correctly perform a malloc
213 when asked to perform a realloc on a NULL pointer,
214 though the ANSI C library spec requires this. */
215 menuList
= (GLUTmenu
**) malloc(sizeof(GLUTmenu
*));
218 __glutFatalError("out of memory.");
220 menuList
[menuListSize
- 1] = NULL
;
221 return menuListSize
- 1;
225 menuModificationError(void)
227 /* XXX Remove the warning after GLUT 3.0. */
228 __glutWarning("The following is a new check for GLUT 3.0; update your code.");
229 __glutFatalError("menu manipulation not allowed while menus in use.");
233 glutCreateMenu(GLUTselectCB selectFunc
)
238 if (__glutMappedMenu
) {
239 menuModificationError();
241 menuid
= getUnusedMenuSlot();
242 menu
= (GLUTmenu
*) malloc(sizeof(GLUTmenu
));
244 __glutFatalError("out of memory.");
249 menu
->select
= selectFunc
;
251 menu
->cascade
= NULL
;
252 menu
->highlighted
= NULL
;
254 menu
->win
= (HWND
) CreatePopupMenu();
255 menuList
[menuid
] = menu
;
261 __glutCreateMenuWithExit(GLUTselectCB selectFunc
, void (__cdecl
*exitfunc
)(int))
263 __glutExitFunc
= exitfunc
;
264 return glutCreateMenu(selectFunc
);
268 glutDestroyMenu(int menunum
)
270 GLUTmenu
*menu
= __glutGetMenuByNum(menunum
);
271 GLUTmenuItem
*item
, *next
;
273 if (__glutMappedMenu
) {
274 menuModificationError();
276 assert(menu
->id
== menunum
- 1);
277 DestroyMenu( (HMENU
) menu
->win
);
278 menuList
[menunum
- 1] = NULL
;
279 /* free all menu entries */
282 assert(item
->menu
== menu
);
288 if (__glutCurrentMenu
== menu
) {
289 __glutCurrentMenu
= NULL
;
297 if (__glutCurrentMenu
) {
298 return __glutCurrentMenu
->id
+ 1;
305 glutSetMenu(int menuid
)
309 if (menuid
< 1 || menuid
> menuListSize
) {
310 __glutWarning("glutSetMenu attempted on bogus menu.");
313 menu
= menuList
[menuid
- 1];
315 __glutWarning("glutSetMenu attempted on bogus menu.");
322 setMenuItem(GLUTmenuItem
* item
, const char *label
,
323 int value
, Bool isTrigger
)
328 item
->label
= __glutStrdup(label
);
330 __glutFatalError("out of memory.");
332 item
->isTrigger
= isTrigger
;
333 item
->len
= (int) strlen(label
);
335 item
->unique
= uniqueMenuHandler
++;
337 AppendMenu((HMENU
) menu
->win
, MF_POPUP
, (UINT
)item
->win
, label
);
339 AppendMenu((HMENU
) menu
->win
, MF_STRING
, item
->unique
, label
);
344 glutAddMenuEntry(const char *label
, int value
)
348 if (__glutMappedMenu
) {
349 menuModificationError();
351 entry
= (GLUTmenuItem
*) malloc(sizeof(GLUTmenuItem
));
353 __glutFatalError("out of memory.");
355 entry
->menu
= __glutCurrentMenu
;
356 setMenuItem(entry
, label
, value
, FALSE
);
357 __glutCurrentMenu
->num
++;
358 entry
->next
= __glutCurrentMenu
->list
;
359 __glutCurrentMenu
->list
= entry
;
363 glutAddSubMenu(const char *label
, int menu
)
365 GLUTmenuItem
*submenu
;
368 if (__glutMappedMenu
) {
369 menuModificationError();
371 submenu
= (GLUTmenuItem
*) malloc(sizeof(GLUTmenuItem
));
373 __glutFatalError("out of memory.");
375 __glutCurrentMenu
->submenus
++;
376 submenu
->menu
= __glutCurrentMenu
;
377 popupmenu
= __glutGetMenuByNum(menu
);
379 submenu
->win
= popupmenu
->win
;
381 setMenuItem(submenu
, label
, /* base 0 */ menu
- 1, TRUE
);
382 __glutCurrentMenu
->num
++;
383 submenu
->next
= __glutCurrentMenu
->list
;
384 __glutCurrentMenu
->list
= submenu
;
388 glutChangeToMenuEntry(int num
, const char *label
, int value
)
393 if (__glutMappedMenu
) {
394 menuModificationError();
396 i
= __glutCurrentMenu
->num
;
397 item
= __glutCurrentMenu
->list
;
400 if (item
->isTrigger
) {
401 /* If changing a submenu trigger to a menu entry, we
402 need to account for submenus. */
403 item
->menu
->submenus
--;
404 /* 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
++;
416 ModifyMenu((HMENU
) __glutCurrentMenu
->win
, (UINT
) i
- 1,
417 MF_BYPOSITION
| MFT_STRING
, item
->unique
, label
);
424 __glutWarning("Current menu has no %d item.", num
);
428 glutChangeToSubMenu(int num
, const char *label
, int menu
)
434 if (__glutMappedMenu
) {
435 menuModificationError();
437 i
= __glutCurrentMenu
->num
;
438 item
= __glutCurrentMenu
->list
;
441 if (!item
->isTrigger
) {
442 /* If changing a menu entry to as submenu trigger, we
443 need to account for submenus. */
444 item
->menu
->submenus
++;
445 item
->win
= (HWND
) CreatePopupMenu();
449 item
->label
= strdup(label
);
451 __glutFatalError("out of memory");
452 item
->isTrigger
= TRUE
;
453 item
->len
= (int) strlen(label
);
454 item
->value
= menu
- 1;
455 item
->unique
= uniqueMenuHandler
++;
456 popupmenu
= __glutGetMenuByNum(menu
);
458 item
->win
= popupmenu
->win
;
459 ModifyMenu((HMENU
) __glutCurrentMenu
->win
, (UINT
) i
- 1,
460 MF_BYPOSITION
| MF_POPUP
, (UINT
) item
->win
, label
);
466 __glutWarning("Current menu has no %d item.", num
);
470 glutRemoveMenuItem(int num
)
472 GLUTmenuItem
*item
, **prev
;
475 if (__glutMappedMenu
) {
476 menuModificationError();
478 i
= __glutCurrentMenu
->num
;
479 prev
= &__glutCurrentMenu
->list
;
480 item
= __glutCurrentMenu
->list
;
483 /* Found the menu item in list to remove. */
484 __glutCurrentMenu
->num
--;
486 /* Patch up menu's item list. */
489 RemoveMenu((HMENU
) __glutCurrentMenu
->win
, (UINT
) i
- 1, MF_BYPOSITION
);
499 __glutWarning("Current menu has no %d item.", num
);
503 glutAttachMenu(int button
)
505 if (__glutCurrentWindow
== __glutGameModeWindow
) {
506 __glutWarning("cannot attach menus in game mode.");
509 if (__glutMappedMenu
) {
510 menuModificationError();
512 if (__glutCurrentWindow
->menu
[button
] < 1) {
513 __glutCurrentWindow
->buttonUses
++;
515 __glutCurrentWindow
->menu
[button
] = __glutCurrentMenu
->id
+ 1;
519 glutDetachMenu(int button
)
521 if (__glutMappedMenu
) {
522 menuModificationError();
524 if (__glutCurrentWindow
->menu
[button
] > 0) {
525 __glutCurrentWindow
->buttonUses
--;
526 __glutCurrentWindow
->menu
[button
] = 0;