📄 win32_menu.c
字号:
/* Copyright (c) Mark J. Kilgard, 1994, 1997, 1998. *//* Copyright (c) Nate Robins, 1997. *//* This program is freely distributable without licensing fees and is provided without guarantee or warrantee expressed or implied. This program is -not- in the public domain. *//* This file completely re-implements glut_menu.c and glut_menu2.c for Win32. Note that neither glut_menu.c nor glut_menu2.c are compiled into Win32 GLUT. */#include <stdlib.h>#include <string.h>#include <stdio.h>#include <errno.h>#include <assert.h>#include "glutint.h"void (GLUTCALLBACK *__glutMenuStatusFunc) (int, int, int);GLUTmenu *__glutMappedMenu;GLUTwindow *__glutMenuWindow;GLUTmenuItem *__glutItemSelected;unsigned __glutMenuButton;static GLUTmenu **menuList = NULL;static int menuListSize = 0;static UINT uniqueMenuHandler = 1;/* DEPRICATED, use glutMenuStatusFunc instead. */void GLUTAPIENTRYglutMenuStateFunc(GLUTmenuStateCB menuStateFunc){ __glutMenuStatusFunc = (GLUTmenuStatusCB) menuStateFunc;}void GLUTAPIENTRYglutMenuStatusFunc(GLUTmenuStatusCB menuStatusFunc){ __glutMenuStatusFunc = menuStatusFunc;}void__glutSetMenu(GLUTmenu * menu){ __glutCurrentMenu = menu;}static voidunmapMenu(GLUTmenu * menu){ if (menu->cascade) { unmapMenu(menu->cascade); menu->cascade = NULL; } menu->anchor = NULL; menu->highlighted = NULL;}void__glutFinishMenu(Window win, int x, int y){ unmapMenu(__glutMappedMenu); /* XXX Put in a GdiFlush just in case. Probably unnecessary. -mjk */ GdiFlush(); if (__glutMenuStatusFunc) { __glutSetWindow(__glutMenuWindow); __glutSetMenu(__glutMappedMenu); /* Setting __glutMappedMenu to NULL permits operations that change menus or destroy the menu window again. */ __glutMappedMenu = NULL; __glutMenuStatusFunc(GLUT_MENU_NOT_IN_USE, x, y); } /* Setting __glutMappedMenu to NULL permits operations that change menus or destroy the menu window again. */ __glutMappedMenu = NULL; /* If an item is selected and it is not a submenu trigger, generate menu callback. */ if (__glutItemSelected && !__glutItemSelected->isTrigger) { __glutSetWindow(__glutMenuWindow); /* When menu callback is triggered, current menu should be set to the callback menu. */ __glutSetMenu(__glutItemSelected->menu); __glutItemSelected->menu->select(__glutItemSelected->value); } __glutMenuWindow = NULL;}static voidmapMenu(GLUTmenu * menu, int x, int y){ TrackPopupMenu((HMENU) menu->win, TPM_LEFTALIGN | (__glutMenuButton == TPM_RIGHTBUTTON) ? TPM_RIGHTBUTTON : TPM_LEFTBUTTON, x, y, 0, __glutCurrentWindow->win, NULL);}void__glutStartMenu(GLUTmenu * menu, GLUTwindow * window, int x, int y, int x_win, int y_win){ assert(__glutMappedMenu == NULL); __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);}GLUTmenuItem *__glutGetUniqueMenuItem(GLUTmenu * menu, UINT unique){ GLUTmenuItem *item; int i; i = menu->num; item = menu->list; while (item) { if (item->unique == unique) { return item; } if (item->isTrigger) { GLUTmenuItem *subitem; subitem = __glutGetUniqueMenuItem(menuList[item->value], unique); if (subitem) { return subitem; } } i--; item = item->next; } return NULL;}GLUTmenuItem *__glutGetMenuItem(GLUTmenu * menu, Window win, int *which){ GLUTmenuItem *item; int i; i = menu->num; item = menu->list; while (item) { if (item->win == win) { *which = i; return item; } if (item->isTrigger) { GLUTmenuItem *subitem; subitem = __glutGetMenuItem(menuList[item->value], win, which); if (subitem) { return subitem; } } i--; item = item->next; } return NULL;}GLUTmenu *__glutGetMenu(Window win){ GLUTmenu *menu; menu = __glutMappedMenu; while (menu) { if (win == menu->win) { return menu; } menu = menu->cascade; } return NULL;}GLUTmenu *__glutGetMenuByNum(int menunum){ if (menunum < 1 || menunum > menuListSize) { return NULL; } return menuList[menunum - 1];}static intgetUnusedMenuSlot(void){ int i; /* Look for allocated, unused slot. */ for (i = 0; i < menuListSize; i++) { if (!menuList[i]) { return i; } } /* Allocate a new slot. */ menuListSize++; if (menuList) { menuList = (GLUTmenu **) realloc(menuList, 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. */ menuList = (GLUTmenu **) malloc(sizeof(GLUTmenu *)); } if (!menuList) { __glutFatalError("out of memory."); } menuList[menuListSize - 1] = NULL; return menuListSize - 1;}static voidmenuModificationError(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.");}int GLUTAPIENTRYglutCreateMenu(GLUTselectCB selectFunc){ GLUTmenu *menu; int menuid; if (__glutMappedMenu) { menuModificationError(); } menuid = getUnusedMenuSlot(); menu = (GLUTmenu *) malloc(sizeof(GLUTmenu)); if (!menu) { __glutFatalError("out of memory."); } menu->id = menuid; menu->num = 0; menu->submenus = 0; menu->select = selectFunc; menu->list = NULL; menu->cascade = NULL; menu->highlighted = NULL; menu->anchor = NULL; menu->win = (HWND) CreatePopupMenu(); menuList[menuid] = menu; __glutSetMenu(menu); return menuid + 1;}int GLUTAPIENTRY__glutCreateMenuWithExit(GLUTselectCB selectFunc, void (__cdecl *exitfunc)(int)){ __glutExitFunc = exitfunc; return glutCreateMenu(selectFunc);}void GLUTAPIENTRYglutDestroyMenu(int menunum){ GLUTmenu *menu = __glutGetMenuByNum(menunum); GLUTmenuItem *item, *next; if (__glutMappedMenu) { menuModificationError(); } assert(menu->id == menunum - 1); DestroyMenu( (HMENU) menu->win); menuList[menunum - 1] = NULL; /* free all menu entries */ item = menu->list; while (item) { assert(item->menu == menu); next = item->next; free(item->label); free(item); item = next; } if (__glutCurrentMenu == menu) { __glutCurrentMenu = NULL; } free(menu);}int GLUTAPIENTRYglutGetMenu(void){ if (__glutCurrentMenu) { return __glutCurrentMenu->id + 1; } else { return 0; }}void GLUTAPIENTRYglutSetMenu(int menuid){ GLUTmenu *menu; if (menuid < 1 || menuid > menuListSize) { __glutWarning("glutSetMenu attempted on bogus menu."); return; } menu = menuList[menuid - 1]; if (!menu) { __glutWarning("glutSetMenu attempted on bogus menu."); return; } __glutSetMenu(menu);}static voidsetMenuItem(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->unique = uniqueMenuHandler++; if (isTrigger) { AppendMenu((HMENU) menu->win, MF_POPUP, (UINT)item->win, label); } else { AppendMenu((HMENU) menu->win, MF_STRING, item->unique, label); }}void GLUTAPIENTRYglutAddMenuEntry(const char *label, int value){ GLUTmenuItem *entry; if (__glutMappedMenu) { menuModificationError(); } entry = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem)); if (!entry) { __glutFatalError("out of memory."); } entry->menu = __glutCurrentMenu; setMenuItem(entry, label, value, FALSE); __glutCurrentMenu->num++; entry->next = __glutCurrentMenu->list; __glutCurrentMenu->list = entry;}void GLUTAPIENTRYglutAddSubMenu(const char *label, int menu){ GLUTmenuItem *submenu; GLUTmenu *popupmenu; if (__glutMappedMenu) { menuModificationError(); } submenu = (GLUTmenuItem *) malloc(sizeof(GLUTmenuItem)); if (!submenu) { __glutFatalError("out of memory."); } __glutCurrentMenu->submenus++; submenu->menu = __glutCurrentMenu; popupmenu = __glutGetMenuByNum(menu); if (popupmenu) { submenu->win = popupmenu->win; } setMenuItem(submenu, label, /* base 0 */ menu - 1, TRUE); __glutCurrentMenu->num++; submenu->next = __glutCurrentMenu->list; __glutCurrentMenu->list = submenu;}void GLUTAPIENTRYglutChangeToMenuEntry(int num, const char *label, int value){ GLUTmenuItem *item; int i; if (__glutMappedMenu) { menuModificationError(); } i = __glutCurrentMenu->num; item = __glutCurrentMenu->list; while (item) { if (i == num) { if (item->isTrigger) { /* If changing a submenu trigger to a menu entry, we need to account for submenus. */ item->menu->submenus--; /* Nuke the Win32 menu. */ DestroyMenu((HMENU) item->win); } free(item->label); item->label = strdup(label); if (!item->label) __glutFatalError("out of memory"); item->isTrigger = FALSE; item->len = (int) strlen(label); item->value = value; item->unique = uniqueMenuHandler++; ModifyMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1, MF_BYPOSITION | MFT_STRING, item->unique, label); return; } i--; item = item->next; } __glutWarning("Current menu has no %d item.", num);}void GLUTAPIENTRYglutChangeToSubMenu(int num, const char *label, int menu){ GLUTmenu *popupmenu; GLUTmenuItem *item; int i; if (__glutMappedMenu) { menuModificationError(); } i = __glutCurrentMenu->num; item = __glutCurrentMenu->list; while (item) { if (i == num) { if (!item->isTrigger) { /* If changing a menu entry to as submenu trigger, we need to account for submenus. */ item->menu->submenus++; item->win = (HWND) CreatePopupMenu(); } free(item->label); item->label = strdup(label); if (!item->label) __glutFatalError("out of memory"); item->isTrigger = TRUE; item->len = (int) strlen(label); item->value = menu - 1; item->unique = uniqueMenuHandler++; popupmenu = __glutGetMenuByNum(menu); if (popupmenu) item->win = popupmenu->win; ModifyMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1, MF_BYPOSITION | MF_POPUP, (UINT) item->win, label); return; } i--; item = item->next; } __glutWarning("Current menu has no %d item.", num);}void GLUTAPIENTRYglutRemoveMenuItem(int num){ GLUTmenuItem *item, **prev; int i; if (__glutMappedMenu) { menuModificationError(); } i = __glutCurrentMenu->num; prev = &__glutCurrentMenu->list; item = __glutCurrentMenu->list; while (item) { if (i == num) { /* Found the menu item in list to remove. */ __glutCurrentMenu->num--; /* Patch up menu's item list. */ *prev = item->next; RemoveMenu((HMENU) __glutCurrentMenu->win, (UINT) i - 1, MF_BYPOSITION); free(item->label); free(item); return; } i--; prev = &item->next; item = item->next; } __glutWarning("Current menu has no %d item.", num);}void GLUTAPIENTRYglutAttachMenu(int button){ if (__glutCurrentWindow == __glutGameModeWindow) { __glutWarning("cannot attach menus in game mode."); return; } if (__glutMappedMenu) { menuModificationError(); } if (__glutCurrentWindow->menu[button] < 1) { __glutCurrentWindow->buttonUses++; } __glutCurrentWindow->menu[button] = __glutCurrentMenu->id + 1;}void GLUTAPIENTRYglutDetachMenu(int button){ if (__glutMappedMenu) { menuModificationError(); } if (__glutCurrentWindow->menu[button] > 0) { __glutCurrentWindow->buttonUses--; __glutCurrentWindow->menu[button] = 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -