📄 tkmenu.c
字号:
/* * tkMenu.c -- * * This file contains most of the code for implementing menus in Tk. It takes * care of all of the generic (platform-independent) parts of menus, and * is supplemented by platform-specific files. The geometry calculation * and drawing code for menus is in the file tkMenuDraw.c * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkMenu.c 1.148 97/10/29 09:22:00 *//* * Notes on implementation of menus: * * Menus can be used in three ways: * - as a popup menu, either as part of a menubutton or standalone. * - as a menubar. The menu's cascade items are arranged according to * the specific platform to provide the user access to the menus at all * times * - as a tearoff palette. This is a window with the menu's items in it. * * The goal is to provide the Tk developer with a way to use a common * set of menus for all of these tasks. * * In order to make the bindings for cascade menus work properly under Unix, * the cascade menus' pathnames must be proper children of the menu that * they are cascade from. So if there is a menu .m, and it has two * cascades labelled "File" and "Edit", the cascade menus might have * the pathnames .m.file and .m.edit. Another constraint is that the menus * used for menubars must be children of the toplevel widget that they * are attached to. And on the Macintosh, the platform specific menu handle * for cascades attached to a menu bar must have a title that matches the * label for the cascade menu. * * To handle all of the constraints, Tk menubars and tearoff menus are * implemented using menu clones. Menu clones are full menus in their own * right; they have a Tk window and pathname associated with them; they have * a TkMenu structure and array of entries. However, they are linked with the * original menu that they were cloned from. The reflect the attributes of * the original, or "master", menu. So if an item is added to a menu, and * that menu has clones, then the item must be added to all of its clones * also. Menus are cloned when a menu is torn-off or when a menu is assigned * as a menubar using the "-menu" option of the toplevel's pathname configure * subcommand. When a clone is destroyed, only the clone is destroyed, but * when the master menu is destroyed, all clones are also destroyed. This * allows the developer to just deal with one set of menus when creating * and destroying. * * Clones are rather tricky when a menu with cascade entries is cloned (such * as a menubar). Not only does the menu have to be cloned, but each cascade * entry's corresponding menu must also be cloned. This maintains the pathname * parent-child hierarchy necessary for menubars and toplevels to work. * This leads to several special cases: * * 1. When a new menu is created, and it is pointed to by cascade entries in * cloned menus, the new menu has to be cloned to parallel the cascade * structure. * 2. When a cascade item is added to a menu that has been cloned, and the * menu that the cascade item points to exists, that menu has to be cloned. * 3. When the menu that a cascade entry points to is changed, the old * cloned cascade menu has to be discarded, and the new one has to be cloned. * */#include "tkPort.h"#include "tkMenu.h"#define MENU_HASH_KEY "tkMenus"static int menusInitialized; /* Whether or not the hash tables, etc., have * been setup *//* * Configuration specs for individual menu entries. If this changes, be sure * to update code in TkpMenuInit that changes the font string entry. */Tk_ConfigSpec tkMenuEntryConfigSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_ACTIVE_BG, Tk_Offset(TkMenuEntry, activeBorder), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-activeforeground", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_ACTIVE_FG, Tk_Offset(TkMenuEntry, activeFg), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-accelerator", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_ACCELERATOR, Tk_Offset(TkMenuEntry, accel), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_NULL_OK}, {TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_BG, Tk_Offset(TkMenuEntry, border), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |SEPARATOR_MASK|TEAROFF_MASK|TK_CONFIG_NULL_OK}, {TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_BITMAP, Tk_Offset(TkMenuEntry, bitmap), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-columnbreak", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_COLUMN_BREAK, Tk_Offset(TkMenuEntry, columnBreak), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK}, {TK_CONFIG_STRING, "-command", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_COMMAND, Tk_Offset(TkMenuEntry, command), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_NULL_OK}, {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_FONT, Tk_Offset(TkMenuEntry, tkfont), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_FG, Tk_Offset(TkMenuEntry, fg), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-hidemargin", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_HIDE_MARGIN, Tk_Offset(TkMenuEntry, hideMargin), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |SEPARATOR_MASK|TEAROFF_MASK}, {TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_IMAGE, Tk_Offset(TkMenuEntry, imageString), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-indicatoron", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_INDICATOR, Tk_Offset(TkMenuEntry, indicatorOn), CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-label", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_LABEL, Tk_Offset(TkMenuEntry, label), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK}, {TK_CONFIG_STRING, "-menu", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_MENU, Tk_Offset(TkMenuEntry, name), CASCADE_MASK|TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-offvalue", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_OFF_VALUE, Tk_Offset(TkMenuEntry, offValue), CHECK_BUTTON_MASK}, {TK_CONFIG_STRING, "-onvalue", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_ON_VALUE, Tk_Offset(TkMenuEntry, onValue), CHECK_BUTTON_MASK}, {TK_CONFIG_COLOR, "-selectcolor", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_SELECT, Tk_Offset(TkMenuEntry, indicatorFg), CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-selectimage", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_SELECT_IMAGE, Tk_Offset(TkMenuEntry, selectImageString), CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, {TK_CONFIG_UID, "-state", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_STATE, Tk_Offset(TkMenuEntry, state), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TEAROFF_MASK|TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_STRING, "-value", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_VALUE, Tk_Offset(TkMenuEntry, onValue), RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-variable", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_CHECK_VARIABLE, Tk_Offset(TkMenuEntry, name), CHECK_BUTTON_MASK|TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-variable", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_RADIO_VARIABLE, Tk_Offset(TkMenuEntry, name), RADIO_BUTTON_MASK}, {TK_CONFIG_INT, "-underline", (char *) NULL, (char *) NULL, DEF_MENU_ENTRY_UNDERLINE, Tk_Offset(TkMenuEntry, underline), COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK |TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0}};/* * Configuration specs valid for the menu as a whole. If this changes, be sure * to update code in TkpMenuInit that changes the font string entry. */Tk_ConfigSpec tkMenuConfigSpecs[] = { {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_MENU_ACTIVE_BG_COLOR, Tk_Offset(TkMenu, activeBorder), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground", DEF_MENU_ACTIVE_BG_MONO, Tk_Offset(TkMenu, activeBorder), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_PIXELS, "-activeborderwidth", "activeBorderWidth", "BorderWidth", DEF_MENU_ACTIVE_BORDER_WIDTH, Tk_Offset(TkMenu, activeBorderWidth), 0}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", DEF_MENU_ACTIVE_FG_COLOR, Tk_Offset(TkMenu, activeFg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background", DEF_MENU_ACTIVE_FG_MONO, Tk_Offset(TkMenu, activeFg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_MENU_BG_COLOR, Tk_Offset(TkMenu, border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_MENU_BG_MONO, Tk_Offset(TkMenu, border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, (char *) NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, (char *) NULL, 0, 0}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_MENU_BORDER_WIDTH, Tk_Offset(TkMenu, borderWidth), 0}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_MENU_CURSOR, Tk_Offset(TkMenu, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_MENU_DISABLED_FG_COLOR, Tk_Offset(TkMenu, disabledFg), TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground", "DisabledForeground", DEF_MENU_DISABLED_FG_MONO, Tk_Offset(TkMenu, disabledFg), TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, (char *) NULL, 0, 0}, {TK_CONFIG_FONT, "-font", "font", "Font", DEF_MENU_FONT, Tk_Offset(TkMenu, tkfont), 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_MENU_FG, Tk_Offset(TkMenu, fg), 0}, {TK_CONFIG_STRING, "-postcommand", "postCommand", "Command", DEF_MENU_POST_COMMAND, Tk_Offset(TkMenu, postCommand), TK_CONFIG_NULL_OK}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_MENU_RELIEF, Tk_Offset(TkMenu, relief), 0}, {TK_CONFIG_COLOR, "-selectcolor", "selectColor", "Background", DEF_MENU_SELECT_COLOR, Tk_Offset(TkMenu, indicatorFg), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_COLOR, "-selectcolor", "selectColor", "Background", DEF_MENU_SELECT_MONO, Tk_Offset(TkMenu, indicatorFg), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_MENU_TAKE_FOCUS, Tk_Offset(TkMenu, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-tearoff", "tearOff", "TearOff", DEF_MENU_TEAROFF, Tk_Offset(TkMenu, tearOff), 0}, {TK_CONFIG_STRING, "-tearoffcommand", "tearOffCommand", "TearOffCommand", DEF_MENU_TEAROFF_CMD, Tk_Offset(TkMenu, tearOffCommand), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-title", "title", "Title", DEF_MENU_TITLE, Tk_Offset(TkMenu, title), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-type", "type", "Type", DEF_MENU_TYPE, Tk_Offset(TkMenu, menuTypeName), TK_CONFIG_NULL_OK}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0}};/* * Prototypes for static procedures in this file: */static int CloneMenu _ANSI_ARGS_((TkMenu *menuPtr, char *newMenuName, char *newMenuTypeString));static int ConfigureMenu _ANSI_ARGS_((Tcl_Interp *interp, TkMenu *menuPtr, int argc, char **argv, int flags));static int ConfigureMenuCloneEntries _ANSI_ARGS_(( Tcl_Interp *interp, TkMenu *menuPtr, int index, int argc, char **argv, int flags));static int ConfigureMenuEntry _ANSI_ARGS_((TkMenuEntry *mePtr, int argc, char **argv, int flags));static void DeleteMenuCloneEntries _ANSI_ARGS_((TkMenu *menuPtr, int first, int last));static void DestroyMenuHashTable _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp));static void DestroyMenuInstance _ANSI_ARGS_((TkMenu *menuPtr));static void DestroyMenuEntry _ANSI_ARGS_((char *memPtr));static int GetIndexFromCoords _ANSI_ARGS_((Tcl_Interp *interp, TkMenu *menuPtr, char *string, int *indexPtr));static int MenuDoYPosition _ANSI_ARGS_((Tcl_Interp *interp, TkMenu *menuPtr, char *arg));static int MenuAddOrInsert _ANSI_ARGS_((Tcl_Interp *interp, TkMenu *menuPtr, char *indexString, int argc, char **argv));static void MenuCmdDeletedProc _ANSI_ARGS_(( ClientData clientData));static TkMenuEntry * MenuNewEntry _ANSI_ARGS_((TkMenu *menuPtr, int index, int type));static char * MenuVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags));static int MenuWidgetCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv));static void MenuWorldChanged _ANSI_ARGS_(( ClientData instanceData));static void RecursivelyDeleteMenu _ANSI_ARGS_((TkMenu *menuPtr));static void UnhookCascadeEntry _ANSI_ARGS_((TkMenuEntry *mePtr));/* * The structure below is a list of procs that respond to certain window * manager events. One of these includes a font change, which forces * the geometry proc to be called. */static TkClassProcs menuClass = { NULL, /* createProc. */ MenuWorldChanged /* geometryProc. */};/* *-------------------------------------------------------------- * * Tk_MenuCmd -- * * This procedure is invoked to process the "menu" Tcl * command. See the user documentation for details on * what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */intTk_MenuCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ Tk_Window tkwin = (Tk_Window) clientData; Tk_Window new; register TkMenu *menuPtr; TkMenuReferences *menuRefPtr; int i, len; char *arg, c; int toplevel; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " pathName ?options?\"", (char *) NULL); return TCL_ERROR; } TkMenuInit(); toplevel = 1; for (i = 2; i < argc; i += 2) { arg = argv[i]; len = strlen(arg); if (len < 2) { continue; } c = arg[1]; if ((c == 't') && (strncmp(arg, "-type", strlen(arg)) == 0) && (len >= 3)) { if (strcmp(argv[i + 1], "menubar") == 0) { toplevel = 0; } break; } } new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], toplevel ? "" : NULL); if (new == NULL) { return TCL_ERROR; } /* * Initialize the data structure for the menu. */ menuPtr = (TkMenu *) ckalloc(sizeof(TkMenu)); menuPtr->tkwin = new; menuPtr->display = Tk_Display(new); menuPtr->interp = interp; menuPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(menuPtr->tkwin), MenuWidgetCmd, (ClientData) menuPtr, MenuCmdDeletedProc); menuPtr->entries = NULL; menuPtr->numEntries = 0; menuPtr->active = -1; menuPtr->border = NULL; menuPtr->borderWidth = 0; menuPtr->relief = TK_RELIEF_FLAT; menuPtr->activeBorder = NULL; menuPtr->activeBorderWidth = 0; menuPtr->tkfont = NULL; menuPtr->fg = NULL; menuPtr->disabledFg = NULL; menuPtr->activeFg = NULL; menuPtr->indicatorFg = NULL; menuPtr->tearOff = 1; menuPtr->tearOffCommand = NULL; menuPtr->cursor = None; menuPtr->takeFocus = NULL; menuPtr->postCommand = NULL; menuPtr->postCommandGeneration = 0; menuPtr->postedCascade = NULL; menuPtr->nextInstancePtr = NULL; menuPtr->masterMenuPtr = menuPtr; menuPtr->menuType = UNKNOWN_TYPE; menuPtr->menuFlags = 0; menuPtr->parentTopLevelPtr = NULL; menuPtr->menuTypeName = NULL; menuPtr->title = NULL; TkMenuInitializeDrawingFields(menuPtr); menuRefPtr = TkCreateMenuReferences(menuPtr->interp, Tk_PathName(menuPtr->tkwin)); menuRefPtr->menuPtr = menuPtr; menuPtr->menuRefPtr = menuRefPtr; if (TCL_OK != TkpNewMenu(menuPtr)) { goto error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -