📄 tkmenu.c
字号:
*---------------------------------------------------------------------- */static intConfigureMenuCloneEntries(interp, menuPtr, index, argc, argv, flags) Tcl_Interp *interp; /* Used for error reporting. */ TkMenu *menuPtr; /* Information about whole menu. */ int index; /* Index of mePtr within menuPtr's * entries. */ int argc; /* Number of valid entries in argv. */ char **argv; /* Arguments. */ int flags; /* Additional flags to pass to * Tk_ConfigureWidget. */{ TkMenuEntry *mePtr; TkMenu *menuListPtr; char *oldCascadeName = NULL, *newMenuName = NULL; int cascadeEntryChanged; TkMenuReferences *oldCascadeMenuRefPtr, *cascadeMenuRefPtr = NULL; /* * Cascades are kind of tricky here. This is special case #3 in the comment * at the top of this file. Basically, if a menu is the master menu of a * clone chain, and has an entry with a cascade menu, the clones of * the menu will point to clones of the cascade menu. We have * to destroy the clones of the cascades, clone the new cascade * menu, and configure the entry to point to the new clone. */ mePtr = menuPtr->masterMenuPtr->entries[index]; if (mePtr->type == CASCADE_ENTRY) { oldCascadeName = mePtr->name; } if (ConfigureMenuEntry(mePtr, argc, argv, flags) != TCL_OK) { return TCL_ERROR; } cascadeEntryChanged = (mePtr->type == CASCADE_ENTRY) && (oldCascadeName != mePtr->name); if (cascadeEntryChanged) { newMenuName = mePtr->name; if (newMenuName != NULL) { cascadeMenuRefPtr = TkFindMenuReferences(menuPtr->interp, mePtr->name); } } for (menuListPtr = menuPtr->masterMenuPtr->nextInstancePtr; menuListPtr != NULL; menuListPtr = menuListPtr->nextInstancePtr) { mePtr = menuListPtr->entries[index]; if (cascadeEntryChanged && (mePtr->name != NULL)) { oldCascadeMenuRefPtr = TkFindMenuReferences(menuPtr->interp, mePtr->name); if ((oldCascadeMenuRefPtr != NULL) && (oldCascadeMenuRefPtr->menuPtr != NULL)) { RecursivelyDeleteMenu(oldCascadeMenuRefPtr->menuPtr); } } if (ConfigureMenuEntry(mePtr, argc, argv, flags) != TCL_OK) { return TCL_ERROR; } if (cascadeEntryChanged && (newMenuName != NULL)) { if (cascadeMenuRefPtr->menuPtr != NULL) { char *newArgV[2]; char *newCloneName; newCloneName = TkNewMenuName(menuPtr->interp, Tk_PathName(menuListPtr->tkwin), cascadeMenuRefPtr->menuPtr); CloneMenu(cascadeMenuRefPtr->menuPtr, newCloneName, "normal"); newArgV[0] = "-menu"; newArgV[1] = newCloneName; ConfigureMenuEntry(mePtr, 2, newArgV, flags); ckfree(newCloneName); } } } return TCL_OK;}/* *-------------------------------------------------------------- * * TkGetMenuIndex -- * * Parse a textual index into a menu and return the numerical * index of the indicated entry. * * Results: * A standard Tcl result. If all went well, then *indexPtr is * filled in with the entry index corresponding to string * (ranges from -1 to the number of entries in the menu minus * one). Otherwise an error message is left in interp->result. * * Side effects: * None. * *-------------------------------------------------------------- */intTkGetMenuIndex(interp, menuPtr, string, lastOK, indexPtr) Tcl_Interp *interp; /* For error messages. */ TkMenu *menuPtr; /* Menu for which the index is being * specified. */ char *string; /* Specification of an entry in menu. See * manual entry for valid .*/ int lastOK; /* Non-zero means its OK to return index * just *after* last entry. */ int *indexPtr; /* Where to store converted relief. */{ int i; if ((string[0] == 'a') && (strcmp(string, "active") == 0)) { *indexPtr = menuPtr->active; return TCL_OK; } if (((string[0] == 'l') && (strcmp(string, "last") == 0)) || ((string[0] == 'e') && (strcmp(string, "end") == 0))) { *indexPtr = menuPtr->numEntries - ((lastOK) ? 0 : 1); return TCL_OK; } if ((string[0] == 'n') && (strcmp(string, "none") == 0)) { *indexPtr = -1; return TCL_OK; } if (string[0] == '@') { if (GetIndexFromCoords(interp, menuPtr, string, indexPtr) == TCL_OK) { return TCL_OK; } } if (isdigit(UCHAR(string[0]))) { if (Tcl_GetInt(interp, string, &i) == TCL_OK) { if (i >= menuPtr->numEntries) { if (lastOK) { i = menuPtr->numEntries; } else { i = menuPtr->numEntries-1; } } else if (i < 0) { i = -1; } *indexPtr = i; return TCL_OK; } Tcl_SetResult(interp, (char *) NULL, TCL_STATIC); } for (i = 0; i < menuPtr->numEntries; i++) { char *label; label = menuPtr->entries[i]->label; if ((label != NULL) && (Tcl_StringMatch(menuPtr->entries[i]->label, string))) { *indexPtr = i; return TCL_OK; } } Tcl_AppendResult(interp, "bad menu entry index \"", string, "\"", (char *) NULL); return TCL_ERROR;}/* *---------------------------------------------------------------------- * * MenuCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */static voidMenuCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */{ TkMenu *menuPtr = (TkMenu *) clientData; Tk_Window tkwin = menuPtr->tkwin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { menuPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); }}/* *---------------------------------------------------------------------- * * MenuNewEntry -- * * This procedure allocates and initializes a new menu entry. * * Results: * The return value is a pointer to a new menu entry structure, * which has been malloc-ed, initialized, and entered into the * entry array for the menu. * * Side effects: * Storage gets allocated. * *---------------------------------------------------------------------- */static TkMenuEntry *MenuNewEntry(menuPtr, index, type) TkMenu *menuPtr; /* Menu that will hold the new entry. */ int index; /* Where in the menu the new entry is to * go. */ int type; /* The type of the new entry. */{ TkMenuEntry *mePtr; TkMenuEntry **newEntries; int i; /* * Create a new array of entries with an empty slot for the * new entry. */ newEntries = (TkMenuEntry **) ckalloc((unsigned) ((menuPtr->numEntries+1)*sizeof(TkMenuEntry *))); for (i = 0; i < index; i++) { newEntries[i] = menuPtr->entries[i]; } for ( ; i < menuPtr->numEntries; i++) { newEntries[i+1] = menuPtr->entries[i]; newEntries[i+1]->index = i + 1; } if (menuPtr->numEntries != 0) { ckfree((char *) menuPtr->entries); } menuPtr->entries = newEntries; menuPtr->numEntries++; mePtr = (TkMenuEntry *) ckalloc(sizeof(TkMenuEntry)); menuPtr->entries[index] = mePtr; mePtr->type = type; mePtr->menuPtr = menuPtr; mePtr->label = NULL; mePtr->labelLength = 0; mePtr->underline = -1; mePtr->bitmap = None; mePtr->imageString = NULL; mePtr->image = NULL; mePtr->selectImageString = NULL; mePtr->selectImage = NULL; mePtr->accel = NULL; mePtr->accelLength = 0; mePtr->state = tkNormalUid; mePtr->border = NULL; mePtr->fg = NULL; mePtr->activeBorder = NULL; mePtr->activeFg = NULL; mePtr->tkfont = NULL; mePtr->indicatorOn = 1; mePtr->indicatorFg = NULL; mePtr->columnBreak = 0; mePtr->hideMargin = 0; mePtr->command = NULL; mePtr->name = NULL; mePtr->childMenuRefPtr = NULL; mePtr->onValue = NULL; mePtr->offValue = NULL; mePtr->entryFlags = 0; mePtr->index = index; mePtr->nextCascadePtr = NULL; TkMenuInitializeEntryDrawingFields(mePtr); if (TkpMenuNewEntry(mePtr) != TCL_OK) { ckfree((char *) mePtr); return NULL; } return mePtr;}/* *---------------------------------------------------------------------- * * MenuAddOrInsert -- * * This procedure does all of the work of the "add" and "insert" * widget commands, allowing the code for these to be shared. * * Results: * A standard Tcl return value. * * Side effects: * A new menu entry is created in menuPtr. * *---------------------------------------------------------------------- */static intMenuAddOrInsert(interp, menuPtr, indexString, argc, argv) Tcl_Interp *interp; /* Used for error reporting. */ TkMenu *menuPtr; /* Widget in which to create new * entry. */ char *indexString; /* String describing index at which * to insert. NULL means insert at * end. */ int argc; /* Number of elements in argv. */ char **argv; /* Arguments to command: first arg * is type of entry, others are * config options. */{ int c, type, index; size_t length; TkMenuEntry *mePtr; TkMenu *menuListPtr; if (indexString != NULL) { if (TkGetMenuIndex(interp, menuPtr, indexString, 1, &index) != TCL_OK) { return TCL_ERROR; } } else { index = menuPtr->numEntries; } if (index < 0) { Tcl_AppendResult(interp, "bad index \"", indexString, "\"", (char *) NULL); return TCL_ERROR; } if (menuPtr->tearOff && (index == 0)) { index = 1; } /* * Figure out the type of the new entry. */ c = argv[0][0]; length = strlen(argv[0]); if ((c == 'c') && (strncmp(argv[0], "cascade", length) == 0) && (length >= 2)) { type = CASCADE_ENTRY; } else if ((c == 'c') && (strncmp(argv[0], "checkbutton", length) == 0) && (length >= 2)) { type = CHECK_BUTTON_ENTRY; } else if ((c == 'c') && (strncmp(argv[0], "command", length) == 0) && (length >= 2)) { type = COMMAND_ENTRY; } else if ((c == 'r') && (strncmp(argv[0], "radiobutton", length) == 0)) { type = RADIO_BUTTON_ENTRY; } else if ((c == 's') && (strncmp(argv[0], "separator", length) == 0)) { type = SEPARATOR_ENTRY; } else { Tcl_AppendResult(interp, "bad menu entry type \"", argv[0], "\": must be cascade, checkbutton, ", "command, radiobutton, or separator", (char *) NULL); return TCL_ERROR; } /* * Now we have to add an entry for every instance related to this menu. */ for (menuListPtr = menuPtr->masterMenuPtr; menuListPtr != NULL; menuListPtr = menuListPtr->nextInstancePtr) { mePtr = MenuNewEntry(menuListPtr, index, type); if (mePtr == NULL) { return TCL_ERROR; } if (ConfigureMenuEntry(mePtr, argc-1, argv+1, 0) != TCL_OK) { TkMenu *errorMenuPtr; int i; for (errorMenuPtr = menuPtr->masterMenuPtr; errorMenuPtr != NULL; errorMenuPtr = errorMenuPtr->nextInstancePtr) { Tcl_EventuallyFree((Clie
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -