📄 glut_menu.c
字号:
} else { changes.x = x; } /* Rember where the menu is placed so submenus can be properly placed relative to it. */ menu->x = changes.x; menu->y = changes.y; XConfigureWindow(__glutDisplay, menu->win, mask, &changes); XInstallColormap(__glutDisplay, menuColormap); /* XXX The XRaiseWindow below should not be necessary because the XConfigureWindow requests an Above stack mode (same as XRaiseWindow), but some Sun users complained this was still necessary. Probably some window manager or X server bug on these machines?? */ XRaiseWindow(__glutDisplay, menu->win); XMapWindow(__glutDisplay, menu->win);}static voidstartMenu(GLUTmenu * menu, GLUTwindow * window, int x, int y, int x_win, int y_win){ int grab; assert(__glutMappedMenu == NULL); grab = XGrabPointer(__glutDisplay, __glutRoot, True, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, __glutRoot, menuCursor, CurrentTime); if (grab != GrabSuccess) { /* Somebody else has pointer grabbed, ignore menu activation. */ return; } __glutMappedMenu = menu; __glutMenuWindow = window; __glutItemSelected = NULL; if (__glutMenuStatusFunc) { __glutSetMenu(menu); __glutSetWindow(window); __glutMenuStatusFunc(GLUT_MENU_IN_USE, x_win, y_win); } mapMenu(menu, x, y);}static voidpaintSubMenuArrow(Window win, int x, int y){ XPoint p[5]; p[0].x = p[4].x = x; p[0].y = p[4].y = y - menuFont->ascent + 1; p[1].x = p[0].x + MENU_ARROW_WIDTH - 1; p[1].y = p[0].y + (menuFont->ascent / 2) - 1; p[2].x = p[1].x; p[2].y = p[1].y + 1; p[3].x = p[0].x; p[3].y = p[0].y + menuFont->ascent - 2; XFillPolygon(__glutDisplay, win, whiteGC, p, 4, Convex, CoordModeOrigin); XDrawLines(__glutDisplay, win, blackGC, p, 5, CoordModeOrigin);}static voidpaintMenuItem(GLUTmenuItem * item, int num){ Window win = item->menu->win; GC gc; int y; int subMenuExtension; if (item->menu->submenus > 0) { subMenuExtension = MENU_ARROW_GAP + MENU_ARROW_WIDTH; } else { subMenuExtension = 0; } if (item->menu->highlighted == item) { gc = whiteGC; } else { gc = grayGC; } y = MENU_GAP + fontHeight * num - menuFont->descent; XFillRectangle(__glutDisplay, win, gc, MENU_GAP, y - fontHeight + menuFont->descent, item->menu->pixwidth + subMenuExtension, fontHeight); XDrawString(__glutDisplay, win, blackGC, MENU_GAP, y, item->label, item->len); if (item->isTrigger) { paintSubMenuArrow(win, item->menu->pixwidth + MENU_ARROW_GAP + 1, y); }}static voidpaintMenu(GLUTmenu * menu){ GLUTmenuItem *item; int i = menu->num; int y = MENU_GAP + fontHeight * i - menuFont->descent; item = menu->list; while (item) { if (item->menu->highlighted == item) { paintMenuItem(item, i); } else { /* Quick render of the menu item; assume background already cleared to gray. */ XDrawString(__glutDisplay, menu->win, blackGC, 2, y, item->label, item->len); if (item->isTrigger) { paintSubMenuArrow(menu->win, menu->pixwidth + MENU_ARROW_GAP + 1, y); } } i--; y -= fontHeight; item = item->next; }}static GLUTmenuItem *getMenuItem(GLUTmenu * menu, Window win, int *which){ GLUTmenuItem *item; int i; if (menu->searched) { __glutFatalError("submenu infinite loop detected"); } menu->searched = True; i = menu->num; item = menu->list; while (item) { if (item->win == win) { *which = i; menu->searched = False; return item; } if (item->isTrigger) { GLUTmenuItem *subitem; subitem = __glutGetMenuItem(__glutMenuList[item->value], win, which); if (subitem) { menu->searched = False; return subitem; } } i--; item = item->next; } menu->searched = False; return NULL;}static intgetMenuItemIndex(GLUTmenuItem * item){ int count = 0; while (item) { count++; item = item->next; } return count;}static GLUTmenu *getMenu(Window win){ GLUTmenu *menu; menu = __glutMappedMenu; while (menu) { if (win == menu->win) { return menu; } menu = menu->cascade; } return NULL;}static GLUTmenu *getMenuByNum(int menunum){ if (menunum < 1 || menunum > menuListSize) { return NULL; } return __glutMenuList[menunum - 1];}static intgetUnusedMenuSlot(void){ int i; /* Look for allocated, unused slot. */ for (i = 0; i < menuListSize; i++) { if (!__glutMenuList[i]) { return i; } } /* Allocate a new slot. */ menuListSize++; if (__glutMenuList) { __glutMenuList = (GLUTmenu **) realloc(__glutMenuList, menuListSize * sizeof(GLUTmenu *)); } else { /* XXX Some realloc's do not correctly perform a malloc when asked to perform a realloc on a NULL pointer, though the ANSI C library spec requires this. */ __glutMenuList = (GLUTmenu **) malloc(sizeof(GLUTmenu *)); } if (!__glutMenuList) { __glutFatalError("out of memory."); } __glutMenuList[menuListSize - 1] = NULL; return menuListSize - 1;}void__glutMenuModificationError(void){ /* XXX Remove the warning after GLUT 3.0. */ __glutWarning("The following is a new check for GLUT 3.0; update your code."); __glutFatalError("menu manipulation not allowed while menus in use.");}static voidmenuItemEnterOrLeave(GLUTmenuItem * item, int num, int type){ int alreadyUp = 0; if (type == EnterNotify) { GLUTmenuItem *prevItem = item->menu->highlighted; if (prevItem && prevItem != item) { /* If there's an already higlighted item in this menu that is different from this one (we could be re-entering an item with an already cascaded submenu!), unhighlight the previous item. */ item->menu->highlighted = NULL; paintMenuItem(prevItem, getMenuItemIndex(prevItem)); } item->menu->highlighted = item; __glutItemSelected = item; if (item->menu->cascade) { if (!item->isTrigger) { /* Entered a menu item that is not a submenu trigger, so pop down the current submenu cascade of this menu. */ unmapMenu(item->menu->cascade); item->menu->cascade = NULL; } else { GLUTmenu *submenu = __glutMenuList[item->value]; if (submenu->anchor == item) { /* We entered the submenu trigger for the submenu that is already up, so don't take down the submenu. */ alreadyUp = 1; } else { /* Submenu already popped up for some other submenu item of this menu; need to pop down that other submenu cascade. */ unmapMenu(item->menu->cascade); item->menu->cascade = NULL; } } } if (!alreadyUp) { /* Make sure the menu item gets painted with highlighting. */ paintMenuItem(item, num); } else { /* If already up, should already be highlighted. */ } } else { /* LeaveNotify: Handle leaving a menu item... */ if (item->menu->cascade && item->menu->cascade->anchor == item) { /* If there is a submenu casacaded from this item, do not change the highlighting on this item upon leaving. */ } else { /* Unhighlight this menu item. */ item->menu->highlighted = NULL; paintMenuItem(item, num); } __glutItemSelected = NULL; } if (item->isTrigger) { if (type == EnterNotify && !alreadyUp) { GLUTmenu *submenu = __glutMenuList[item->value]; mapMenu(submenu, item->menu->x + item->menu->pixwidth + MENU_ARROW_GAP + MENU_ARROW_WIDTH + MENU_GAP + MENU_BORDER, item->menu->y + fontHeight * (num - 1) + MENU_GAP); item->menu->cascade = submenu; submenu->anchor = item; } }}/* Installs callback functions for use by glut_event.c The point of this is so that GLUT's menu code only gets linked into GLUT binaries (assuming a static library) if the GLUT menu API is used. */static voidinstallMenuCallbacks(void){ __glutMenuItemEnterOrLeave = menuItemEnterOrLeave; __glutFinishMenu = finishMenu; __glutPaintMenu = paintMenu; __glutStartMenu = startMenu; __glutGetMenuByNum = getMenuByNum; __glutGetMenu = getMenu; __glutGetMenuItem = getMenuItem;}int GLUTAPIENTRY glutCreateMenu(GLUTselectCB selectFunc){ XSetWindowAttributes wa; GLUTmenu *menu; int menuid; if (__glutMappedMenu) { __glutMenuModificationError(); } if (!__glutDisplay) { __glutOpenXConnection(NULL); } installMenuCallbacks(); menuid = getUnusedMenuSlot(); menu = (GLUTmenu *) malloc(sizeof(GLUTmenu)); if (!menu) { __glutFatalError("out of memory."); } menu->id = menuid; menu->num = 0; menu->submenus = 0; menu->managed = False; menu->searched = False; menu->pixwidth = 0; menu->select = selectFunc; menu->list = NULL; menu->cascade = NULL; menu->highlighted = NULL; menu->anchor = NULL; menuSetup(); wa.override_redirect = True; wa.background_pixel = menuGray; wa.border_pixel = menuBlack; wa.colormap = menuColormap; wa.event_mask = StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask; /* Save unders really only enabled if useSaveUnders is set to CWSaveUnder, ie. using Mesa 3D. See earlier comments. */ wa.save_under = True; menu->win = XCreateWindow(__glutDisplay, __glutRoot, /* Real position determined when mapped. */ 0, 0, /* Real size will be determined when menu is manged. */ 1, 1, MENU_BORDER, menuDepth, InputOutput, menuVisual, CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWEventMask | CWColormap | useSaveUnders, &wa); menuGraphicsContextSetup(menu->win); __glutMenuList[menuid] = menu; __glutSetMenu(menu); return menuid + 1;}/* CENTRY */int GLUTAPIENTRY glutGetMenu(void){ if (__glutCurrentMenu) { return __glutCurrentMenu->id + 1; } else { return 0; }}void GLUTAPIENTRY glutSetMenu(int menuid){ GLUTmenu *menu; if (menuid < 1 || menuid > menuListSize) { __glutWarning("glutSetMenu attempted on bogus menu."); return; } menu = __glutMenuList[menuid - 1]; if (!menu) { __glutWarning("glutSetMenu attempted on bogus menu."); return; } __glutSetMenu(menu);}/* ENDCENTRY */void__glutSetMenuItem(GLUTmenuItem * item, const char *label, int value, Bool isTrigger){ GLUTmenu *menu; menu = item->menu; item->label = __glutStrdup(label); if (!item->label) { __glutFatalError("out of memory."); } item->isTrigger = isTrigger; item->len = (int) strlen(label); item->value = value; item->pixwidth = XTextWidth(menuFont, label, item->len) + 4; if (item->pixwidth > menu->pixwidth) { menu->pixwidth = item->pixwidth; } menu->managed = False;}/* CENTRY */void GLUTAPIENTRY glutAddMenuEntry(const char *label, int value){ XSetWindowAttributes wa; GLUTmenuItem *entry; if (__glutMappedMenu) { __glutMenuModificationError(); } entry = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem)); if (!entry) { __glutFatalError("out of memory."); } entry->menu = __glutCurrentMenu; __glutSetMenuItem(entry, label, value, False); wa.event_mask = EnterWindowMask | LeaveWindowMask; entry->win = XCreateWindow(__glutDisplay, __glutCurrentMenu->win, MENU_GAP, __glutCurrentMenu->num * fontHeight + MENU_GAP, /* x & y */ entry->pixwidth, fontHeight, /* width & height */ 0, CopyFromParent, InputOnly, CopyFromParent, CWEventMask, &wa); XMapWindow(__glutDisplay, entry->win); __glutCurrentMenu->num++; entry->next = __glutCurrentMenu->list; __glutCurrentMenu->list = entry;}void GLUTAPIENTRY glutAddSubMenu(const char *label, int menu){ XSetWindowAttributes wa; GLUTmenuItem *submenu; if (__glutMappedMenu) { __glutMenuModificationError(); } submenu = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem)); if (!submenu) { __glutFatalError("out of memory."); } __glutCurrentMenu->submenus++; submenu->menu = __glutCurrentMenu; __glutSetMenuItem(submenu, label, /* base 0 */ menu - 1, True); wa.event_mask = EnterWindowMask | LeaveWindowMask; submenu->win = XCreateWindow(__glutDisplay, __glutCurrentMenu->win, MENU_GAP, __glutCurrentMenu->num * fontHeight + MENU_GAP, /* x & y */ submenu->pixwidth, fontHeight, /* width & height */ 0, CopyFromParent, InputOnly, CopyFromParent, CWEventMask, &wa); XMapWindow(__glutDisplay, submenu->win); __glutCurrentMenu->num++; submenu->next = __glutCurrentMenu->list; __glutCurrentMenu->list = submenu;}void GLUTAPIENTRY glutAttachMenu(int button){ if (__glutMappedMenu) { __glutMenuModificationError(); } installMenuCallbacks(); if (__glutCurrentWindow->menu[button] < 1) { __glutCurrentWindow->buttonUses++; } __glutChangeWindowEventMask( ButtonPressMask | ButtonReleaseMask, True); __glutCurrentWindow->menu[button] = __glutCurrentMenu->id + 1;}/* ENDCENTRY */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -