1 |
dashley |
71 |
/* $Header$ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* tkMenubutton.c -- |
5 |
|
|
* |
6 |
|
|
* This module implements button-like widgets that are used |
7 |
|
|
* to invoke pull-down menus. |
8 |
|
|
* |
9 |
|
|
* Copyright (c) 1990-1994 The Regents of the University of California. |
10 |
|
|
* Copyright (c) 1994-1997 Sun Microsystems, Inc. |
11 |
|
|
* |
12 |
|
|
* See the file "license.terms" for information on usage and redistribution |
13 |
|
|
* of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
14 |
|
|
* |
15 |
|
|
* RCS: @(#) $Id: tkmenubutton.c,v 1.1.1.1 2001/06/13 05:05:54 dtashley Exp $ |
16 |
|
|
*/ |
17 |
|
|
|
18 |
|
|
#include "tkMenubutton.h" |
19 |
|
|
#include "tkPort.h" |
20 |
|
|
#include "default.h" |
21 |
|
|
|
22 |
|
|
/* |
23 |
|
|
* The following table defines the legal values for the -direction |
24 |
|
|
* option. It is used together with the "enum direction" declaration |
25 |
|
|
* in tkMenubutton.h. |
26 |
|
|
*/ |
27 |
|
|
|
28 |
|
|
static char *directionStrings[] = { |
29 |
|
|
"above", "below", "flush", "left", "right", (char *) NULL |
30 |
|
|
}; |
31 |
|
|
|
32 |
|
|
/* |
33 |
|
|
* The following table defines the legal values for the -state option. |
34 |
|
|
* It is used together with the "enum state" declaration in tkMenubutton.h. |
35 |
|
|
*/ |
36 |
|
|
|
37 |
|
|
static char *stateStrings[] = { |
38 |
|
|
"active", "disabled", "normal", (char *) NULL |
39 |
|
|
}; |
40 |
|
|
|
41 |
|
|
/* |
42 |
|
|
* Information used for parsing configuration specs: |
43 |
|
|
*/ |
44 |
|
|
|
45 |
|
|
static Tk_OptionSpec optionSpecs[] = { |
46 |
|
|
{TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground", |
47 |
|
|
DEF_MENUBUTTON_ACTIVE_BG_COLOR, -1, |
48 |
|
|
Tk_Offset(TkMenuButton, activeBorder), 0, |
49 |
|
|
(ClientData) DEF_MENUBUTTON_ACTIVE_BG_MONO, 0}, |
50 |
|
|
{TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background", |
51 |
|
|
DEF_MENUBUTTON_ACTIVE_FG_COLOR, -1, |
52 |
|
|
Tk_Offset(TkMenuButton, activeFg), |
53 |
|
|
0, (ClientData) DEF_MENUBUTTON_ACTIVE_FG_MONO, 0}, |
54 |
|
|
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", |
55 |
|
|
DEF_MENUBUTTON_ANCHOR, -1, |
56 |
|
|
Tk_Offset(TkMenuButton, anchor), 0, 0, 0}, |
57 |
|
|
{TK_OPTION_BORDER, "-background", "background", "Background", |
58 |
|
|
DEF_MENUBUTTON_BG_COLOR, -1, Tk_Offset(TkMenuButton, normalBorder), |
59 |
|
|
0, (ClientData) DEF_MENUBUTTON_BG_MONO, 0}, |
60 |
|
|
{TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, |
61 |
|
|
(char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0}, |
62 |
|
|
{TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, |
63 |
|
|
(char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, |
64 |
|
|
{TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap", |
65 |
|
|
DEF_MENUBUTTON_BITMAP, -1, Tk_Offset(TkMenuButton, bitmap), |
66 |
|
|
TK_OPTION_NULL_OK, 0, 0}, |
67 |
|
|
{TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", |
68 |
|
|
DEF_MENUBUTTON_BORDER_WIDTH, -1, |
69 |
|
|
Tk_Offset(TkMenuButton, borderWidth), 0, 0, 0}, |
70 |
|
|
{TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", |
71 |
|
|
DEF_MENUBUTTON_CURSOR, -1, Tk_Offset(TkMenuButton, cursor), |
72 |
|
|
TK_OPTION_NULL_OK, 0, 0}, |
73 |
|
|
{TK_OPTION_STRING_TABLE, "-direction", "direction", "Direction", |
74 |
|
|
DEF_MENUBUTTON_DIRECTION, -1, Tk_Offset(TkMenuButton, direction), |
75 |
|
|
0, (ClientData) directionStrings, 0}, |
76 |
|
|
{TK_OPTION_COLOR, "-disabledforeground", "disabledForeground", |
77 |
|
|
"DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_COLOR, |
78 |
|
|
-1, Tk_Offset(TkMenuButton, disabledFg), TK_OPTION_NULL_OK, |
79 |
|
|
(ClientData) DEF_MENUBUTTON_DISABLED_FG_MONO, 0}, |
80 |
|
|
{TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, |
81 |
|
|
(char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, |
82 |
|
|
{TK_OPTION_FONT, "-font", "font", "Font", |
83 |
|
|
DEF_MENUBUTTON_FONT, -1, Tk_Offset(TkMenuButton, tkfont), 0, 0, 0}, |
84 |
|
|
{TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", |
85 |
|
|
DEF_MENUBUTTON_FG, -1, Tk_Offset(TkMenuButton, normalFg), 0, 0, 0}, |
86 |
|
|
{TK_OPTION_STRING, "-height", "height", "Height", |
87 |
|
|
DEF_MENUBUTTON_HEIGHT, -1, Tk_Offset(TkMenuButton, heightString), |
88 |
|
|
0, 0, 0}, |
89 |
|
|
{TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", |
90 |
|
|
"HighlightBackground", DEF_MENUBUTTON_HIGHLIGHT_BG_COLOR, |
91 |
|
|
-1, Tk_Offset(TkMenuButton, highlightBgColorPtr), 0, 0, 0}, |
92 |
|
|
{TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", |
93 |
|
|
DEF_MENUBUTTON_HIGHLIGHT, -1, |
94 |
|
|
Tk_Offset(TkMenuButton, highlightColorPtr), 0, 0, 0}, |
95 |
|
|
{TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", |
96 |
|
|
"HighlightThickness", DEF_MENUBUTTON_HIGHLIGHT_WIDTH, |
97 |
|
|
-1, Tk_Offset(TkMenuButton, highlightWidth), 0, 0, 0}, |
98 |
|
|
{TK_OPTION_STRING, "-image", "image", "Image", |
99 |
|
|
DEF_MENUBUTTON_IMAGE, -1, Tk_Offset(TkMenuButton, imageString), |
100 |
|
|
TK_OPTION_NULL_OK, 0, 0}, |
101 |
|
|
{TK_OPTION_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn", |
102 |
|
|
DEF_MENUBUTTON_INDICATOR, -1, Tk_Offset(TkMenuButton, indicatorOn), |
103 |
|
|
0, 0, 0}, |
104 |
|
|
{TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", |
105 |
|
|
DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkMenuButton, justify), 0, 0, 0}, |
106 |
|
|
{TK_OPTION_STRING, "-menu", "menu", "Menu", |
107 |
|
|
DEF_MENUBUTTON_MENU, -1, Tk_Offset(TkMenuButton, menuName), |
108 |
|
|
TK_OPTION_NULL_OK, 0, 0}, |
109 |
|
|
{TK_OPTION_PIXELS, "-padx", "padX", "Pad", |
110 |
|
|
DEF_MENUBUTTON_PADX, -1, Tk_Offset(TkMenuButton, padX), |
111 |
|
|
0, 0, 0}, |
112 |
|
|
{TK_OPTION_PIXELS, "-pady", "padY", "Pad", |
113 |
|
|
DEF_MENUBUTTON_PADY, -1, Tk_Offset(TkMenuButton, padY), |
114 |
|
|
0, 0, 0}, |
115 |
|
|
{TK_OPTION_RELIEF, "-relief", "relief", "Relief", |
116 |
|
|
DEF_MENUBUTTON_RELIEF, -1, Tk_Offset(TkMenuButton, relief), |
117 |
|
|
0, 0, 0}, |
118 |
|
|
{TK_OPTION_STRING_TABLE, "-state", "state", "State", |
119 |
|
|
DEF_MENUBUTTON_STATE, -1, Tk_Offset(TkMenuButton, state), |
120 |
|
|
0, (ClientData) stateStrings, 0}, |
121 |
|
|
{TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", |
122 |
|
|
DEF_MENUBUTTON_TAKE_FOCUS, -1, |
123 |
|
|
Tk_Offset(TkMenuButton, takeFocus), TK_OPTION_NULL_OK, 0, 0}, |
124 |
|
|
{TK_OPTION_STRING, "-text", "text", "Text", |
125 |
|
|
DEF_MENUBUTTON_TEXT, -1, Tk_Offset(TkMenuButton, text), 0, 0, 0}, |
126 |
|
|
{TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", |
127 |
|
|
DEF_MENUBUTTON_TEXT_VARIABLE, -1, |
128 |
|
|
Tk_Offset(TkMenuButton, textVarName), TK_OPTION_NULL_OK, 0, 0}, |
129 |
|
|
{TK_OPTION_INT, "-underline", "underline", "Underline", |
130 |
|
|
DEF_MENUBUTTON_UNDERLINE, -1, Tk_Offset(TkMenuButton, underline), |
131 |
|
|
0, 0, 0}, |
132 |
|
|
{TK_OPTION_STRING, "-width", "width", "Width", |
133 |
|
|
DEF_MENUBUTTON_WIDTH, -1, Tk_Offset(TkMenuButton, widthString), |
134 |
|
|
0, 0, 0}, |
135 |
|
|
{TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength", |
136 |
|
|
DEF_MENUBUTTON_WRAP_LENGTH, -1, Tk_Offset(TkMenuButton, wrapLength), |
137 |
|
|
0, 0, 0}, |
138 |
|
|
{TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, |
139 |
|
|
(char *) NULL, 0, 0} |
140 |
|
|
}; |
141 |
|
|
|
142 |
|
|
/* |
143 |
|
|
* The following tables define the menubutton widget commands and map the |
144 |
|
|
* indexes into the string tables into a single enumerated type used |
145 |
|
|
* to dispatch the scale widget command. |
146 |
|
|
*/ |
147 |
|
|
|
148 |
|
|
static char *commandNames[] = { |
149 |
|
|
"cget", "configure", (char *) NULL |
150 |
|
|
}; |
151 |
|
|
|
152 |
|
|
enum command { |
153 |
|
|
COMMAND_CGET, COMMAND_CONFIGURE |
154 |
|
|
}; |
155 |
|
|
|
156 |
|
|
/* |
157 |
|
|
* Forward declarations for procedures defined later in this file: |
158 |
|
|
*/ |
159 |
|
|
|
160 |
|
|
static void MenuButtonCmdDeletedProc _ANSI_ARGS_(( |
161 |
|
|
ClientData clientData)); |
162 |
|
|
static void MenuButtonEventProc _ANSI_ARGS_((ClientData clientData, |
163 |
|
|
XEvent *eventPtr)); |
164 |
|
|
static void MenuButtonImageProc _ANSI_ARGS_((ClientData clientData, |
165 |
|
|
int x, int y, int width, int height, int imgWidth, |
166 |
|
|
int imgHeight)); |
167 |
|
|
static char * MenuButtonTextVarProc _ANSI_ARGS_(( |
168 |
|
|
ClientData clientData, Tcl_Interp *interp, |
169 |
|
|
char *name1, char *name2, int flags)); |
170 |
|
|
static int MenuButtonWidgetObjCmd _ANSI_ARGS_(( |
171 |
|
|
ClientData clientData, Tcl_Interp *interp, |
172 |
|
|
int objc, Tcl_Obj *CONST objv[])); |
173 |
|
|
static int ConfigureMenuButton _ANSI_ARGS_((Tcl_Interp *interp, |
174 |
|
|
TkMenuButton *mbPtr, int objc, |
175 |
|
|
Tcl_Obj *CONST objv[])); |
176 |
|
|
static void DestroyMenuButton _ANSI_ARGS_((char *memPtr)); |
177 |
|
|
|
178 |
|
|
/* |
179 |
|
|
*-------------------------------------------------------------- |
180 |
|
|
* |
181 |
|
|
* Tk_MenubuttonObjCmd -- |
182 |
|
|
* |
183 |
|
|
* This procedure is invoked to process the "button", "label", |
184 |
|
|
* "radiobutton", and "checkbutton" Tcl commands. See the |
185 |
|
|
* user documentation for details on what it does. |
186 |
|
|
* |
187 |
|
|
* Results: |
188 |
|
|
* A standard Tcl result. |
189 |
|
|
* |
190 |
|
|
* Side effects: |
191 |
|
|
* See the user documentation. |
192 |
|
|
* |
193 |
|
|
*-------------------------------------------------------------- |
194 |
|
|
*/ |
195 |
|
|
|
196 |
|
|
int |
197 |
|
|
Tk_MenubuttonObjCmd(clientData, interp, objc, objv) |
198 |
|
|
ClientData clientData; /* Either NULL or pointer to |
199 |
|
|
* option table. */ |
200 |
|
|
Tcl_Interp *interp; /* Current interpreter. */ |
201 |
|
|
int objc; /* Number of arguments. */ |
202 |
|
|
Tcl_Obj *CONST objv[]; /* Argument objects. */ |
203 |
|
|
{ |
204 |
|
|
register TkMenuButton *mbPtr; |
205 |
|
|
Tk_OptionTable optionTable; |
206 |
|
|
Tk_Window tkwin; |
207 |
|
|
|
208 |
|
|
optionTable = (Tk_OptionTable) clientData; |
209 |
|
|
if (optionTable == NULL) { |
210 |
|
|
Tcl_CmdInfo info; |
211 |
|
|
char *name; |
212 |
|
|
|
213 |
|
|
/* |
214 |
|
|
* We haven't created the option table for this widget class |
215 |
|
|
* yet. Do it now and save the table as the clientData for |
216 |
|
|
* the command, so we'll have access to it in future |
217 |
|
|
* invocations of the command. |
218 |
|
|
*/ |
219 |
|
|
|
220 |
|
|
optionTable = Tk_CreateOptionTable(interp, optionSpecs); |
221 |
|
|
name = Tcl_GetString(objv[0]); |
222 |
|
|
Tcl_GetCommandInfo(interp, name, &info); |
223 |
|
|
info.objClientData = (ClientData) optionTable; |
224 |
|
|
Tcl_SetCommandInfo(interp, name, &info); |
225 |
|
|
} |
226 |
|
|
|
227 |
|
|
if (objc < 2) { |
228 |
|
|
Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); |
229 |
|
|
return TCL_ERROR; |
230 |
|
|
} |
231 |
|
|
|
232 |
|
|
/* |
233 |
|
|
* Create the new window. |
234 |
|
|
*/ |
235 |
|
|
|
236 |
|
|
tkwin = Tk_CreateWindowFromPath(interp, |
237 |
|
|
Tk_MainWindow(interp), Tcl_GetString(objv[1]), (char *) NULL); |
238 |
|
|
if (tkwin == NULL) { |
239 |
|
|
return TCL_ERROR; |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
Tk_SetClass(tkwin, "Menubutton"); |
243 |
|
|
mbPtr = TkpCreateMenuButton(tkwin); |
244 |
|
|
|
245 |
|
|
TkSetClassProcs(tkwin, &tkpMenubuttonClass, (ClientData) mbPtr); |
246 |
|
|
|
247 |
|
|
/* |
248 |
|
|
* Initialize the data structure for the button. |
249 |
|
|
*/ |
250 |
|
|
|
251 |
|
|
mbPtr->tkwin = tkwin; |
252 |
|
|
mbPtr->display = Tk_Display (tkwin); |
253 |
|
|
mbPtr->interp = interp; |
254 |
|
|
mbPtr->widgetCmd = Tcl_CreateObjCommand(interp, |
255 |
|
|
Tk_PathName(mbPtr->tkwin), MenuButtonWidgetObjCmd, |
256 |
|
|
(ClientData) mbPtr, MenuButtonCmdDeletedProc); |
257 |
|
|
mbPtr->optionTable = optionTable; |
258 |
|
|
mbPtr->menuName = NULL; |
259 |
|
|
mbPtr->text = NULL; |
260 |
|
|
mbPtr->underline = -1; |
261 |
|
|
mbPtr->textVarName = NULL; |
262 |
|
|
mbPtr->bitmap = None; |
263 |
|
|
mbPtr->imageString = NULL; |
264 |
|
|
mbPtr->image = NULL; |
265 |
|
|
mbPtr->state = STATE_NORMAL; |
266 |
|
|
mbPtr->normalBorder = NULL; |
267 |
|
|
mbPtr->activeBorder = NULL; |
268 |
|
|
mbPtr->borderWidth = 0; |
269 |
|
|
mbPtr->relief = TK_RELIEF_FLAT; |
270 |
|
|
mbPtr->highlightWidth = 0; |
271 |
|
|
mbPtr->highlightBgColorPtr = NULL; |
272 |
|
|
mbPtr->highlightColorPtr = NULL; |
273 |
|
|
mbPtr->inset = 0; |
274 |
|
|
mbPtr->tkfont = NULL; |
275 |
|
|
mbPtr->normalFg = NULL; |
276 |
|
|
mbPtr->activeFg = NULL; |
277 |
|
|
mbPtr->disabledFg = NULL; |
278 |
|
|
mbPtr->normalTextGC = None; |
279 |
|
|
mbPtr->activeTextGC = None; |
280 |
|
|
mbPtr->gray = None; |
281 |
|
|
mbPtr->disabledGC = None; |
282 |
|
|
mbPtr->leftBearing = 0; |
283 |
|
|
mbPtr->rightBearing = 0; |
284 |
|
|
mbPtr->widthString = NULL; |
285 |
|
|
mbPtr->heightString = NULL; |
286 |
|
|
mbPtr->width = 0; |
287 |
|
|
mbPtr->width = 0; |
288 |
|
|
mbPtr->wrapLength = 0; |
289 |
|
|
mbPtr->padX = 0; |
290 |
|
|
mbPtr->padY = 0; |
291 |
|
|
mbPtr->anchor = TK_ANCHOR_CENTER; |
292 |
|
|
mbPtr->justify = TK_JUSTIFY_CENTER; |
293 |
|
|
mbPtr->textLayout = NULL; |
294 |
|
|
mbPtr->indicatorOn = 0; |
295 |
|
|
mbPtr->indicatorWidth = 0; |
296 |
|
|
mbPtr->indicatorHeight = 0; |
297 |
|
|
mbPtr->direction = DIRECTION_FLUSH; |
298 |
|
|
mbPtr->cursor = None; |
299 |
|
|
mbPtr->takeFocus = NULL; |
300 |
|
|
mbPtr->flags = 0; |
301 |
|
|
|
302 |
|
|
Tk_CreateEventHandler(mbPtr->tkwin, |
303 |
|
|
ExposureMask|StructureNotifyMask|FocusChangeMask, |
304 |
|
|
MenuButtonEventProc, (ClientData) mbPtr); |
305 |
|
|
|
306 |
|
|
if (Tk_InitOptions(interp, (char *) mbPtr, optionTable, tkwin) |
307 |
|
|
!= TCL_OK) { |
308 |
|
|
Tk_DestroyWindow(mbPtr->tkwin); |
309 |
|
|
return TCL_ERROR; |
310 |
|
|
} |
311 |
|
|
|
312 |
|
|
if (ConfigureMenuButton(interp, mbPtr, objc-2, objv+2) != TCL_OK) { |
313 |
|
|
Tk_DestroyWindow(mbPtr->tkwin); |
314 |
|
|
return TCL_ERROR; |
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_PathName(mbPtr->tkwin), |
318 |
|
|
-1); |
319 |
|
|
return TCL_OK; |
320 |
|
|
} |
321 |
|
|
|
322 |
|
|
/* |
323 |
|
|
*-------------------------------------------------------------- |
324 |
|
|
* |
325 |
|
|
* MenuButtonWidgetObjCmd -- |
326 |
|
|
* |
327 |
|
|
* This procedure is invoked to process the Tcl command |
328 |
|
|
* that corresponds to a widget managed by this module. |
329 |
|
|
* See the user documentation for details on what it does. |
330 |
|
|
* |
331 |
|
|
* Results: |
332 |
|
|
* A standard Tcl result. |
333 |
|
|
* |
334 |
|
|
* Side effects: |
335 |
|
|
* See the user documentation. |
336 |
|
|
* |
337 |
|
|
*-------------------------------------------------------------- |
338 |
|
|
*/ |
339 |
|
|
|
340 |
|
|
static int |
341 |
|
|
MenuButtonWidgetObjCmd(clientData, interp, objc, objv) |
342 |
|
|
ClientData clientData; /* Information about button widget. */ |
343 |
|
|
Tcl_Interp *interp; /* Current interpreter. */ |
344 |
|
|
int objc; /* Number of arguments. */ |
345 |
|
|
Tcl_Obj *CONST objv[]; /* Argument objects. */ |
346 |
|
|
{ |
347 |
|
|
register TkMenuButton *mbPtr = (TkMenuButton *) clientData; |
348 |
|
|
int result, index; |
349 |
|
|
Tcl_Obj *objPtr; |
350 |
|
|
|
351 |
|
|
if (objc < 2) { |
352 |
|
|
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); |
353 |
|
|
return TCL_ERROR; |
354 |
|
|
} |
355 |
|
|
result = Tcl_GetIndexFromObj(interp, objv[1], |
356 |
|
|
commandNames, "option", 0, &index); |
357 |
|
|
if (result != TCL_OK) { |
358 |
|
|
return result; |
359 |
|
|
} |
360 |
|
|
Tcl_Preserve((ClientData) mbPtr); |
361 |
|
|
|
362 |
|
|
switch (index) { |
363 |
|
|
case COMMAND_CGET: { |
364 |
|
|
if (objc != 3) { |
365 |
|
|
Tcl_WrongNumArgs(interp, 1, objv, "cget option"); |
366 |
|
|
goto error; |
367 |
|
|
} |
368 |
|
|
|
369 |
|
|
objPtr = Tk_GetOptionValue(interp, (char *) mbPtr, |
370 |
|
|
mbPtr->optionTable, objv[2], mbPtr->tkwin); |
371 |
|
|
if (objPtr == NULL) { |
372 |
|
|
goto error; |
373 |
|
|
} else { |
374 |
|
|
Tcl_SetObjResult(interp, objPtr); |
375 |
|
|
} |
376 |
|
|
break; |
377 |
|
|
} |
378 |
|
|
|
379 |
|
|
case COMMAND_CONFIGURE: { |
380 |
|
|
if (objc <= 3) { |
381 |
|
|
objPtr = Tk_GetOptionInfo(interp, (char *) mbPtr, |
382 |
|
|
mbPtr->optionTable, |
383 |
|
|
(objc == 3) ? objv[2] : (Tcl_Obj *) NULL, |
384 |
|
|
mbPtr->tkwin); |
385 |
|
|
if (objPtr == NULL) { |
386 |
|
|
goto error; |
387 |
|
|
} else { |
388 |
|
|
Tcl_SetObjResult(interp, objPtr); |
389 |
|
|
} |
390 |
|
|
} else { |
391 |
|
|
result = ConfigureMenuButton(interp, mbPtr, objc-2, |
392 |
|
|
objv+2); |
393 |
|
|
} |
394 |
|
|
break; |
395 |
|
|
} |
396 |
|
|
} |
397 |
|
|
Tcl_Release((ClientData) mbPtr); |
398 |
|
|
return result; |
399 |
|
|
|
400 |
|
|
error: |
401 |
|
|
Tcl_Release((ClientData) mbPtr); |
402 |
|
|
return TCL_ERROR; |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
/* |
406 |
|
|
*---------------------------------------------------------------------- |
407 |
|
|
* |
408 |
|
|
* DestroyMenuButton -- |
409 |
|
|
* |
410 |
|
|
* This procedure is invoked to recycle all of the resources |
411 |
|
|
* associated with a menubutton widget. It is invoked as a |
412 |
|
|
* when-idle handler in order to make sure that there is no |
413 |
|
|
* other use of the menubutton pending at the time of the deletion. |
414 |
|
|
* |
415 |
|
|
* Results: |
416 |
|
|
* None. |
417 |
|
|
* |
418 |
|
|
* Side effects: |
419 |
|
|
* Everything associated with the widget is freed up. |
420 |
|
|
* |
421 |
|
|
*---------------------------------------------------------------------- |
422 |
|
|
*/ |
423 |
|
|
|
424 |
|
|
static void |
425 |
|
|
DestroyMenuButton(memPtr) |
426 |
|
|
char *memPtr; /* Info about button widget. */ |
427 |
|
|
{ |
428 |
|
|
register TkMenuButton *mbPtr = (TkMenuButton *) memPtr; |
429 |
|
|
TkpDestroyMenuButton(mbPtr); |
430 |
|
|
|
431 |
|
|
if (mbPtr->flags & REDRAW_PENDING) { |
432 |
|
|
Tcl_CancelIdleCall(TkpDisplayMenuButton, (ClientData) mbPtr); |
433 |
|
|
} |
434 |
|
|
|
435 |
|
|
/* |
436 |
|
|
* Free up all the stuff that requires special handling, then |
437 |
|
|
* let Tk_FreeOptions handle all the standard option-related |
438 |
|
|
* stuff. |
439 |
|
|
*/ |
440 |
|
|
|
441 |
|
|
Tcl_DeleteCommandFromToken(mbPtr->interp, mbPtr->widgetCmd); |
442 |
|
|
if (mbPtr->textVarName != NULL) { |
443 |
|
|
Tcl_UntraceVar(mbPtr->interp, mbPtr->textVarName, |
444 |
|
|
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, |
445 |
|
|
MenuButtonTextVarProc, (ClientData) mbPtr); |
446 |
|
|
} |
447 |
|
|
if (mbPtr->image != NULL) { |
448 |
|
|
Tk_FreeImage(mbPtr->image); |
449 |
|
|
} |
450 |
|
|
if (mbPtr->normalTextGC != None) { |
451 |
|
|
Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC); |
452 |
|
|
} |
453 |
|
|
if (mbPtr->activeTextGC != None) { |
454 |
|
|
Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC); |
455 |
|
|
} |
456 |
|
|
if (mbPtr->disabledGC != None) { |
457 |
|
|
Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); |
458 |
|
|
} |
459 |
|
|
if (mbPtr->gray != None) { |
460 |
|
|
Tk_FreeBitmap(mbPtr->display, mbPtr->gray); |
461 |
|
|
} |
462 |
|
|
if (mbPtr->textLayout != NULL) { |
463 |
|
|
Tk_FreeTextLayout(mbPtr->textLayout); |
464 |
|
|
} |
465 |
|
|
Tk_FreeConfigOptions((char *) mbPtr, mbPtr->optionTable, |
466 |
|
|
mbPtr->tkwin); |
467 |
|
|
mbPtr->tkwin = NULL; |
468 |
|
|
Tcl_EventuallyFree((ClientData) mbPtr, TCL_DYNAMIC); |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
/* |
472 |
|
|
*---------------------------------------------------------------------- |
473 |
|
|
* |
474 |
|
|
* ConfigureMenuButton -- |
475 |
|
|
* |
476 |
|
|
* This procedure is called to process an argv/argc list, plus |
477 |
|
|
* the Tk option database, in order to configure (or |
478 |
|
|
* reconfigure) a menubutton widget. |
479 |
|
|
* |
480 |
|
|
* Results: |
481 |
|
|
* The return value is a standard Tcl result. If TCL_ERROR is |
482 |
|
|
* returned, then the interp's result contains an error message. |
483 |
|
|
* |
484 |
|
|
* Side effects: |
485 |
|
|
* Configuration information, such as text string, colors, font, |
486 |
|
|
* etc. get set for mbPtr; old resources get freed, if there |
487 |
|
|
* were any. The menubutton is redisplayed. |
488 |
|
|
* |
489 |
|
|
*---------------------------------------------------------------------- |
490 |
|
|
*/ |
491 |
|
|
|
492 |
|
|
static int |
493 |
|
|
ConfigureMenuButton(interp, mbPtr, objc, objv) |
494 |
|
|
Tcl_Interp *interp; /* Used for error reporting. */ |
495 |
|
|
register TkMenuButton *mbPtr; |
496 |
|
|
/* Information about widget; may or may |
497 |
|
|
* not already have values for some |
498 |
|
|
* fields. */ |
499 |
|
|
int objc; /* Number of valid entries in objv. */ |
500 |
|
|
Tcl_Obj *CONST objv[]; /* Arguments. */ |
501 |
|
|
{ |
502 |
|
|
Tk_SavedOptions savedOptions; |
503 |
|
|
Tcl_Obj *errorResult = NULL; |
504 |
|
|
int error; |
505 |
|
|
Tk_Image image; |
506 |
|
|
|
507 |
|
|
/* |
508 |
|
|
* Eliminate any existing trace on variables monitored by the |
509 |
|
|
* menubutton. |
510 |
|
|
*/ |
511 |
|
|
|
512 |
|
|
if (mbPtr->textVarName != NULL) { |
513 |
|
|
Tcl_UntraceVar(interp, mbPtr->textVarName, |
514 |
|
|
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, |
515 |
|
|
MenuButtonTextVarProc, (ClientData) mbPtr); |
516 |
|
|
} |
517 |
|
|
|
518 |
|
|
/* |
519 |
|
|
* The following loop is potentially executed twice. During the |
520 |
|
|
* first pass configuration options get set to their new values. |
521 |
|
|
* If there is an error in this pass, we execute a second pass |
522 |
|
|
* to restore all the options to their previous values. |
523 |
|
|
*/ |
524 |
|
|
|
525 |
|
|
for (error = 0; error <= 1; error++) { |
526 |
|
|
if (!error) { |
527 |
|
|
/* |
528 |
|
|
* First pass: set options to new values. |
529 |
|
|
*/ |
530 |
|
|
|
531 |
|
|
if (Tk_SetOptions(interp, (char *) mbPtr, |
532 |
|
|
mbPtr->optionTable, objc, objv, |
533 |
|
|
mbPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) { |
534 |
|
|
continue; |
535 |
|
|
} |
536 |
|
|
} else { |
537 |
|
|
/* |
538 |
|
|
* Second pass: restore options to old values. |
539 |
|
|
*/ |
540 |
|
|
|
541 |
|
|
errorResult = Tcl_GetObjResult(interp); |
542 |
|
|
Tcl_IncrRefCount(errorResult); |
543 |
|
|
Tk_RestoreSavedOptions(&savedOptions); |
544 |
|
|
} |
545 |
|
|
|
546 |
|
|
/* |
547 |
|
|
* A few options need special processing, such as setting the |
548 |
|
|
* background from a 3-D border, or filling in complicated |
549 |
|
|
* defaults that couldn't be specified to Tk_SetOptions. |
550 |
|
|
*/ |
551 |
|
|
|
552 |
|
|
if ((mbPtr->state == STATE_ACTIVE) |
553 |
|
|
&& !Tk_StrictMotif(mbPtr->tkwin)) { |
554 |
|
|
Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->activeBorder); |
555 |
|
|
} else { |
556 |
|
|
Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->normalBorder); |
557 |
|
|
} |
558 |
|
|
|
559 |
|
|
if (mbPtr->highlightWidth < 0) { |
560 |
|
|
mbPtr->highlightWidth = 0; |
561 |
|
|
} |
562 |
|
|
|
563 |
|
|
if (mbPtr->padX < 0) { |
564 |
|
|
mbPtr->padX = 0; |
565 |
|
|
} |
566 |
|
|
if (mbPtr->padY < 0) { |
567 |
|
|
mbPtr->padY = 0; |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
/* |
571 |
|
|
* Get the image for the widget, if there is one. Allocate the |
572 |
|
|
* new image before freeing the old one, so that the reference |
573 |
|
|
* count doesn't go to zero and cause image data to be discarded. |
574 |
|
|
*/ |
575 |
|
|
|
576 |
|
|
if (mbPtr->imageString != NULL) { |
577 |
|
|
image = Tk_GetImage(mbPtr->interp, mbPtr->tkwin, |
578 |
|
|
mbPtr->imageString, MenuButtonImageProc, |
579 |
|
|
(ClientData) mbPtr); |
580 |
|
|
if (image == NULL) { |
581 |
|
|
return TCL_ERROR; |
582 |
|
|
} |
583 |
|
|
} else { |
584 |
|
|
image = NULL; |
585 |
|
|
} |
586 |
|
|
if (mbPtr->image != NULL) { |
587 |
|
|
Tk_FreeImage(mbPtr->image); |
588 |
|
|
} |
589 |
|
|
mbPtr->image = image; |
590 |
|
|
|
591 |
|
|
/* |
592 |
|
|
* Recompute the geometry for the button. |
593 |
|
|
*/ |
594 |
|
|
|
595 |
|
|
if ((mbPtr->bitmap != None) || (mbPtr->image != NULL)) { |
596 |
|
|
if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->widthString, |
597 |
|
|
&mbPtr->width) != TCL_OK) { |
598 |
|
|
widthError: |
599 |
|
|
Tcl_AddErrorInfo(interp, "\n (processing -width option)"); |
600 |
|
|
continue; |
601 |
|
|
} |
602 |
|
|
if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->heightString, |
603 |
|
|
&mbPtr->height) != TCL_OK) { |
604 |
|
|
heightError: |
605 |
|
|
Tcl_AddErrorInfo(interp, "\n (processing -height option)"); |
606 |
|
|
continue; |
607 |
|
|
} |
608 |
|
|
} else { |
609 |
|
|
if (Tcl_GetInt(interp, mbPtr->widthString, &mbPtr->width) |
610 |
|
|
!= TCL_OK) { |
611 |
|
|
goto widthError; |
612 |
|
|
} |
613 |
|
|
if (Tcl_GetInt(interp, mbPtr->heightString, &mbPtr->height) |
614 |
|
|
!= TCL_OK) { |
615 |
|
|
goto heightError; |
616 |
|
|
} |
617 |
|
|
} |
618 |
|
|
break; |
619 |
|
|
} |
620 |
|
|
|
621 |
|
|
if (!error) { |
622 |
|
|
Tk_FreeSavedOptions(&savedOptions); |
623 |
|
|
} |
624 |
|
|
|
625 |
|
|
if ((mbPtr->image == NULL) && (mbPtr->bitmap == None) |
626 |
|
|
&& (mbPtr->textVarName != NULL)) { |
627 |
|
|
|
628 |
|
|
/* |
629 |
|
|
* The menubutton displays the value of a variable. |
630 |
|
|
* Set up a trace to watch for any changes in it, create |
631 |
|
|
* the variable if it doesn't exist, and fetch its |
632 |
|
|
* current value. |
633 |
|
|
*/ |
634 |
|
|
|
635 |
|
|
char *value; |
636 |
|
|
|
637 |
|
|
value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); |
638 |
|
|
if (value == NULL) { |
639 |
|
|
Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, |
640 |
|
|
TCL_GLOBAL_ONLY); |
641 |
|
|
} else { |
642 |
|
|
if (mbPtr->text != NULL) { |
643 |
|
|
ckfree(mbPtr->text); |
644 |
|
|
} |
645 |
|
|
mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); |
646 |
|
|
strcpy(mbPtr->text, value); |
647 |
|
|
} |
648 |
|
|
Tcl_TraceVar(interp, mbPtr->textVarName, |
649 |
|
|
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, |
650 |
|
|
MenuButtonTextVarProc, (ClientData) mbPtr); |
651 |
|
|
} |
652 |
|
|
|
653 |
|
|
TkMenuButtonWorldChanged((ClientData) mbPtr); |
654 |
|
|
if (error) { |
655 |
|
|
Tcl_SetObjResult(interp, errorResult); |
656 |
|
|
Tcl_DecrRefCount(errorResult); |
657 |
|
|
return TCL_ERROR; |
658 |
|
|
} else { |
659 |
|
|
return TCL_OK; |
660 |
|
|
} |
661 |
|
|
} |
662 |
|
|
|
663 |
|
|
/* |
664 |
|
|
*--------------------------------------------------------------------------- |
665 |
|
|
* |
666 |
|
|
* TkMenuButtonWorldChanged -- |
667 |
|
|
* |
668 |
|
|
* This procedure is called when the world has changed in some |
669 |
|
|
* way and the widget needs to recompute all its graphics contexts |
670 |
|
|
* and determine its new geometry. |
671 |
|
|
* |
672 |
|
|
* Results: |
673 |
|
|
* None. |
674 |
|
|
* |
675 |
|
|
* Side effects: |
676 |
|
|
* TkMenuButton will be relayed out and redisplayed. |
677 |
|
|
* |
678 |
|
|
*--------------------------------------------------------------------------- |
679 |
|
|
*/ |
680 |
|
|
|
681 |
|
|
void |
682 |
|
|
TkMenuButtonWorldChanged(instanceData) |
683 |
|
|
ClientData instanceData; /* Information about widget. */ |
684 |
|
|
{ |
685 |
|
|
XGCValues gcValues; |
686 |
|
|
GC gc; |
687 |
|
|
unsigned long mask; |
688 |
|
|
TkMenuButton *mbPtr; |
689 |
|
|
|
690 |
|
|
mbPtr = (TkMenuButton *) instanceData; |
691 |
|
|
|
692 |
|
|
gcValues.font = Tk_FontId(mbPtr->tkfont); |
693 |
|
|
gcValues.foreground = mbPtr->normalFg->pixel; |
694 |
|
|
gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel; |
695 |
|
|
|
696 |
|
|
/* |
697 |
|
|
* Note: GraphicsExpose events are disabled in GC's because they're |
698 |
|
|
* used to copy stuff from an off-screen pixmap onto the screen (we know |
699 |
|
|
* that there's no problem with obscured areas). |
700 |
|
|
*/ |
701 |
|
|
|
702 |
|
|
gcValues.graphics_exposures = False; |
703 |
|
|
mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; |
704 |
|
|
gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); |
705 |
|
|
if (mbPtr->normalTextGC != None) { |
706 |
|
|
Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC); |
707 |
|
|
} |
708 |
|
|
mbPtr->normalTextGC = gc; |
709 |
|
|
|
710 |
|
|
gcValues.font = Tk_FontId(mbPtr->tkfont); |
711 |
|
|
gcValues.foreground = mbPtr->activeFg->pixel; |
712 |
|
|
gcValues.background = Tk_3DBorderColor(mbPtr->activeBorder)->pixel; |
713 |
|
|
mask = GCForeground | GCBackground | GCFont; |
714 |
|
|
gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); |
715 |
|
|
if (mbPtr->activeTextGC != None) { |
716 |
|
|
Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC); |
717 |
|
|
} |
718 |
|
|
mbPtr->activeTextGC = gc; |
719 |
|
|
|
720 |
|
|
gcValues.font = Tk_FontId(mbPtr->tkfont); |
721 |
|
|
gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel; |
722 |
|
|
if ((mbPtr->disabledFg != NULL) && (mbPtr->imageString == NULL)) { |
723 |
|
|
gcValues.foreground = mbPtr->disabledFg->pixel; |
724 |
|
|
mask = GCForeground | GCBackground | GCFont; |
725 |
|
|
} else { |
726 |
|
|
gcValues.foreground = gcValues.background; |
727 |
|
|
mask = GCForeground; |
728 |
|
|
if (mbPtr->gray == None) { |
729 |
|
|
mbPtr->gray = Tk_GetBitmap(NULL, mbPtr->tkwin, |
730 |
|
|
Tk_GetUid("gray50")); |
731 |
|
|
} |
732 |
|
|
if (mbPtr->gray != None) { |
733 |
|
|
gcValues.fill_style = FillStippled; |
734 |
|
|
gcValues.stipple = mbPtr->gray; |
735 |
|
|
mask |= GCFillStyle | GCStipple; |
736 |
|
|
} |
737 |
|
|
} |
738 |
|
|
gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues); |
739 |
|
|
if (mbPtr->disabledGC != None) { |
740 |
|
|
Tk_FreeGC(mbPtr->display, mbPtr->disabledGC); |
741 |
|
|
} |
742 |
|
|
mbPtr->disabledGC = gc; |
743 |
|
|
|
744 |
|
|
TkpComputeMenuButtonGeometry(mbPtr); |
745 |
|
|
|
746 |
|
|
/* |
747 |
|
|
* Lastly, arrange for the button to be redisplayed. |
748 |
|
|
*/ |
749 |
|
|
|
750 |
|
|
if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) { |
751 |
|
|
Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); |
752 |
|
|
mbPtr->flags |= REDRAW_PENDING; |
753 |
|
|
} |
754 |
|
|
} |
755 |
|
|
|
756 |
|
|
/* |
757 |
|
|
*-------------------------------------------------------------- |
758 |
|
|
* |
759 |
|
|
* MenuButtonEventProc -- |
760 |
|
|
* |
761 |
|
|
* This procedure is invoked by the Tk dispatcher for various |
762 |
|
|
* events on buttons. |
763 |
|
|
* |
764 |
|
|
* Results: |
765 |
|
|
* None. |
766 |
|
|
* |
767 |
|
|
* Side effects: |
768 |
|
|
* When the window gets deleted, internal structures get |
769 |
|
|
* cleaned up. When it gets exposed, it is redisplayed. |
770 |
|
|
* |
771 |
|
|
*-------------------------------------------------------------- |
772 |
|
|
*/ |
773 |
|
|
|
774 |
|
|
static void |
775 |
|
|
MenuButtonEventProc(clientData, eventPtr) |
776 |
|
|
ClientData clientData; /* Information about window. */ |
777 |
|
|
XEvent *eventPtr; /* Information about event. */ |
778 |
|
|
{ |
779 |
|
|
TkMenuButton *mbPtr = (TkMenuButton *) clientData; |
780 |
|
|
if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { |
781 |
|
|
goto redraw; |
782 |
|
|
} else if (eventPtr->type == ConfigureNotify) { |
783 |
|
|
/* |
784 |
|
|
* Must redraw after size changes, since layout could have changed |
785 |
|
|
* and borders will need to be redrawn. |
786 |
|
|
*/ |
787 |
|
|
|
788 |
|
|
goto redraw; |
789 |
|
|
} else if (eventPtr->type == DestroyNotify) { |
790 |
|
|
DestroyMenuButton((char *) mbPtr); |
791 |
|
|
} else if (eventPtr->type == FocusIn) { |
792 |
|
|
if (eventPtr->xfocus.detail != NotifyInferior) { |
793 |
|
|
mbPtr->flags |= GOT_FOCUS; |
794 |
|
|
if (mbPtr->highlightWidth > 0) { |
795 |
|
|
goto redraw; |
796 |
|
|
} |
797 |
|
|
} |
798 |
|
|
} else if (eventPtr->type == FocusOut) { |
799 |
|
|
if (eventPtr->xfocus.detail != NotifyInferior) { |
800 |
|
|
mbPtr->flags &= ~GOT_FOCUS; |
801 |
|
|
if (mbPtr->highlightWidth > 0) { |
802 |
|
|
goto redraw; |
803 |
|
|
} |
804 |
|
|
} |
805 |
|
|
} |
806 |
|
|
return; |
807 |
|
|
|
808 |
|
|
redraw: |
809 |
|
|
if ((mbPtr->tkwin != NULL) && !(mbPtr->flags & REDRAW_PENDING)) { |
810 |
|
|
Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); |
811 |
|
|
mbPtr->flags |= REDRAW_PENDING; |
812 |
|
|
} |
813 |
|
|
} |
814 |
|
|
|
815 |
|
|
/* |
816 |
|
|
*---------------------------------------------------------------------- |
817 |
|
|
* |
818 |
|
|
* MenuButtonCmdDeletedProc -- |
819 |
|
|
* |
820 |
|
|
* This procedure is invoked when a widget command is deleted. If |
821 |
|
|
* the widget isn't already in the process of being destroyed, |
822 |
|
|
* this command destroys it. |
823 |
|
|
* |
824 |
|
|
* Results: |
825 |
|
|
* None. |
826 |
|
|
* |
827 |
|
|
* Side effects: |
828 |
|
|
* The widget is destroyed. |
829 |
|
|
* |
830 |
|
|
*---------------------------------------------------------------------- |
831 |
|
|
*/ |
832 |
|
|
|
833 |
|
|
static void |
834 |
|
|
MenuButtonCmdDeletedProc(clientData) |
835 |
|
|
ClientData clientData; /* Pointer to widget record for widget. */ |
836 |
|
|
{ |
837 |
|
|
TkMenuButton *mbPtr = (TkMenuButton *) clientData; |
838 |
|
|
Tk_Window tkwin = mbPtr->tkwin; |
839 |
|
|
|
840 |
|
|
/* |
841 |
|
|
* This procedure could be invoked either because the window was |
842 |
|
|
* destroyed and the command was then deleted (in which case tkwin |
843 |
|
|
* is NULL) or because the command was deleted, and then this procedure |
844 |
|
|
* destroys the widget. |
845 |
|
|
*/ |
846 |
|
|
|
847 |
|
|
if (tkwin != NULL) { |
848 |
|
|
Tk_DestroyWindow(tkwin); |
849 |
|
|
} |
850 |
|
|
} |
851 |
|
|
|
852 |
|
|
/* |
853 |
|
|
*-------------------------------------------------------------- |
854 |
|
|
* |
855 |
|
|
* MenuButtonTextVarProc -- |
856 |
|
|
* |
857 |
|
|
* This procedure is invoked when someone changes the variable |
858 |
|
|
* whose contents are to be displayed in a menu button. |
859 |
|
|
* |
860 |
|
|
* Results: |
861 |
|
|
* NULL is always returned. |
862 |
|
|
* |
863 |
|
|
* Side effects: |
864 |
|
|
* The text displayed in the menu button will change to match the |
865 |
|
|
* variable. |
866 |
|
|
* |
867 |
|
|
*-------------------------------------------------------------- |
868 |
|
|
*/ |
869 |
|
|
|
870 |
|
|
/* ARGSUSED */ |
871 |
|
|
static char * |
872 |
|
|
MenuButtonTextVarProc(clientData, interp, name1, name2, flags) |
873 |
|
|
ClientData clientData; /* Information about button. */ |
874 |
|
|
Tcl_Interp *interp; /* Interpreter containing variable. */ |
875 |
|
|
char *name1; /* Name of variable. */ |
876 |
|
|
char *name2; /* Second part of variable name. */ |
877 |
|
|
int flags; /* Information about what happened. */ |
878 |
|
|
{ |
879 |
|
|
register TkMenuButton *mbPtr = (TkMenuButton *) clientData; |
880 |
|
|
char *value; |
881 |
|
|
|
882 |
|
|
/* |
883 |
|
|
* If the variable is unset, then immediately recreate it unless |
884 |
|
|
* the whole interpreter is going away. |
885 |
|
|
*/ |
886 |
|
|
|
887 |
|
|
if (flags & TCL_TRACE_UNSETS) { |
888 |
|
|
if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { |
889 |
|
|
Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, |
890 |
|
|
TCL_GLOBAL_ONLY); |
891 |
|
|
Tcl_TraceVar(interp, mbPtr->textVarName, |
892 |
|
|
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, |
893 |
|
|
MenuButtonTextVarProc, clientData); |
894 |
|
|
} |
895 |
|
|
return (char *) NULL; |
896 |
|
|
} |
897 |
|
|
|
898 |
|
|
value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); |
899 |
|
|
if (value == NULL) { |
900 |
|
|
value = ""; |
901 |
|
|
} |
902 |
|
|
if (mbPtr->text != NULL) { |
903 |
|
|
ckfree(mbPtr->text); |
904 |
|
|
} |
905 |
|
|
mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); |
906 |
|
|
strcpy(mbPtr->text, value); |
907 |
|
|
TkpComputeMenuButtonGeometry(mbPtr); |
908 |
|
|
|
909 |
|
|
if ((mbPtr->tkwin != NULL) && Tk_IsMapped(mbPtr->tkwin) |
910 |
|
|
&& !(mbPtr->flags & REDRAW_PENDING)) { |
911 |
|
|
Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); |
912 |
|
|
mbPtr->flags |= REDRAW_PENDING; |
913 |
|
|
} |
914 |
|
|
return (char *) NULL; |
915 |
|
|
} |
916 |
|
|
|
917 |
|
|
/* |
918 |
|
|
*---------------------------------------------------------------------- |
919 |
|
|
* |
920 |
|
|
* MenuButtonImageProc -- |
921 |
|
|
* |
922 |
|
|
* This procedure is invoked by the image code whenever the manager |
923 |
|
|
* for an image does something that affects the size of contents |
924 |
|
|
* of an image displayed in a button. |
925 |
|
|
* |
926 |
|
|
* Results: |
927 |
|
|
* None. |
928 |
|
|
* |
929 |
|
|
* Side effects: |
930 |
|
|
* Arranges for the button to get redisplayed. |
931 |
|
|
* |
932 |
|
|
*---------------------------------------------------------------------- |
933 |
|
|
*/ |
934 |
|
|
|
935 |
|
|
static void |
936 |
|
|
MenuButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight) |
937 |
|
|
ClientData clientData; /* Pointer to widget record. */ |
938 |
|
|
int x, y; /* Upper left pixel (within image) |
939 |
|
|
* that must be redisplayed. */ |
940 |
|
|
int width, height; /* Dimensions of area to redisplay |
941 |
|
|
* (may be <= 0). */ |
942 |
|
|
int imgWidth, imgHeight; /* New dimensions of image. */ |
943 |
|
|
{ |
944 |
|
|
register TkMenuButton *mbPtr = (TkMenuButton *) clientData; |
945 |
|
|
|
946 |
|
|
if (mbPtr->tkwin != NULL) { |
947 |
|
|
TkpComputeMenuButtonGeometry(mbPtr); |
948 |
|
|
if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) { |
949 |
|
|
Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr); |
950 |
|
|
mbPtr->flags |= REDRAW_PENDING; |
951 |
|
|
} |
952 |
|
|
} |
953 |
|
|
} |
954 |
|
|
|
955 |
|
|
/* End of tkmenubutton.c */ |