1c041511dScube
2c041511dScube/* Copyright (c) Mark J. Kilgard, 1994, 1997. */
3c041511dScube
4c041511dScube/* This program is freely distributable without licensing fees
5c041511dScube   and is provided without guarantee or warrantee expressed or
6c041511dScube   implied. This program is -not- in the public domain. */
7c041511dScube
8c041511dScube/* glut_menu2.c implements the little used GLUT menu calls in
9c041511dScube   a distinct file from glut_menu.c for slim static linking. */
10c041511dScube
11c041511dScube/* The Win32 GLUT file win32_menu.c completely re-implements all
12c041511dScube   the menuing functionality implemented.  This file is used only by
13c041511dScube   the X Window System version of GLUT. */
14c041511dScube
15c041511dScube#ifdef __VMS
16c041511dScube#include <GL/vms_x_fix.h>
17c041511dScube#endif
18c041511dScube
19c041511dScube#include <stdlib.h>
20c041511dScube#include <string.h>
21c041511dScube#include <stdio.h>
22c041511dScube#include <errno.h>
23c041511dScube#include <assert.h>
24c041511dScube
25c041511dScube#include <X11/Xlib.h>
26c041511dScube
27c041511dScube#include "glutint.h"
28c041511dScube
29c041511dScube/* CENTRY */
30c041511dScube/* DEPRICATED, use glutMenuStatusFunc instead. */
31c041511dScubevoid GLUTAPIENTRY
32c041511dScubeglutMenuStateFunc(GLUTmenuStateCB menuStateFunc)
33c041511dScube{
34c041511dScube  __glutMenuStatusFunc = (GLUTmenuStatusCB) menuStateFunc;
35c041511dScube}
36c041511dScube
37c041511dScubevoid GLUTAPIENTRY
38c041511dScubeglutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc)
39c041511dScube{
40c041511dScube  __glutMenuStatusFunc = menuStatusFunc;
41c041511dScube}
42c041511dScube
43c041511dScubevoid GLUTAPIENTRY
44c041511dScubeglutDestroyMenu(int menunum)
45c041511dScube{
46c041511dScube  GLUTmenu *menu = __glutGetMenuByNum(menunum);
47c041511dScube  GLUTmenuItem *item, *next;
48c041511dScube
49c041511dScube  if (__glutMappedMenu)
50c041511dScube    __glutMenuModificationError();
51c041511dScube  assert(menu->id == menunum - 1);
52c041511dScube  XDestroySubwindows(__glutDisplay, menu->win);
53c041511dScube  XDestroyWindow(__glutDisplay, menu->win);
54c041511dScube  __glutMenuList[menunum - 1] = NULL;
55c041511dScube  /* free all menu entries */
56c041511dScube  item = menu->list;
57c041511dScube  while (item) {
58c041511dScube    assert(item->menu == menu);
59c041511dScube    next = item->next;
60c041511dScube    free(item->label);
61c041511dScube    free(item);
62c041511dScube    item = next;
63c041511dScube  }
64c041511dScube  if (__glutCurrentMenu == menu) {
65c041511dScube    __glutCurrentMenu = NULL;
66c041511dScube  }
67c041511dScube  free(menu);
68c041511dScube}
69c041511dScube
70c041511dScubevoid GLUTAPIENTRY
71c041511dScubeglutChangeToMenuEntry(int num, const char *label, int value)
72c041511dScube{
73c041511dScube  GLUTmenuItem *item;
74c041511dScube  int i;
75c041511dScube
76c041511dScube  if (__glutMappedMenu)
77c041511dScube    __glutMenuModificationError();
78c041511dScube  i = __glutCurrentMenu->num;
79c041511dScube  item = __glutCurrentMenu->list;
80c041511dScube  while (item) {
81c041511dScube    if (i == num) {
82c041511dScube      if (item->isTrigger) {
83c041511dScube        /* If changing a submenu trigger to a menu entry, we
84c041511dScube           need to account for submenus.  */
85c041511dScube        item->menu->submenus--;
86c041511dScube      }
87c041511dScube      free(item->label);
88c041511dScube      __glutSetMenuItem(item, label, value, False);
89c041511dScube      return;
90c041511dScube    }
91c041511dScube    i--;
92c041511dScube    item = item->next;
93c041511dScube  }
94c041511dScube  __glutWarning("Current menu has no %d item.", num);
95c041511dScube}
96c041511dScube
97c041511dScubevoid GLUTAPIENTRY
98c041511dScubeglutChangeToSubMenu(int num, const char *label, int menu)
99c041511dScube{
100c041511dScube  GLUTmenuItem *item;
101c041511dScube  int i;
102c041511dScube
103c041511dScube  if (__glutMappedMenu)
104c041511dScube    __glutMenuModificationError();
105c041511dScube  i = __glutCurrentMenu->num;
106c041511dScube  item = __glutCurrentMenu->list;
107c041511dScube  while (item) {
108c041511dScube    if (i == num) {
109c041511dScube      if (!item->isTrigger) {
110c041511dScube        /* If changing a menu entry to as submenu trigger, we
111c041511dScube           need to account for submenus.  */
112c041511dScube        item->menu->submenus++;
113c041511dScube      }
114c041511dScube      free(item->label);
115c041511dScube      __glutSetMenuItem(item, label, /* base 0 */ menu - 1, True);
116c041511dScube      return;
117c041511dScube    }
118c041511dScube    i--;
119c041511dScube    item = item->next;
120c041511dScube  }
121c041511dScube  __glutWarning("Current menu has no %d item.", num);
122c041511dScube}
123c041511dScube
124c041511dScubevoid GLUTAPIENTRY
125c041511dScubeglutRemoveMenuItem(int num)
126c041511dScube{
127c041511dScube  GLUTmenuItem *item, **prev, *remaining;
128c041511dScube  int pixwidth, i;
129c041511dScube
130c041511dScube  if (__glutMappedMenu)
131c041511dScube    __glutMenuModificationError();
132c041511dScube  i = __glutCurrentMenu->num;
133c041511dScube  prev = &__glutCurrentMenu->list;
134c041511dScube  item = __glutCurrentMenu->list;
135c041511dScube  /* If menu item is removed, the menu's pixwidth may need to
136c041511dScube     be recomputed. */
137c041511dScube  pixwidth = 1;
138c041511dScube  while (item) {
139c041511dScube    if (i == num) {
140c041511dScube      /* If this menu item's pixwidth is as wide as the menu's
141c041511dScube         pixwidth, removing this menu item will necessitate
142c041511dScube         shrinking the menu's pixwidth. */
143c041511dScube      if (item->pixwidth >= __glutCurrentMenu->pixwidth) {
144c041511dScube        /* Continue recalculating menu pixwidth, first skipping
145c041511dScube           the removed item. */
146c041511dScube        remaining = item->next;
147c041511dScube        while (remaining) {
148c041511dScube          if (remaining->pixwidth > pixwidth) {
149c041511dScube            pixwidth = remaining->pixwidth;
150c041511dScube          }
151c041511dScube          remaining = remaining->next;
152c041511dScube        }
153c041511dScube        __glutCurrentMenu->pixwidth = pixwidth;
154c041511dScube      }
155c041511dScube      __glutCurrentMenu->num--;
156c041511dScube      __glutCurrentMenu->managed = False;
157c041511dScube
158c041511dScube      /* Patch up menu's item list. */
159c041511dScube      *prev = item->next;
160c041511dScube
161c041511dScube      free(item->label);
162c041511dScube      free(item);
163c041511dScube      return;
164c041511dScube    }
165c041511dScube    if (item->pixwidth > pixwidth) {
166c041511dScube      pixwidth = item->pixwidth;
167c041511dScube    }
168c041511dScube    i--;
169c041511dScube    prev = &item->next;
170c041511dScube    item = item->next;
171c041511dScube  }
172c041511dScube  __glutWarning("Current menu has no %d item.", num);
173c041511dScube}
174c041511dScube
175c041511dScubevoid GLUTAPIENTRY
176c041511dScubeglutDetachMenu(int button)
177c041511dScube{
178c041511dScube  if (__glutMappedMenu)
179c041511dScube    __glutMenuModificationError();
180c041511dScube  if (__glutCurrentWindow->menu[button] > 0) {
181c041511dScube    __glutCurrentWindow->buttonUses--;
182c041511dScube    __glutChangeWindowEventMask(ButtonPressMask | ButtonReleaseMask,
183c041511dScube      __glutCurrentWindow->buttonUses > 0);
184c041511dScube    __glutCurrentWindow->menu[button] = 0;
185c041511dScube  }
186c041511dScube}
187c041511dScube
188c041511dScube/* ENDCENTRY */
189