00001
00002
00003
00004
00005
00006
00007
00008 #include <stdlib.h>
00009 #include <string.h>
00010 #include <stdio.h>
00011 #include <errno.h>
00012 #include <unistd.h>
00013 #include <assert.h>
00014
00015 #include <X11/Xlib.h>
00016 #include <X11/cursorfont.h>
00017
00018 #include <GL/glut.h>
00019 #include "glutint.h"
00020 #include "layerutil.h"
00021
00022 GLUTmenu *__glutCurrentMenu = NULL;
00023 void (*__glutMenuStatusFunc) (int, int, int);
00024 GLUTmenu *__glutMappedMenu;
00025 GLUTwindow *__glutMenuWindow;
00026 GLUTmenuItem *__glutItemSelected;
00027
00028 static GLUTmenu **menuList = NULL;
00029 static int menuListSize = 0;
00030 static XFontStruct *menuFont = NULL;
00031 static Cursor menuCursor;
00032 static Colormap menuColormap;
00033 static Visual *menuVisual;
00034 static int menuDepth;
00035 static int fontHeight;
00036 static GC blackGC, grayGC, whiteGC;
00037 static unsigned long menuBlack, menuWhite, menuGray;
00038 static unsigned long useSaveUnders;
00039
00040
00041
00042
00043
00044
00045 static void
00046 noFaultXAllocColor(Display * dpy, Colormap cmap, int cmapSize,
00047 XColor * color)
00048 {
00049 XColor *ctable, subColor;
00050 int i, bestmatch;
00051 double mindist;
00052
00053
00054 for (;;) {
00055
00056 if (XAllocColor(dpy, cmap, color))
00057 return;
00058
00059
00060
00061 ctable = (XColor *) malloc(cmapSize * sizeof(XColor));
00062 for (i = 0; i < cmapSize; i++)
00063 ctable[i].pixel = i;
00064 XQueryColors(dpy, cmap, ctable, cmapSize);
00065
00066
00067 bestmatch = -1;
00068 mindist = 0.0;
00069 for (i = 0; i < cmapSize; i++) {
00070 double dr = (double) color->red - (double) ctable[i].red;
00071 double dg = (double) color->green - (double) ctable[i].green;
00072 double db = (double) color->blue - (double) ctable[i].blue;
00073 double dist = dr * dr + dg * dg + db * db;
00074 if (bestmatch < 0 || dist < mindist) {
00075 bestmatch = i;
00076 mindist = dist;
00077 }
00078 }
00079
00080
00081 subColor.red = ctable[bestmatch].red;
00082 subColor.green = ctable[bestmatch].green;
00083 subColor.blue = ctable[bestmatch].blue;
00084 free(ctable);
00085 if (XAllocColor(dpy, cmap, &subColor)) {
00086 *color = subColor;
00087 return;
00088 }
00089
00090
00091
00092
00093 }
00094 }
00095
00096 static void
00097 menuVisualSetup(void)
00098 {
00099 XLayerVisualInfo template, *visual, *overlayVisuals;
00100 XColor color;
00101 Status status;
00102 Bool presumablyMesa;
00103 int layer, nVisuals, i, dummy;
00104
00105 for (layer = 3; layer > 0; layer--) {
00106 template.layer = layer;
00107 template.vinfo.screen = __glutScreen;
00108 overlayVisuals = __glutXGetLayerVisualInfo(__glutDisplay,
00109 VisualScreenMask | VisualLayerMask, &template, &nVisuals);
00110 if (overlayVisuals) {
00111 for (i = 0; i < nVisuals; i++) {
00112 visual = &overlayVisuals[i];
00113 if (visual->vinfo.colormap_size >= 3) {
00114 menuColormap = XCreateColormap(__glutDisplay, __glutRoot,
00115 visual->vinfo.visual, AllocNone);
00116
00117
00118
00119
00120
00121
00122 color.red = color.green = color.blue = 0xaa00;
00123 status = XAllocColor(__glutDisplay,
00124 menuColormap, &color);
00125 if (!status) {
00126 XFreeColormap(__glutDisplay, menuColormap);
00127 continue;
00128 }
00129 menuGray = color.pixel;
00130 color.red = color.green = color.blue = 0x0000;
00131 status = XAllocColor(__glutDisplay,
00132 menuColormap, &color);
00133 if (!status) {
00134 XFreeColormap(__glutDisplay, menuColormap);
00135 continue;
00136 }
00137 menuBlack = color.pixel;
00138 color.red = color.green = color.blue = 0xffff;
00139 status = XAllocColor(__glutDisplay,
00140 menuColormap, &color);
00141 if (!status) {
00142 XFreeColormap(__glutDisplay, menuColormap);
00143 continue;
00144 }
00145 menuWhite = color.pixel;
00146 menuVisual = visual->vinfo.visual;
00147 menuDepth = visual->vinfo.depth;
00148
00149
00150 useSaveUnders = 0;
00151 XFree(overlayVisuals);
00152 return;
00153 }
00154 }
00155 XFree(overlayVisuals);
00156 }
00157 }
00158
00159 menuVisual = DefaultVisual(__glutDisplay, __glutScreen);
00160 menuDepth = DefaultDepth(__glutDisplay, __glutScreen);
00161 menuColormap = DefaultColormap(__glutDisplay, __glutScreen);
00162 menuBlack = BlackPixel(__glutDisplay, __glutScreen);
00163 menuWhite = WhitePixel(__glutDisplay, __glutScreen);
00164 color.red = color.green = color.blue = 0xaa00;
00165 noFaultXAllocColor(__glutDisplay, menuColormap,
00166 menuVisual->map_entries, &color);
00167 menuGray = color.pixel;
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 presumablyMesa = !XQueryExtension(__glutDisplay, "GLX",
00193 &dummy, &dummy, &dummy);
00194
00195 if (presumablyMesa)
00196 useSaveUnders = CWSaveUnder;
00197 else
00198 useSaveUnders = 0;
00199 }
00200
00201 static void
00202 menuSetup(void)
00203 {
00204 if (menuFont) {
00205
00206 return;
00207 }
00208 menuFont = XLoadQueryFont(__glutDisplay,
00209 "-*-helvetica-bold-o-normal--14-*-*-*-p-*-iso8859-1");
00210 if (!menuFont) {
00211
00212 menuFont = XLoadQueryFont(__glutDisplay, "fixed");
00213 }
00214 if (!menuFont) {
00215 __glutFatalError("could not load font.");
00216 }
00217 menuVisualSetup();
00218 fontHeight = menuFont->ascent + menuFont->descent;
00219 menuCursor = XCreateFontCursor(__glutDisplay, XC_arrow);
00220 }
00221
00222 static void
00223 menuGraphicsContextSetup(Window win)
00224 {
00225 XGCValues gcvals;
00226
00227 if (blackGC != None)
00228 return;
00229 gcvals.font = menuFont->fid;
00230 gcvals.foreground = menuBlack;
00231 blackGC = XCreateGC(__glutDisplay, win,
00232 GCFont | GCForeground, &gcvals);
00233 gcvals.foreground = menuGray;
00234 grayGC = XCreateGC(__glutDisplay, win, GCForeground, &gcvals);
00235 gcvals.foreground = menuWhite;
00236 whiteGC = XCreateGC(__glutDisplay, win, GCForeground, &gcvals);
00237 }
00238
00239
00240 void
00241 glutMenuStateFunc(GLUTmenuStateCB menuStateFunc)
00242 {
00243 __glutMenuStatusFunc = (GLUTmenuStatusCB) menuStateFunc;
00244 }
00245
00246 void
00247 glutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc)
00248 {
00249 __glutMenuStatusFunc = menuStatusFunc;
00250 }
00251
00252 void
00253 __glutSetMenu(GLUTmenu * menu)
00254 {
00255 __glutCurrentMenu = menu;
00256 }
00257
00258 static void
00259 unmapMenu(GLUTmenu * menu)
00260 {
00261 if (menu->cascade) {
00262 unmapMenu(menu->cascade);
00263 menu->cascade = NULL;
00264 }
00265 menu->anchor = NULL;
00266 menu->highlighted = NULL;
00267 XUnmapWindow(__glutDisplay, menu->win);
00268 }
00269
00270 void
00271 __glutFinishMenu(Window win, int x, int y)
00272 {
00273 Window dummy;
00274 int rc;
00275
00276 unmapMenu(__glutMappedMenu);
00277 XUngrabPointer(__glutDisplay, CurrentTime);
00278
00279
00280
00281
00282
00283
00284
00285 XFlush(__glutDisplay);
00286
00287 if (__glutMenuStatusFunc) {
00288 if (win != __glutMenuWindow->win) {
00289
00290
00291
00292
00293
00294 rc = XTranslateCoordinates(__glutDisplay, win, __glutMenuWindow->win,
00295 x, y, &x, &y, &dummy);
00296 assert(rc != False);
00297 }
00298 __glutSetWindow(__glutMenuWindow);
00299 __glutSetMenu(__glutMappedMenu);
00300
00301
00302
00303 __glutMappedMenu = NULL;
00304
00305 __glutMenuStatusFunc(GLUT_MENU_NOT_IN_USE, x, y);
00306 }
00307
00308
00309 __glutMappedMenu = NULL;
00310
00311
00312
00313 if (__glutItemSelected && !__glutItemSelected->isTrigger) {
00314 __glutSetWindow(__glutMenuWindow);
00315
00316
00317 __glutSetMenu(__glutItemSelected->menu);
00318 __glutItemSelected->menu->select(
00319 __glutItemSelected->value);
00320 }
00321 __glutMenuWindow = NULL;
00322 }
00323
00324 #define MENU_BORDER 1
00325 #define MENU_GAP 2
00326 #define MENU_ARROW_GAP 6
00327 #define MENU_ARROW_WIDTH 8
00328
00329 static void
00330 mapMenu(GLUTmenu * menu, int x, int y)
00331 {
00332 XWindowChanges changes;
00333 unsigned int mask;
00334 int subMenuExtension, num;
00335
00336
00337
00338 if (menu->submenus > 0) {
00339 subMenuExtension = MENU_ARROW_GAP + MENU_ARROW_WIDTH;
00340 } else {
00341 subMenuExtension = 0;
00342 }
00343
00344 changes.stack_mode = Above;
00345 mask = CWStackMode | CWX | CWY;
00346
00347
00348 if (!menu->managed) {
00349 GLUTmenuItem *item;
00350
00351 item = menu->list;
00352 num = menu->num;
00353 while (item) {
00354 XWindowChanges itemupdate;
00355
00356 itemupdate.y = (num - 1) * fontHeight + MENU_GAP;
00357 itemupdate.width = menu->pixwidth;
00358 itemupdate.width += subMenuExtension;
00359 XConfigureWindow(__glutDisplay, item->win,
00360 CWWidth | CWY, &itemupdate);
00361 item = item->next;
00362 num--;
00363 }
00364 menu->pixheight = MENU_GAP +
00365 fontHeight * menu->num + MENU_GAP;
00366 changes.height = menu->pixheight;
00367 changes.width = MENU_GAP +
00368 menu->pixwidth + subMenuExtension + MENU_GAP;
00369 mask |= CWWidth | CWHeight;
00370 menu->managed = True;
00371 }
00372
00373 if (y + menu->pixheight >= __glutScreenHeight) {
00374 changes.y = __glutScreenHeight - menu->pixheight;
00375 } else {
00376 changes.y = y;
00377 }
00378 if (x + menu->pixwidth + subMenuExtension >=
00379 __glutScreenWidth) {
00380 changes.x = __glutScreenWidth -
00381 menu->pixwidth + subMenuExtension;
00382 } else {
00383 changes.x = x;
00384 }
00385
00386
00387
00388 menu->x = changes.x;
00389 menu->y = changes.y;
00390
00391 XConfigureWindow(__glutDisplay, menu->win, mask, &changes);
00392 XInstallColormap(__glutDisplay, menuColormap);
00393
00394
00395
00396
00397
00398 XRaiseWindow(__glutDisplay, menu->win);
00399 XMapWindow(__glutDisplay, menu->win);
00400 }
00401
00402 void
00403 __glutStartMenu(GLUTmenu * menu, GLUTwindow * window,
00404 int x, int y, int x_win, int y_win)
00405 {
00406 int grab;
00407
00408 assert(__glutMappedMenu == NULL);
00409 grab = XGrabPointer(__glutDisplay, __glutRoot, True,
00410 ButtonPressMask | ButtonReleaseMask,
00411 GrabModeAsync, GrabModeAsync,
00412 __glutRoot, menuCursor, CurrentTime);
00413 if (grab != GrabSuccess) {
00414
00415
00416 return;
00417 }
00418 __glutMappedMenu = menu;
00419 __glutMenuWindow = window;
00420 __glutItemSelected = NULL;
00421 if (__glutMenuStatusFunc) {
00422 __glutSetMenu(menu);
00423 __glutSetWindow(window);
00424 __glutMenuStatusFunc(GLUT_MENU_IN_USE, x_win, y_win);
00425 }
00426 mapMenu(menu, x, y);
00427 }
00428
00429 static void
00430 paintSubMenuArrow(Window win, int x, int y)
00431 {
00432 XPoint p[5];
00433
00434 p[0].x = p[4].x = x;
00435 p[0].y = p[4].y = y - menuFont->ascent + 1;
00436 p[1].x = p[0].x + MENU_ARROW_WIDTH - 1;
00437 p[1].y = p[0].y + (menuFont->ascent / 2) - 1;
00438 p[2].x = p[1].x;
00439 p[2].y = p[1].y + 1;
00440 p[3].x = p[0].x;
00441 p[3].y = p[0].y + menuFont->ascent - 2;
00442 XFillPolygon(__glutDisplay, win,
00443 whiteGC, p, 4, Convex, CoordModeOrigin);
00444 XDrawLines(__glutDisplay, win, blackGC, p, 5, CoordModeOrigin);
00445 }
00446
00447 static void
00448 paintMenuItem(GLUTmenuItem * item, int num)
00449 {
00450 Window win = item->menu->win;
00451 GC gc;
00452 int y;
00453 int subMenuExtension;
00454
00455 if (item->menu->submenus > 0) {
00456 subMenuExtension = MENU_ARROW_GAP + MENU_ARROW_WIDTH;
00457 } else {
00458 subMenuExtension = 0;
00459 }
00460 if (item->menu->highlighted == item) {
00461 gc = whiteGC;
00462 } else {
00463 gc = grayGC;
00464 }
00465 y = MENU_GAP + fontHeight * num - menuFont->descent;
00466 XFillRectangle(__glutDisplay, win, gc,
00467 MENU_GAP, y - fontHeight + menuFont->descent,
00468 item->menu->pixwidth + subMenuExtension, fontHeight);
00469 XDrawString(__glutDisplay, win, blackGC,
00470 MENU_GAP, y, item->label, item->len);
00471 if (item->isTrigger) {
00472 paintSubMenuArrow(win,
00473 item->menu->pixwidth + MENU_ARROW_GAP + 1, y);
00474 }
00475 }
00476
00477 void
00478 __glutPaintMenu(GLUTmenu * menu)
00479 {
00480 GLUTmenuItem *item;
00481 int i = menu->num;
00482 int y = MENU_GAP + fontHeight * i - menuFont->descent;
00483
00484 item = menu->list;
00485 while (item) {
00486 if (item->menu->highlighted == item) {
00487 paintMenuItem(item, i);
00488 } else {
00489
00490
00491 XDrawString(__glutDisplay, menu->win, blackGC,
00492 2, y, item->label, item->len);
00493 if (item->isTrigger) {
00494 paintSubMenuArrow(menu->win,
00495 menu->pixwidth + MENU_ARROW_GAP + 1, y);
00496 }
00497 }
00498 i--;
00499 y -= fontHeight;
00500 item = item->next;
00501 }
00502 }
00503
00504 GLUTmenuItem *
00505 __glutGetMenuItem(GLUTmenu * menu, Window win, int *which)
00506 {
00507 GLUTmenuItem *item;
00508 int i;
00509
00510 i = menu->num;
00511 item = menu->list;
00512 while (item) {
00513 if (item->win == win) {
00514 *which = i;
00515 return item;
00516 }
00517 if (item->isTrigger) {
00518 GLUTmenuItem *subitem;
00519
00520 subitem = __glutGetMenuItem(menuList[item->value],
00521 win, which);
00522 if (subitem) {
00523 return subitem;
00524 }
00525 }
00526 i--;
00527 item = item->next;
00528 }
00529 return NULL;
00530 }
00531
00532 static int
00533 getMenuItemIndex(GLUTmenuItem * item)
00534 {
00535 int count = 0;
00536
00537 while (item) {
00538 count++;
00539 item = item->next;
00540 }
00541 return count;
00542 }
00543
00544 GLUTmenu *
00545 __glutGetMenu(Window win)
00546 {
00547 GLUTmenu *menu;
00548
00549 menu = __glutMappedMenu;
00550 while (menu) {
00551 if (win == menu->win) {
00552 return menu;
00553 }
00554 menu = menu->cascade;
00555 }
00556 return NULL;
00557 }
00558
00559 GLUTmenu *
00560 __glutGetMenuByNum(int menunum)
00561 {
00562 if (menunum < 1 || menunum > menuListSize) {
00563 return NULL;
00564 }
00565 return menuList[menunum - 1];
00566 }
00567
00568 static int
00569 getUnusedMenuSlot(void)
00570 {
00571 int i;
00572
00573
00574 for (i = 0; i < menuListSize; i++) {
00575 if (!menuList[i]) {
00576 return i;
00577 }
00578 }
00579
00580 menuListSize++;
00581 if (menuList) {
00582 menuList = (GLUTmenu **)
00583 realloc(menuList, menuListSize * sizeof(GLUTmenu *));
00584 } else {
00585
00586
00587
00588 menuList = (GLUTmenu **) malloc(sizeof(GLUTmenu *));
00589 }
00590 if (!menuList)
00591 __glutFatalError("out of memory.");
00592 menuList[menuListSize - 1] = NULL;
00593 return menuListSize - 1;
00594 }
00595
00596 static void
00597 menuModificationError(void)
00598 {
00599
00600 __glutWarning("The following is a new check for GLUT 3.0; update your code.");
00601 __glutFatalError("menu manipulation not allowed while menus in use");
00602 }
00603
00604 int
00605 glutCreateMenu(GLUTselectCB selectFunc)
00606 {
00607 XSetWindowAttributes wa;
00608 GLUTmenu *menu;
00609 int menuid;
00610
00611 if (__glutMappedMenu)
00612 menuModificationError();
00613 if (!__glutDisplay)
00614 __glutOpenXConnection(NULL);
00615 menuid = getUnusedMenuSlot();
00616 menu = (GLUTmenu *) malloc(sizeof(GLUTmenu));
00617 if (!menu)
00618 __glutFatalError("out of memory.");
00619 menu->id = menuid;
00620 menu->num = 0;
00621 menu->submenus = 0;
00622 menu->managed = False;
00623 menu->pixwidth = 0;
00624 menu->select = selectFunc;
00625 menu->list = NULL;
00626 menu->cascade = NULL;
00627 menu->highlighted = NULL;
00628 menu->anchor = NULL;
00629 menuSetup();
00630 wa.override_redirect = True;
00631 wa.background_pixel = menuGray;
00632 wa.border_pixel = menuBlack;
00633 wa.colormap = menuColormap;
00634 wa.event_mask = StructureNotifyMask | ExposureMask |
00635 ButtonPressMask | ButtonReleaseMask |
00636 EnterWindowMask | LeaveWindowMask;
00637
00638
00639 wa.save_under = True;
00640 menu->win = XCreateWindow(__glutDisplay, __glutRoot,
00641
00642 0, 0,
00643
00644 1, 1,
00645 MENU_BORDER, menuDepth, InputOutput, menuVisual,
00646 CWOverrideRedirect | CWBackPixel | CWBorderPixel |
00647 CWEventMask | CWColormap | useSaveUnders,
00648 &wa);
00649 menuGraphicsContextSetup(menu->win);
00650 menuList[menuid] = menu;
00651 __glutSetMenu(menu);
00652 return menuid + 1;
00653 }
00654
00655 void
00656 glutDestroyMenu(int menunum)
00657 {
00658 GLUTmenu *menu = __glutGetMenuByNum(menunum);
00659 GLUTmenuItem *item, *next;
00660
00661 if (__glutMappedMenu)
00662 menuModificationError();
00663 assert(menu->id == menunum - 1);
00664 XDestroySubwindows(__glutDisplay, menu->win);
00665 XDestroyWindow(__glutDisplay, menu->win);
00666 menuList[menunum - 1] = NULL;
00667
00668 item = menu->list;
00669 while (item) {
00670 assert(item->menu == menu);
00671 next = item->next;
00672 free(item->label);
00673 free(item);
00674 item = next;
00675 }
00676 if (__glutCurrentMenu == menu) {
00677 __glutCurrentMenu = NULL;
00678 }
00679 free(menu);
00680 }
00681
00682 int
00683 glutGetMenu(void)
00684 {
00685 if (__glutCurrentMenu) {
00686 return __glutCurrentMenu->id + 1;
00687 } else {
00688 return 0;
00689 }
00690 }
00691
00692 void
00693 glutSetMenu(int menuid)
00694 {
00695 GLUTmenu *menu;
00696
00697 if (menuid < 1 || menuid > menuListSize) {
00698 __glutWarning("glutSetMenu attempted on bogus menu.");
00699 return;
00700 }
00701 menu = menuList[menuid - 1];
00702 if (!menu) {
00703 __glutWarning("glutSetMenu attempted on bogus menu.");
00704 return;
00705 }
00706 __glutSetMenu(menu);
00707 }
00708
00709 static void
00710 setMenuItem(GLUTmenuItem * item, char *label,
00711 int value, Bool isTrigger)
00712 {
00713 GLUTmenu *menu;
00714
00715 menu = item->menu;
00716 item->label = strdup(label);
00717 if (!item->label)
00718 __glutFatalError("out of memory.");
00719 item->isTrigger = isTrigger;
00720 item->len = (int) strlen(label);
00721 item->value = value;
00722 item->pixwidth = XTextWidth(menuFont, label, item->len) + 4;
00723 if (item->pixwidth > menu->pixwidth) {
00724 menu->pixwidth = item->pixwidth;
00725 }
00726 menu->managed = False;
00727 }
00728
00729 void
00730 glutAddMenuEntry(char *label, int value)
00731 {
00732 XSetWindowAttributes wa;
00733 GLUTmenuItem *entry;
00734
00735 if (__glutMappedMenu)
00736 menuModificationError();
00737 entry = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
00738 if (!entry)
00739 __glutFatalError("out of memory.");
00740 entry->menu = __glutCurrentMenu;
00741 setMenuItem(entry, label, value, False);
00742 wa.event_mask = EnterWindowMask | LeaveWindowMask;
00743 entry->win = XCreateWindow(__glutDisplay,
00744 __glutCurrentMenu->win, MENU_GAP,
00745 __glutCurrentMenu->num * fontHeight + MENU_GAP,
00746 entry->pixwidth, fontHeight,
00747 0, CopyFromParent, InputOnly, CopyFromParent,
00748 CWEventMask, &wa);
00749 XMapWindow(__glutDisplay, entry->win);
00750 __glutCurrentMenu->num++;
00751 entry->next = __glutCurrentMenu->list;
00752 __glutCurrentMenu->list = entry;
00753 }
00754
00755 void
00756 glutAddSubMenu(char *label, int menu)
00757 {
00758 XSetWindowAttributes wa;
00759 GLUTmenuItem *submenu;
00760
00761 if (__glutMappedMenu)
00762 menuModificationError();
00763 submenu = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem));
00764 if (!submenu)
00765 __glutFatalError("out of memory.");
00766 __glutCurrentMenu->submenus++;
00767 submenu->menu = __glutCurrentMenu;
00768 setMenuItem(submenu, label, menu - 1, True);
00769 wa.event_mask = EnterWindowMask | LeaveWindowMask;
00770 submenu->win = XCreateWindow(__glutDisplay,
00771 __glutCurrentMenu->win, MENU_GAP,
00772 __glutCurrentMenu->num * fontHeight + MENU_GAP,
00773 submenu->pixwidth, fontHeight,
00774 0, CopyFromParent, InputOnly, CopyFromParent,
00775 CWEventMask, &wa);
00776 XMapWindow(__glutDisplay, submenu->win);
00777 __glutCurrentMenu->num++;
00778 submenu->next = __glutCurrentMenu->list;
00779 __glutCurrentMenu->list = submenu;
00780 }
00781
00782 void
00783 glutChangeToMenuEntry(int num, char *label, int value)
00784 {
00785 GLUTmenuItem *item;
00786 int i;
00787
00788 if (__glutMappedMenu)
00789 menuModificationError();
00790 i = __glutCurrentMenu->num;
00791 item = __glutCurrentMenu->list;
00792 while (item) {
00793 if (i == num) {
00794 if (item->isTrigger) {
00795
00796
00797 item->menu->submenus--;
00798 }
00799 free(item->label);
00800 setMenuItem(item, label, value, False);
00801 return;
00802 }
00803 i--;
00804 item = item->next;
00805 }
00806 __glutWarning("Current menu has no %d item.", num);
00807 }
00808
00809 void
00810 glutChangeToSubMenu(int num, char *label, int menu)
00811 {
00812 GLUTmenuItem *item;
00813 int i;
00814
00815 if (__glutMappedMenu)
00816 menuModificationError();
00817 i = __glutCurrentMenu->num;
00818 item = __glutCurrentMenu->list;
00819 while (item) {
00820 if (i == num) {
00821 if (!item->isTrigger) {
00822
00823
00824 item->menu->submenus++;
00825 }
00826 free(item->label);
00827 setMenuItem(item, label, menu - 1, True);
00828 return;
00829 }
00830 i--;
00831 item = item->next;
00832 }
00833 __glutWarning("Current menu has no %d item.", num);
00834 }
00835
00836 void
00837 glutRemoveMenuItem(int num)
00838 {
00839 GLUTmenuItem *item, **prev, *remaining;
00840 int pixwidth, i;
00841
00842 if (__glutMappedMenu)
00843 menuModificationError();
00844 i = __glutCurrentMenu->num;
00845 prev = &__glutCurrentMenu->list;
00846 item = __glutCurrentMenu->list;
00847
00848
00849 pixwidth = 0;
00850 while (item) {
00851 if (i == num) {
00852
00853
00854
00855 if (item->pixwidth >= __glutCurrentMenu->pixwidth) {
00856
00857
00858 remaining = item->next;
00859 while (remaining) {
00860 if (remaining->pixwidth > pixwidth) {
00861 pixwidth = remaining->pixwidth;
00862 }
00863 remaining = remaining->next;
00864 }
00865 }
00866 __glutCurrentMenu->num--;
00867 __glutCurrentMenu->managed = False;
00868 __glutCurrentMenu->pixwidth = pixwidth;
00869
00870
00871 *prev = item->next;
00872
00873 free(item->label);
00874 free(item);
00875 return;
00876 }
00877 if (item->pixwidth > pixwidth) {
00878 pixwidth = item->pixwidth;
00879 }
00880 i--;
00881 prev = &item->next;
00882 item = item->next;
00883 }
00884 __glutWarning("Current menu has no %d item.", num);
00885 }
00886
00887 void
00888 glutAttachMenu(int button)
00889 {
00890 if (__glutMappedMenu)
00891 menuModificationError();
00892 if (__glutCurrentWindow->menu[button] < 1) {
00893 __glutCurrentWindow->buttonUses++;
00894 }
00895 __glutChangeWindowEventMask(
00896 ButtonPressMask | ButtonReleaseMask, True);
00897 __glutCurrentWindow->menu[button] = __glutCurrentMenu->id + 1;
00898 }
00899
00900 void
00901 glutDetachMenu(int button)
00902 {
00903 if (__glutMappedMenu)
00904 menuModificationError();
00905 if (__glutCurrentWindow->menu[button] > 0) {
00906 __glutCurrentWindow->buttonUses--;
00907 __glutChangeWindowEventMask(ButtonPressMask | ButtonReleaseMask,
00908 __glutCurrentWindow->buttonUses > 0);
00909 __glutCurrentWindow->menu[button] = 0;
00910 }
00911 }
00912
00913 void
00914 __glutMenuItemEnterOrLeave(GLUTmenuItem * item,
00915 int num, int type)
00916 {
00917 int alreadyUp = 0;
00918
00919 if (type == EnterNotify) {
00920 GLUTmenuItem *prevItem = item->menu->highlighted;
00921
00922 if (prevItem && prevItem != item) {
00923
00924
00925
00926
00927 item->menu->highlighted = NULL;
00928 paintMenuItem(prevItem, getMenuItemIndex(prevItem));
00929 }
00930 item->menu->highlighted = item;
00931 __glutItemSelected = item;
00932 if (item->menu->cascade) {
00933 if (!item->isTrigger) {
00934
00935
00936
00937 unmapMenu(item->menu->cascade);
00938 item->menu->cascade = NULL;
00939 } else {
00940 GLUTmenu *submenu = menuList[item->value];
00941
00942 if (submenu->anchor == item) {
00943
00944
00945
00946 alreadyUp = 1;
00947 } else {
00948
00949
00950
00951 unmapMenu(item->menu->cascade);
00952 item->menu->cascade = NULL;
00953 }
00954 }
00955 }
00956 if (!alreadyUp) {
00957
00958
00959 paintMenuItem(item, num);
00960 } else {
00961
00962 }
00963 } else {
00964
00965 if (item->menu->cascade &&
00966 item->menu->cascade->anchor == item) {
00967
00968
00969 } else {
00970
00971 item->menu->highlighted = NULL;
00972 paintMenuItem(item, num);
00973 }
00974 __glutItemSelected = NULL;
00975 }
00976 if (item->isTrigger) {
00977 if (type == EnterNotify && !alreadyUp) {
00978 GLUTmenu *submenu = menuList[item->value];
00979
00980 mapMenu(submenu,
00981 item->menu->x + item->menu->pixwidth +
00982 MENU_ARROW_GAP + MENU_ARROW_WIDTH +
00983 MENU_GAP + MENU_BORDER,
00984 item->menu->y + fontHeight * (num - 1) + MENU_GAP);
00985 item->menu->cascade = submenu;
00986 submenu->anchor = item;
00987 }
00988 }
00989 }