OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkMenubutton.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.