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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkButton.c --
3
 *
4
 *      This module implements a collection of button-like
5
 *      widgets for the Tk toolkit.  The widgets implemented
6
 *      include labels, buttons, check buttons, and radio
7
 *      buttons.
8
 *
9
 * Copyright (c) 1990-1994 The Regents of the University of California.
10
 * Copyright (c) 1994-1995 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: tkButton.c,v 1.1.1.1 2002-01-16 10:25:50 markom Exp $
16
 */
17
 
18
#include "tkButton.h"
19
#include "default.h"
20
 
21
/*
22
 * Class names for buttons, indexed by one of the type values above.
23
 */
24
 
25
static char *classNames[] = {"Label", "Button", "Checkbutton", "Radiobutton"};
26
 
27
/*
28
 * The class procedure table for the button widget.
29
 */
30
 
31
static int configFlags[] = {LABEL_MASK, BUTTON_MASK,
32
        CHECK_BUTTON_MASK, RADIO_BUTTON_MASK};
33
 
34
/*
35
 * Information used for parsing configuration specs:
36
 */
37
 
38
Tk_ConfigSpec tkpButtonConfigSpecs[] = {
39
    {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
40
        DEF_BUTTON_ACTIVE_BG_COLOR, Tk_Offset(TkButton, activeBorder),
41
        BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK
42
        |TK_CONFIG_COLOR_ONLY},
43
    {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
44
        DEF_BUTTON_ACTIVE_BG_MONO, Tk_Offset(TkButton, activeBorder),
45
        BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK
46
        |TK_CONFIG_MONO_ONLY},
47
    {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
48
        DEF_BUTTON_ACTIVE_FG_COLOR, Tk_Offset(TkButton, activeFg),
49
        BUTTON_MASK|TK_CONFIG_COLOR_ONLY},
50
    {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
51
        DEF_CHKRAD_ACTIVE_FG_COLOR, Tk_Offset(TkButton, activeFg),
52
        CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY},
53
    {TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
54
        DEF_BUTTON_ACTIVE_FG_MONO, Tk_Offset(TkButton, activeFg),
55
        BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK
56
        |TK_CONFIG_MONO_ONLY},
57
    {TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
58
        DEF_BUTTON_ANCHOR, Tk_Offset(TkButton, anchor), ALL_MASK},
59
    {TK_CONFIG_BORDER, "-background", "background", "Background",
60
        DEF_BUTTON_BG_COLOR, Tk_Offset(TkButton, normalBorder),
61
        ALL_MASK | TK_CONFIG_COLOR_ONLY},
62
    {TK_CONFIG_BORDER, "-background", "background", "Background",
63
        DEF_BUTTON_BG_MONO, Tk_Offset(TkButton, normalBorder),
64
        ALL_MASK | TK_CONFIG_MONO_ONLY},
65
    {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
66
        (char *) NULL, 0, ALL_MASK},
67
    {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
68
        (char *) NULL, 0, ALL_MASK},
69
    {TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap",
70
        DEF_BUTTON_BITMAP, Tk_Offset(TkButton, bitmap),
71
        ALL_MASK|TK_CONFIG_NULL_OK},
72
    {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
73
        DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidth), ALL_MASK},
74
    {TK_CONFIG_STRING, "-command", "command", "Command",
75
        DEF_BUTTON_COMMAND, Tk_Offset(TkButton, command),
76
        BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK},
77
    {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
78
        DEF_BUTTON_CURSOR, Tk_Offset(TkButton, cursor),
79
        ALL_MASK|TK_CONFIG_NULL_OK},
80
    {TK_CONFIG_UID, "-default", "default", "Default",
81
        DEF_BUTTON_DEFAULT, Tk_Offset(TkButton, defaultState), BUTTON_MASK},
82
    {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
83
        "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR,
84
        Tk_Offset(TkButton, disabledFg), BUTTON_MASK|CHECK_BUTTON_MASK
85
        |RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK},
86
    {TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
87
        "DisabledForeground", DEF_BUTTON_DISABLED_FG_MONO,
88
        Tk_Offset(TkButton, disabledFg), BUTTON_MASK|CHECK_BUTTON_MASK
89
        |RADIO_BUTTON_MASK|TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK},
90
    {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
91
        (char *) NULL, 0, ALL_MASK},
92
    {TK_CONFIG_FONT, "-font", "font", "Font",
93
        DEF_BUTTON_FONT, Tk_Offset(TkButton, tkfont),
94
        ALL_MASK},
95
    {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
96
        DEF_BUTTON_FG, Tk_Offset(TkButton, normalFg), LABEL_MASK|BUTTON_MASK},
97
    {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
98
        DEF_CHKRAD_FG, Tk_Offset(TkButton, normalFg), CHECK_BUTTON_MASK
99
        |RADIO_BUTTON_MASK},
100
    {TK_CONFIG_STRING, "-height", "height", "Height",
101
        DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightString), ALL_MASK},
102
    {TK_CONFIG_BORDER, "-highlightbackground", "highlightBackground",
103
        "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG,
104
        Tk_Offset(TkButton, highlightBorder), ALL_MASK},
105
    {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
106
        DEF_BUTTON_HIGHLIGHT, Tk_Offset(TkButton, highlightColorPtr),
107
        ALL_MASK},
108
    {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
109
        "HighlightThickness",
110
        DEF_LABEL_HIGHLIGHT_WIDTH, Tk_Offset(TkButton, highlightWidth),
111
        LABEL_MASK},
112
    {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
113
        "HighlightThickness",
114
        DEF_BUTTON_HIGHLIGHT_WIDTH, Tk_Offset(TkButton, highlightWidth),
115
        BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK},
116
    {TK_CONFIG_STRING, "-image", "image", "Image",
117
        DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imageString),
118
        ALL_MASK|TK_CONFIG_NULL_OK},
119
    {TK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn",
120
        DEF_BUTTON_INDICATOR, Tk_Offset(TkButton, indicatorOn),
121
        CHECK_BUTTON_MASK|RADIO_BUTTON_MASK},
122
    {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
123
        DEF_BUTTON_JUSTIFY, Tk_Offset(TkButton, justify), ALL_MASK},
124
    {TK_CONFIG_STRING, "-offvalue", "offValue", "Value",
125
        DEF_BUTTON_OFF_VALUE, Tk_Offset(TkButton, offValue),
126
        CHECK_BUTTON_MASK},
127
    {TK_CONFIG_STRING, "-onvalue", "onValue", "Value",
128
        DEF_BUTTON_ON_VALUE, Tk_Offset(TkButton, onValue),
129
        CHECK_BUTTON_MASK},
130
    {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
131
        DEF_BUTTON_PADX, Tk_Offset(TkButton, padX), BUTTON_MASK},
132
    {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
133
        DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padX),
134
        LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK},
135
    {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
136
        DEF_BUTTON_PADY, Tk_Offset(TkButton, padY), BUTTON_MASK},
137
    {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
138
        DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padY),
139
        LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK},
140
    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
141
        DEF_BUTTON_RELIEF, Tk_Offset(TkButton, relief), BUTTON_MASK},
142
    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
143
        DEF_LABCHKRAD_RELIEF, Tk_Offset(TkButton, relief),
144
        LABEL_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK},
145
    {TK_CONFIG_BORDER, "-selectcolor", "selectColor", "Background",
146
        DEF_BUTTON_SELECT_COLOR, Tk_Offset(TkButton, selectBorder),
147
        CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_COLOR_ONLY
148
        |TK_CONFIG_NULL_OK},
149
    {TK_CONFIG_BORDER, "-selectcolor", "selectColor", "Background",
150
        DEF_BUTTON_SELECT_MONO, Tk_Offset(TkButton, selectBorder),
151
        CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_MONO_ONLY
152
        |TK_CONFIG_NULL_OK},
153
    {TK_CONFIG_STRING, "-selectimage", "selectImage", "SelectImage",
154
        DEF_BUTTON_SELECT_IMAGE, Tk_Offset(TkButton, selectImageString),
155
        CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK},
156
    {TK_CONFIG_UID, "-state", "state", "State",
157
        DEF_BUTTON_STATE, Tk_Offset(TkButton, state),
158
        BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK},
159
    {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
160
        DEF_LABEL_TAKE_FOCUS, Tk_Offset(TkButton, takeFocus),
161
        LABEL_MASK|TK_CONFIG_NULL_OK},
162
    {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
163
        DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocus),
164
        BUTTON_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK},
165
    {TK_CONFIG_STRING, "-text", "text", "Text",
166
        DEF_BUTTON_TEXT, Tk_Offset(TkButton, text), ALL_MASK},
167
    {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
168
        DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarName),
169
        ALL_MASK|TK_CONFIG_NULL_OK},
170
    {TK_CONFIG_INT, "-underline", "underline", "Underline",
171
        DEF_BUTTON_UNDERLINE, Tk_Offset(TkButton, underline), ALL_MASK},
172
    {TK_CONFIG_STRING, "-value", "value", "Value",
173
        DEF_BUTTON_VALUE, Tk_Offset(TkButton, onValue),
174
        RADIO_BUTTON_MASK},
175
    {TK_CONFIG_STRING, "-variable", "variable", "Variable",
176
        DEF_RADIOBUTTON_VARIABLE, Tk_Offset(TkButton, selVarName),
177
        RADIO_BUTTON_MASK},
178
    {TK_CONFIG_STRING, "-variable", "variable", "Variable",
179
        DEF_CHECKBUTTON_VARIABLE, Tk_Offset(TkButton, selVarName),
180
        CHECK_BUTTON_MASK|TK_CONFIG_NULL_OK},
181
    {TK_CONFIG_STRING, "-width", "width", "Width",
182
        DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthString), ALL_MASK},
183
    {TK_CONFIG_PIXELS, "-wraplength", "wrapLength", "WrapLength",
184
        DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLength), ALL_MASK},
185
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
186
        (char *) NULL, 0, 0}
187
};
188
 
189
/*
190
 * String to print out in error messages, identifying options for
191
 * widget commands for different types of labels or buttons:
192
 */
193
 
194
static char *optionStrings[] = {
195
    "cget or configure",
196
    "cget, configure, flash, or invoke",
197
    "cget, configure, deselect, flash, invoke, select, or toggle",
198
    "cget, configure, deselect, flash, invoke, or select"
199
};
200
 
201
/*
202
 * Forward declarations for procedures defined later in this file:
203
 */
204
 
205
static void             ButtonCmdDeletedProc _ANSI_ARGS_((
206
                            ClientData clientData));
207
static int              ButtonCreate _ANSI_ARGS_((ClientData clientData,
208
                            Tcl_Interp *interp, int argc, char **argv,
209
                            int type));
210
static void             ButtonEventProc _ANSI_ARGS_((ClientData clientData,
211
                            XEvent *eventPtr));
212
static void             ButtonImageProc _ANSI_ARGS_((ClientData clientData,
213
                            int x, int y, int width, int height,
214
                            int imgWidth, int imgHeight));
215
static void             ButtonSelectImageProc _ANSI_ARGS_((
216
                            ClientData clientData, int x, int y, int width,
217
                            int height, int imgWidth, int imgHeight));
218
static char *           ButtonTextVarProc _ANSI_ARGS_((ClientData clientData,
219
                            Tcl_Interp *interp, char *name1, char *name2,
220
                            int flags));
221
static char *           ButtonVarProc _ANSI_ARGS_((ClientData clientData,
222
                            Tcl_Interp *interp, char *name1, char *name2,
223
                            int flags));
224
static int              ButtonWidgetCmd _ANSI_ARGS_((ClientData clientData,
225
                            Tcl_Interp *interp, int argc, char **argv));
226
static int              ConfigureButton _ANSI_ARGS_((Tcl_Interp *interp,
227
                            TkButton *butPtr, int argc, char **argv,
228
                            int flags));
229
static void             DestroyButton _ANSI_ARGS_((TkButton *butPtr));
230
 
231
 
232
/*
233
 *--------------------------------------------------------------
234
 *
235
 * Tk_ButtonCmd, Tk_CheckbuttonCmd, Tk_LabelCmd, Tk_RadiobuttonCmd --
236
 *
237
 *      These procedures are invoked to process the "button", "label",
238
 *      "radiobutton", and "checkbutton" Tcl commands.  See the
239
 *      user documentation for details on what they do.
240
 *
241
 * Results:
242
 *      A standard Tcl result.
243
 *
244
 * Side effects:
245
 *      See the user documentation.  These procedures are just wrappers;
246
 *      they call ButtonCreate to do all of the real work.
247
 *
248
 *--------------------------------------------------------------
249
 */
250
 
251
int
252
Tk_ButtonCmd(clientData, interp, argc, argv)
253
    ClientData clientData;      /* Main window associated with
254
                                 * interpreter. */
255
    Tcl_Interp *interp;         /* Current interpreter. */
256
    int argc;                   /* Number of arguments. */
257
    char **argv;                /* Argument strings. */
258
{
259
    return ButtonCreate(clientData, interp, argc, argv, TYPE_BUTTON);
260
}
261
 
262
int
263
Tk_CheckbuttonCmd(clientData, interp, argc, argv)
264
    ClientData clientData;      /* Main window associated with
265
                                 * interpreter. */
266
    Tcl_Interp *interp;         /* Current interpreter. */
267
    int argc;                   /* Number of arguments. */
268
    char **argv;                /* Argument strings. */
269
{
270
    return ButtonCreate(clientData, interp, argc, argv, TYPE_CHECK_BUTTON);
271
}
272
 
273
int
274
Tk_LabelCmd(clientData, interp, argc, argv)
275
    ClientData clientData;      /* Main window associated with
276
                                 * interpreter. */
277
    Tcl_Interp *interp;         /* Current interpreter. */
278
    int argc;                   /* Number of arguments. */
279
    char **argv;                /* Argument strings. */
280
{
281
    return ButtonCreate(clientData, interp, argc, argv, TYPE_LABEL);
282
}
283
 
284
int
285
Tk_RadiobuttonCmd(clientData, interp, argc, argv)
286
    ClientData clientData;      /* Main window associated with
287
                                 * interpreter. */
288
    Tcl_Interp *interp;         /* Current interpreter. */
289
    int argc;                   /* Number of arguments. */
290
    char **argv;                /* Argument strings. */
291
{
292
    return ButtonCreate(clientData, interp, argc, argv, TYPE_RADIO_BUTTON);
293
}
294
 
295
/*
296
 *--------------------------------------------------------------
297
 *
298
 * ButtonCreate --
299
 *
300
 *      This procedure does all the real work of implementing the
301
 *      "button", "label", "radiobutton", and "checkbutton" Tcl
302
 *      commands.  See the user documentation for details on what it does.
303
 *
304
 * Results:
305
 *      A standard Tcl result.
306
 *
307
 * Side effects:
308
 *      See the user documentation.
309
 *
310
 *--------------------------------------------------------------
311
 */
312
 
313
static int
314
ButtonCreate(clientData, interp, argc, argv, type)
315
    ClientData clientData;      /* Main window associated with
316
                                 * interpreter. */
317
    Tcl_Interp *interp;         /* Current interpreter. */
318
    int argc;                   /* Number of arguments. */
319
    char **argv;                /* Argument strings. */
320
    int type;                   /* Type of button to create: TYPE_LABEL,
321
                                 * TYPE_BUTTON, TYPE_CHECK_BUTTON, or
322
                                 * TYPE_RADIO_BUTTON. */
323
{
324
    register TkButton *butPtr;
325
    Tk_Window tkwin = (Tk_Window) clientData;
326
    Tk_Window new;
327
 
328
    if (argc < 2) {
329
        Tcl_AppendResult(interp, "wrong # args: should be \"",
330
                argv[0], " pathName ?options?\"", (char *) NULL);
331
        return TCL_ERROR;
332
    }
333
 
334
    /*
335
     * Create the new window.
336
     */
337
 
338
    new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
339
    if (new == NULL) {
340
        return TCL_ERROR;
341
    }
342
 
343
    Tk_SetClass(new, classNames[type]);
344
    butPtr = TkpCreateButton(new);
345
 
346
    TkSetClassProcs(new, &tkpButtonProcs, (ClientData) butPtr);
347
 
348
    /*
349
     * Initialize the data structure for the button.
350
     */
351
 
352
    butPtr->tkwin = new;
353
    butPtr->display = Tk_Display(new);
354
    butPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(butPtr->tkwin),
355
            ButtonWidgetCmd, (ClientData) butPtr, ButtonCmdDeletedProc);
356
    butPtr->interp = interp;
357
    butPtr->type = type;
358
    butPtr->text = NULL;
359
    butPtr->underline = -1;
360
    butPtr->textVarName = NULL;
361
    butPtr->bitmap = None;
362
    butPtr->imageString = NULL;
363
    butPtr->image = NULL;
364
    butPtr->selectImageString = NULL;
365
    butPtr->selectImage = NULL;
366
    butPtr->state = tkNormalUid;
367
    butPtr->normalBorder = NULL;
368
    butPtr->activeBorder = NULL;
369
    butPtr->borderWidth = 0;
370
    butPtr->relief = TK_RELIEF_FLAT;
371
    butPtr->highlightWidth = 0;
372
    butPtr->highlightBorder = NULL;
373
    butPtr->highlightColorPtr = NULL;
374
    butPtr->inset = 0;
375
    butPtr->tkfont = NULL;
376
    butPtr->normalFg = NULL;
377
    butPtr->activeFg = NULL;
378
    butPtr->disabledFg = NULL;
379
    butPtr->normalTextGC = None;
380
    butPtr->activeTextGC = None;
381
    butPtr->gray = None;
382
    butPtr->disabledGC = None;
383
    butPtr->copyGC = None;
384
    butPtr->widthString = NULL;
385
    butPtr->heightString = NULL;
386
    butPtr->width = 0;
387
    butPtr->height = 0;
388
    butPtr->wrapLength = 0;
389
    butPtr->padX = 0;
390
    butPtr->padY = 0;
391
    butPtr->anchor = TK_ANCHOR_CENTER;
392
    butPtr->justify = TK_JUSTIFY_CENTER;
393
    butPtr->textLayout = NULL;
394
    butPtr->indicatorOn = 0;
395
    butPtr->selectBorder = NULL;
396
    butPtr->indicatorSpace = 0;
397
    butPtr->indicatorDiameter = 0;
398
    butPtr->defaultState = tkDisabledUid;
399
    butPtr->selVarName = NULL;
400
    butPtr->onValue = NULL;
401
    butPtr->offValue = NULL;
402
    butPtr->cursor = None;
403
    butPtr->command = NULL;
404
    butPtr->takeFocus = NULL;
405
    butPtr->flags = 0;
406
 
407
    Tk_CreateEventHandler(butPtr->tkwin,
408
            ExposureMask|StructureNotifyMask|FocusChangeMask,
409
            ButtonEventProc, (ClientData) butPtr);
410
 
411
    if (ConfigureButton(interp, butPtr, argc - 2, argv + 2,
412
            configFlags[type]) != TCL_OK) {
413
        Tk_DestroyWindow(butPtr->tkwin);
414
        return TCL_ERROR;
415
    }
416
 
417
    interp->result = Tk_PathName(butPtr->tkwin);
418
    return TCL_OK;
419
}
420
 
421
/*
422
 *--------------------------------------------------------------
423
 *
424
 * ButtonWidgetCmd --
425
 *
426
 *      This procedure is invoked to process the Tcl command
427
 *      that corresponds to a widget managed by this module.
428
 *      See the user documentation for details on what it does.
429
 *
430
 * Results:
431
 *      A standard Tcl result.
432
 *
433
 * Side effects:
434
 *      See the user documentation.
435
 *
436
 *--------------------------------------------------------------
437
 */
438
 
439
static int
440
ButtonWidgetCmd(clientData, interp, argc, argv)
441
    ClientData clientData;      /* Information about button widget. */
442
    Tcl_Interp *interp;         /* Current interpreter. */
443
    int argc;                   /* Number of arguments. */
444
    char **argv;                /* Argument strings. */
445
{
446
    register TkButton *butPtr = (TkButton *) clientData;
447
    int result = TCL_OK;
448
    size_t length;
449
    int c;
450
 
451
    if (argc < 2) {
452
        sprintf(interp->result,
453
                "wrong # args: should be \"%.50s option ?arg arg ...?\"",
454
                argv[0]);
455
        return TCL_ERROR;
456
    }
457
    Tcl_Preserve((ClientData) butPtr);
458
    c = argv[1][0];
459
    length = strlen(argv[1]);
460
 
461
    if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
462
            && (length >= 2)) {
463
        if (argc != 3) {
464
            Tcl_AppendResult(interp, "wrong # args: should be \"",
465
                    argv[0], " cget option\"",
466
                    (char *) NULL);
467
            goto error;
468
        }
469
        result = Tk_ConfigureValue(interp, butPtr->tkwin, tkpButtonConfigSpecs,
470
                (char *) butPtr, argv[2], configFlags[butPtr->type]);
471
    } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
472
            && (length >= 2)) {
473
        if (argc == 2) {
474
            result = Tk_ConfigureInfo(interp, butPtr->tkwin,
475
                    tkpButtonConfigSpecs, (char *) butPtr, (char *) NULL,
476
                    configFlags[butPtr->type]);
477
        } else if (argc == 3) {
478
            result = Tk_ConfigureInfo(interp, butPtr->tkwin,
479
                    tkpButtonConfigSpecs, (char *) butPtr, argv[2],
480
                    configFlags[butPtr->type]);
481
        } else {
482
            result = ConfigureButton(interp, butPtr, argc-2, argv+2,
483
                    configFlags[butPtr->type] | TK_CONFIG_ARGV_ONLY);
484
        }
485
    } else if ((c == 'd') && (strncmp(argv[1], "deselect", length) == 0)
486
            && (butPtr->type >= TYPE_CHECK_BUTTON)) {
487
        if (argc > 2) {
488
            sprintf(interp->result,
489
                    "wrong # args: should be \"%.50s deselect\"",
490
                    argv[0]);
491
            goto error;
492
        }
493
        if (butPtr->type == TYPE_CHECK_BUTTON) {
494
            if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue,
495
                    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
496
                result = TCL_ERROR;
497
            }
498
        } else if (butPtr->flags & SELECTED) {
499
            if (Tcl_SetVar(interp, butPtr->selVarName, "",
500
                    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
501
                result = TCL_ERROR;
502
            };
503
        }
504
    } else if ((c == 'f') && (strncmp(argv[1], "flash", length) == 0)
505
            && (butPtr->type != TYPE_LABEL)) {
506
        int i;
507
 
508
        if (argc > 2) {
509
            sprintf(interp->result,
510
                    "wrong # args: should be \"%.50s flash\"",
511
                    argv[0]);
512
            goto error;
513
        }
514
        if (butPtr->state != tkDisabledUid) {
515
            for (i = 0; i < 4; i++) {
516
                butPtr->state = (butPtr->state == tkNormalUid)
517
                        ? tkActiveUid : tkNormalUid;
518
                Tk_SetBackgroundFromBorder(butPtr->tkwin,
519
                        (butPtr->state == tkActiveUid) ? butPtr->activeBorder
520
                        : butPtr->normalBorder);
521
                TkpDisplayButton((ClientData) butPtr);
522
 
523
                /*
524
                 * Special note: must cancel any existing idle handler
525
                 * for TkpDisplayButton;  it's no longer needed, and TkpDisplayButton
526
                 * cleared the REDRAW_PENDING flag.
527
                 */
528
 
529
                Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr);
530
                XFlush(butPtr->display);
531
                Tcl_Sleep(50);
532
            }
533
        }
534
    } else if ((c == 'i') && (strncmp(argv[1], "invoke", length) == 0)
535
            && (butPtr->type > TYPE_LABEL)) {
536
        if (argc > 2) {
537
            sprintf(interp->result,
538
                    "wrong # args: should be \"%.50s invoke\"",
539
                    argv[0]);
540
            goto error;
541
        }
542
        if (butPtr->state != tkDisabledUid) {
543
            result = TkInvokeButton(butPtr);
544
        }
545
    } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0)
546
            && (butPtr->type >= TYPE_CHECK_BUTTON)) {
547
        if (argc > 2) {
548
            sprintf(interp->result,
549
                    "wrong # args: should be \"%.50s select\"",
550
                    argv[0]);
551
            goto error;
552
        }
553
        if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue,
554
                TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
555
            result = TCL_ERROR;
556
        }
557
    } else if ((c == 't') && (strncmp(argv[1], "toggle", length) == 0)
558
            && (length >= 2) && (butPtr->type == TYPE_CHECK_BUTTON)) {
559
        if (argc > 2) {
560
            sprintf(interp->result,
561
                    "wrong # args: should be \"%.50s toggle\"",
562
                    argv[0]);
563
            goto error;
564
        }
565
        if (butPtr->flags & SELECTED) {
566
            if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->offValue,
567
                    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
568
                result = TCL_ERROR;
569
            }
570
        } else {
571
            if (Tcl_SetVar(interp, butPtr->selVarName, butPtr->onValue,
572
                    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
573
                result = TCL_ERROR;
574
            }
575
        }
576
    } else {
577
        sprintf(interp->result,
578
                "bad option \"%.50s\": must be %s", argv[1],
579
                optionStrings[butPtr->type]);
580
        goto error;
581
    }
582
    Tcl_Release((ClientData) butPtr);
583
    return result;
584
 
585
    error:
586
    Tcl_Release((ClientData) butPtr);
587
    return TCL_ERROR;
588
}
589
 
590
/*
591
 *----------------------------------------------------------------------
592
 *
593
 * DestroyButton --
594
 *
595
 *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
596
 *      to clean up the internal structure of a button at a safe time
597
 *      (when no-one is using it anymore).
598
 *
599
 * Results:
600
 *      None.
601
 *
602
 * Side effects:
603
 *      Everything associated with the widget is freed up.
604
 *
605
 *----------------------------------------------------------------------
606
 */
607
 
608
static void
609
DestroyButton(butPtr)
610
    TkButton *butPtr;           /* Info about button widget. */
611
{
612
    /*
613
     * Free up all the stuff that requires special handling, then
614
     * let Tk_FreeOptions handle all the standard option-related
615
     * stuff.
616
     */
617
 
618
    if (butPtr->textVarName != NULL) {
619
        Tcl_UntraceVar(butPtr->interp, butPtr->textVarName,
620
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
621
                ButtonTextVarProc, (ClientData) butPtr);
622
    }
623
    if (butPtr->image != NULL) {
624
        Tk_FreeImage(butPtr->image);
625
    }
626
    if (butPtr->selectImage != NULL) {
627
        Tk_FreeImage(butPtr->selectImage);
628
    }
629
    if (butPtr->normalTextGC != None) {
630
        Tk_FreeGC(butPtr->display, butPtr->normalTextGC);
631
    }
632
    if (butPtr->activeTextGC != None) {
633
        Tk_FreeGC(butPtr->display, butPtr->activeTextGC);
634
    }
635
    if (butPtr->gray != None) {
636
        Tk_FreeBitmap(butPtr->display, butPtr->gray);
637
    }
638
    if (butPtr->disabledGC != None) {
639
        Tk_FreeGC(butPtr->display, butPtr->disabledGC);
640
    }
641
    if (butPtr->copyGC != None) {
642
        Tk_FreeGC(butPtr->display, butPtr->copyGC);
643
    }
644
    if (butPtr->selVarName != NULL) {
645
        Tcl_UntraceVar(butPtr->interp, butPtr->selVarName,
646
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
647
                ButtonVarProc, (ClientData) butPtr);
648
    }
649
    Tk_FreeTextLayout(butPtr->textLayout);
650
    Tk_FreeOptions(tkpButtonConfigSpecs, (char *) butPtr, butPtr->display,
651
            configFlags[butPtr->type]);
652
    Tcl_EventuallyFree((ClientData)butPtr, TCL_DYNAMIC);
653
}
654
 
655
/*
656
 *----------------------------------------------------------------------
657
 *
658
 * ConfigureButton --
659
 *
660
 *      This procedure is called to process an argv/argc list, plus
661
 *      the Tk option database, in order to configure (or
662
 *      reconfigure) a button widget.
663
 *
664
 * Results:
665
 *      The return value is a standard Tcl result.  If TCL_ERROR is
666
 *      returned, then interp->result contains an error message.
667
 *
668
 * Side effects:
669
 *      Configuration information, such as text string, colors, font,
670
 *      etc. get set for butPtr;  old resources get freed, if there
671
 *      were any.  The button is redisplayed.
672
 *
673
 *----------------------------------------------------------------------
674
 */
675
 
676
static int
677
ConfigureButton(interp, butPtr, argc, argv, flags)
678
    Tcl_Interp *interp;         /* Used for error reporting. */
679
    register TkButton *butPtr;  /* Information about widget;  may or may
680
                                 * not already have values for some fields. */
681
    int argc;                   /* Number of valid entries in argv. */
682
    char **argv;                /* Arguments. */
683
    int flags;                  /* Flags to pass to Tk_ConfigureWidget. */
684
{
685
    Tk_Image image;
686
 
687
    /*
688
     * Eliminate any existing trace on variables monitored by the button.
689
     */
690
 
691
    if (butPtr->textVarName != NULL) {
692
        Tcl_UntraceVar(interp, butPtr->textVarName,
693
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
694
                ButtonTextVarProc, (ClientData) butPtr);
695
    }
696
    if (butPtr->selVarName != NULL) {
697
        Tcl_UntraceVar(interp, butPtr->selVarName,
698
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
699
                ButtonVarProc, (ClientData) butPtr);
700
    }
701
 
702
 
703
 
704
    if (Tk_ConfigureWidget(interp, butPtr->tkwin, tkpButtonConfigSpecs,
705
            argc, argv, (char *) butPtr, flags) != TCL_OK) {
706
        return TCL_ERROR;
707
    }
708
 
709
    /*
710
     * A few options need special processing, such as setting the
711
     * background from a 3-D border, or filling in complicated
712
     * defaults that couldn't be specified to Tk_ConfigureWidget.
713
     */
714
 
715
    if ((butPtr->state == tkActiveUid) && !Tk_StrictMotif(butPtr->tkwin)) {
716
        Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->activeBorder);
717
    } else {
718
        Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->normalBorder);
719
        if ((butPtr->state != tkNormalUid) && (butPtr->state != tkActiveUid)
720
                && (butPtr->state != tkDisabledUid)) {
721
            Tcl_AppendResult(interp, "bad state value \"", butPtr->state,
722
                    "\": must be normal, active, or disabled", (char *) NULL);
723
            butPtr->state = tkNormalUid;
724
            return TCL_ERROR;
725
        }
726
    }
727
 
728
    if ((butPtr->defaultState != tkActiveUid)
729
            && (butPtr->defaultState != tkDisabledUid)
730
            && (butPtr->defaultState != tkNormalUid)) {
731
        Tcl_AppendResult(interp, "bad -default value \"", butPtr->defaultState,
732
                "\": must be normal, active, or disabled", (char *) NULL);
733
        butPtr->defaultState = tkDisabledUid;
734
        return TCL_ERROR;
735
    }
736
 
737
    if (butPtr->highlightWidth < 0) {
738
        butPtr->highlightWidth = 0;
739
    }
740
 
741
    if (butPtr->padX < 0) {
742
        butPtr->padX = 0;
743
    }
744
    if (butPtr->padY < 0) {
745
        butPtr->padY = 0;
746
    }
747
 
748
    if (butPtr->type >= TYPE_CHECK_BUTTON) {
749
        char *value;
750
 
751
        if (butPtr->selVarName == NULL) {
752
            butPtr->selVarName = (char *) ckalloc((unsigned)
753
                    (strlen(Tk_Name(butPtr->tkwin)) + 1));
754
            strcpy(butPtr->selVarName, Tk_Name(butPtr->tkwin));
755
        }
756
 
757
        /*
758
         * Select the button if the associated variable has the
759
         * appropriate value, initialize the variable if it doesn't
760
         * exist, then set a trace on the variable to monitor future
761
         * changes to its value.
762
         */
763
 
764
        value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY);
765
        butPtr->flags &= ~SELECTED;
766
        if (value != NULL) {
767
            if (strcmp(value, butPtr->onValue) == 0) {
768
                butPtr->flags |= SELECTED;
769
            }
770
        } else {
771
            if (Tcl_SetVar(interp, butPtr->selVarName,
772
                    (butPtr->type == TYPE_CHECK_BUTTON) ? butPtr->offValue : "",
773
                    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
774
                return TCL_ERROR;
775
            }
776
        }
777
        Tcl_TraceVar(interp, butPtr->selVarName,
778
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
779
                ButtonVarProc, (ClientData) butPtr);
780
    }
781
 
782
    /*
783
     * Get the images for the widget, if there are any.  Allocate the
784
     * new images before freeing the old ones, so that the reference
785
     * counts don't go to zero and cause image data to be discarded.
786
     */
787
 
788
    if (butPtr->imageString != NULL) {
789
        image = Tk_GetImage(butPtr->interp, butPtr->tkwin,
790
                butPtr->imageString, ButtonImageProc, (ClientData) butPtr);
791
        if (image == NULL) {
792
            return TCL_ERROR;
793
        }
794
    } else {
795
        image = NULL;
796
    }
797
    if (butPtr->image != NULL) {
798
        Tk_FreeImage(butPtr->image);
799
    }
800
    butPtr->image = image;
801
    if (butPtr->selectImageString != NULL) {
802
        image = Tk_GetImage(butPtr->interp, butPtr->tkwin,
803
                butPtr->selectImageString, ButtonSelectImageProc,
804
                (ClientData) butPtr);
805
        if (image == NULL) {
806
            return TCL_ERROR;
807
        }
808
    } else {
809
        image = NULL;
810
    }
811
    if (butPtr->selectImage != NULL) {
812
        Tk_FreeImage(butPtr->selectImage);
813
    }
814
    butPtr->selectImage = image;
815
 
816
    if ((butPtr->image == NULL) && (butPtr->bitmap == None)
817
            && (butPtr->textVarName != NULL)) {
818
        /*
819
         * The button must display the value of a variable: set up a trace
820
         * on the variable's value, create the variable if it doesn't
821
         * exist, and fetch its current value.
822
         */
823
 
824
        char *value;
825
 
826
        value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY);
827
        if (value == NULL) {
828
            if (Tcl_SetVar(interp, butPtr->textVarName, butPtr->text,
829
                    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
830
                return TCL_ERROR;
831
            }
832
        } else {
833
            if (butPtr->text != NULL) {
834
                ckfree(butPtr->text);
835
            }
836
            butPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1));
837
            strcpy(butPtr->text, value);
838
        }
839
        Tcl_TraceVar(interp, butPtr->textVarName,
840
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
841
                ButtonTextVarProc, (ClientData) butPtr);
842
    }
843
 
844
    if ((butPtr->bitmap != None) || (butPtr->image != NULL)) {
845
        if (Tk_GetPixels(interp, butPtr->tkwin, butPtr->widthString,
846
                &butPtr->width) != TCL_OK) {
847
            widthError:
848
            Tcl_AddErrorInfo(interp, "\n    (processing -width option)");
849
            return TCL_ERROR;
850
        }
851
        if (Tk_GetPixels(interp, butPtr->tkwin, butPtr->heightString,
852
                &butPtr->height) != TCL_OK) {
853
            heightError:
854
            Tcl_AddErrorInfo(interp, "\n    (processing -height option)");
855
            return TCL_ERROR;
856
        }
857
    } else {
858
        if (Tcl_GetInt(interp, butPtr->widthString, &butPtr->width)
859
                != TCL_OK) {
860
            goto widthError;
861
        }
862
        if (Tcl_GetInt(interp, butPtr->heightString, &butPtr->height)
863
                != TCL_OK) {
864
            goto heightError;
865
        }
866
    }
867
 
868
    TkButtonWorldChanged((ClientData) butPtr);
869
    return TCL_OK;
870
}
871
 
872
/*
873
 *---------------------------------------------------------------------------
874
 *
875
 * TkButtonWorldChanged --
876
 *
877
 *      This procedure is called when the world has changed in some
878
 *      way and the widget needs to recompute all its graphics contexts
879
 *      and determine its new geometry.
880
 *
881
 * Results:
882
 *      None.
883
 *
884
 * Side effects:
885
 *      Button will be relayed out and redisplayed.
886
 *
887
 *---------------------------------------------------------------------------
888
 */
889
 
890
void
891
TkButtonWorldChanged(instanceData)
892
    ClientData instanceData;    /* Information about widget. */
893
{
894
    XGCValues gcValues;
895
    GC newGC;
896
    unsigned long mask;
897
    TkButton *butPtr;
898
 
899
    butPtr = (TkButton *) instanceData;
900
 
901
    /*
902
     * Recompute GCs.
903
     */
904
 
905
    gcValues.font = Tk_FontId(butPtr->tkfont);
906
    gcValues.foreground = butPtr->normalFg->pixel;
907
    gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel;
908
 
909
    /*
910
     * Note: GraphicsExpose events are disabled in normalTextGC because it's
911
     * used to copy stuff from an off-screen pixmap onto the screen (we know
912
     * that there's no problem with obscured areas).
913
     */
914
 
915
    gcValues.graphics_exposures = False;
916
    mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
917
    newGC = Tk_GetGCColor(butPtr->tkwin, mask, &gcValues,
918
                          butPtr->normalFg,
919
                          Tk_3DBorderColor(butPtr->normalBorder));
920
    if (butPtr->normalTextGC != None) {
921
        Tk_FreeGC(butPtr->display, butPtr->normalTextGC);
922
    }
923
    butPtr->normalTextGC = newGC;
924
 
925
    if (butPtr->activeFg != NULL) {
926
        gcValues.font = Tk_FontId(butPtr->tkfont);
927
        gcValues.foreground = butPtr->activeFg->pixel;
928
        gcValues.background = Tk_3DBorderColor(butPtr->activeBorder)->pixel;
929
        mask = GCForeground | GCBackground | GCFont;
930
        newGC = Tk_GetGCColor(butPtr->tkwin, mask, &gcValues,
931
                              butPtr->activeFg,
932
                              Tk_3DBorderColor(butPtr->activeBorder));
933
        if (butPtr->activeTextGC != None) {
934
            Tk_FreeGC(butPtr->display, butPtr->activeTextGC);
935
        }
936
        butPtr->activeTextGC = newGC;
937
    }
938
 
939
    if (butPtr->type != TYPE_LABEL) {
940
        XColor *foreground, *background;
941
 
942
        gcValues.font = Tk_FontId(butPtr->tkfont);
943
        background = Tk_3DBorderColor(butPtr->normalBorder);
944
        gcValues.background = background->pixel;
945
        if ((butPtr->disabledFg != NULL) && (butPtr->imageString == NULL)) {
946
            foreground = butPtr->disabledFg;
947
            gcValues.foreground = foreground->pixel;
948
            mask = GCForeground | GCBackground | GCFont;
949
        } else {
950
            foreground = background;
951
            background = NULL;
952
            gcValues.foreground = gcValues.background;
953
            mask = GCForeground;
954
            if (butPtr->gray == None) {
955
                butPtr->gray = Tk_GetBitmap(NULL, butPtr->tkwin,
956
                        Tk_GetUid("gray50"));
957
            }
958
            if (butPtr->gray != None) {
959
                gcValues.fill_style = FillStippled;
960
                gcValues.stipple = butPtr->gray;
961
                mask |= GCFillStyle | GCStipple;
962
            }
963
        }
964
        newGC = Tk_GetGCColor(butPtr->tkwin, mask, &gcValues, foreground,
965
                              background);
966
        if (butPtr->disabledGC != None) {
967
            Tk_FreeGC(butPtr->display, butPtr->disabledGC);
968
        }
969
        butPtr->disabledGC = newGC;
970
    }
971
 
972
    if (butPtr->copyGC == None) {
973
        butPtr->copyGC = Tk_GetGC(butPtr->tkwin, 0, &gcValues);
974
    }
975
 
976
    TkpComputeButtonGeometry(butPtr);
977
 
978
    /*
979
     * Lastly, arrange for the button to be redisplayed.
980
     */
981
 
982
    if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) {
983
        Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
984
        butPtr->flags |= REDRAW_PENDING;
985
    }
986
}
987
 
988
/*
989
 *--------------------------------------------------------------
990
 *
991
 * ButtonEventProc --
992
 *
993
 *      This procedure is invoked by the Tk dispatcher for various
994
 *      events on buttons.
995
 *
996
 * Results:
997
 *      None.
998
 *
999
 * Side effects:
1000
 *      When the window gets deleted, internal structures get
1001
 *      cleaned up.  When it gets exposed, it is redisplayed.
1002
 *
1003
 *--------------------------------------------------------------
1004
 */
1005
 
1006
static void
1007
ButtonEventProc(clientData, eventPtr)
1008
    ClientData clientData;      /* Information about window. */
1009
    XEvent *eventPtr;           /* Information about event. */
1010
{
1011
    TkButton *butPtr = (TkButton *) clientData;
1012
    if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
1013
        goto redraw;
1014
    } else if (eventPtr->type == ConfigureNotify) {
1015
        /*
1016
         * Must redraw after size changes, since layout could have changed
1017
         * and borders will need to be redrawn.
1018
         */
1019
 
1020
        goto redraw;
1021
    } else if (eventPtr->type == DestroyNotify) {
1022
        TkpDestroyButton(butPtr);
1023
        if (butPtr->tkwin != NULL) {
1024
            butPtr->tkwin = NULL;
1025
            Tcl_DeleteCommandFromToken(butPtr->interp, butPtr->widgetCmd);
1026
        }
1027
        if (butPtr->flags & REDRAW_PENDING) {
1028
            Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr);
1029
        }
1030
        DestroyButton(butPtr);
1031
    } else if (eventPtr->type == FocusIn) {
1032
        if (eventPtr->xfocus.detail != NotifyInferior) {
1033
            butPtr->flags |= GOT_FOCUS;
1034
            if (butPtr->highlightWidth > 0) {
1035
                goto redraw;
1036
            }
1037
        }
1038
    } else if (eventPtr->type == FocusOut) {
1039
        if (eventPtr->xfocus.detail != NotifyInferior) {
1040
            butPtr->flags &= ~GOT_FOCUS;
1041
            if (butPtr->highlightWidth > 0) {
1042
                goto redraw;
1043
            }
1044
        }
1045
    }
1046
    return;
1047
 
1048
    redraw:
1049
    if ((butPtr->tkwin != NULL) && !(butPtr->flags & REDRAW_PENDING)) {
1050
        Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1051
        butPtr->flags |= REDRAW_PENDING;
1052
    }
1053
}
1054
 
1055
/*
1056
 *----------------------------------------------------------------------
1057
 *
1058
 * ButtonCmdDeletedProc --
1059
 *
1060
 *      This procedure is invoked when a widget command is deleted.  If
1061
 *      the widget isn't already in the process of being destroyed,
1062
 *      this command destroys it.
1063
 *
1064
 * Results:
1065
 *      None.
1066
 *
1067
 * Side effects:
1068
 *      The widget is destroyed.
1069
 *
1070
 *----------------------------------------------------------------------
1071
 */
1072
 
1073
static void
1074
ButtonCmdDeletedProc(clientData)
1075
    ClientData clientData;      /* Pointer to widget record for widget. */
1076
{
1077
    TkButton *butPtr = (TkButton *) clientData;
1078
    Tk_Window tkwin = butPtr->tkwin;
1079
 
1080
    /*
1081
     * This procedure could be invoked either because the window was
1082
     * destroyed and the command was then deleted (in which case tkwin
1083
     * is NULL) or because the command was deleted, and then this procedure
1084
     * destroys the widget.
1085
     */
1086
 
1087
    if (tkwin != NULL) {
1088
        butPtr->tkwin = NULL;
1089
        Tk_DestroyWindow(tkwin);
1090
    }
1091
}
1092
 
1093
/*
1094
 *----------------------------------------------------------------------
1095
 *
1096
 * TkInvokeButton --
1097
 *
1098
 *      This procedure is called to carry out the actions associated
1099
 *      with a button, such as invoking a Tcl command or setting a
1100
 *      variable.  This procedure is invoked, for example, when the
1101
 *      button is invoked via the mouse.
1102
 *
1103
 * Results:
1104
 *      A standard Tcl return value.  Information is also left in
1105
 *      interp->result.
1106
 *
1107
 * Side effects:
1108
 *      Depends on the button and its associated command.
1109
 *
1110
 *----------------------------------------------------------------------
1111
 */
1112
 
1113
int
1114
TkInvokeButton(butPtr)
1115
    register TkButton *butPtr;          /* Information about button. */
1116
{
1117
    if (butPtr->type == TYPE_CHECK_BUTTON) {
1118
        if (butPtr->flags & SELECTED) {
1119
            if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->offValue,
1120
                    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
1121
                return TCL_ERROR;
1122
            }
1123
        } else {
1124
            if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue,
1125
                    TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
1126
                return TCL_ERROR;
1127
            }
1128
        }
1129
    } else if (butPtr->type == TYPE_RADIO_BUTTON) {
1130
        if (Tcl_SetVar(butPtr->interp, butPtr->selVarName, butPtr->onValue,
1131
                TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
1132
            return TCL_ERROR;
1133
        }
1134
    }
1135
    if ((butPtr->type != TYPE_LABEL) && (butPtr->command != NULL)) {
1136
        return TkCopyAndGlobalEval(butPtr->interp, butPtr->command);
1137
    }
1138
    return TCL_OK;
1139
}
1140
 
1141
/*
1142
 *--------------------------------------------------------------
1143
 *
1144
 * ButtonVarProc --
1145
 *
1146
 *      This procedure is invoked when someone changes the
1147
 *      state variable associated with a radio button.  Depending
1148
 *      on the new value of the button's variable, the button
1149
 *      may be selected or deselected.
1150
 *
1151
 * Results:
1152
 *      NULL is always returned.
1153
 *
1154
 * Side effects:
1155
 *      The button may become selected or deselected.
1156
 *
1157
 *--------------------------------------------------------------
1158
 */
1159
 
1160
        /* ARGSUSED */
1161
static char *
1162
ButtonVarProc(clientData, interp, name1, name2, flags)
1163
    ClientData clientData;      /* Information about button. */
1164
    Tcl_Interp *interp;         /* Interpreter containing variable. */
1165
    char *name1;                /* Name of variable. */
1166
    char *name2;                /* Second part of variable name. */
1167
    int flags;                  /* Information about what happened. */
1168
{
1169
    register TkButton *butPtr = (TkButton *) clientData;
1170
    char *value;
1171
 
1172
    /*
1173
     * If the variable is being unset, then just re-establish the
1174
     * trace unless the whole interpreter is going away.
1175
     */
1176
 
1177
    if (flags & TCL_TRACE_UNSETS) {
1178
        butPtr->flags &= ~SELECTED;
1179
        if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
1180
            Tcl_TraceVar(interp, butPtr->selVarName,
1181
                    TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1182
                    ButtonVarProc, clientData);
1183
        }
1184
        goto redisplay;
1185
    }
1186
 
1187
    /*
1188
     * Use the value of the variable to update the selected status of
1189
     * the button.
1190
     */
1191
 
1192
    value = Tcl_GetVar(interp, butPtr->selVarName, TCL_GLOBAL_ONLY);
1193
    if (value == NULL) {
1194
        value = "";
1195
    }
1196
    if (strcmp(value, butPtr->onValue) == 0) {
1197
        if (butPtr->flags & SELECTED) {
1198
            return (char *) NULL;
1199
        }
1200
        butPtr->flags |= SELECTED;
1201
    } else if (butPtr->flags & SELECTED) {
1202
        butPtr->flags &= ~SELECTED;
1203
    } else {
1204
        return (char *) NULL;
1205
    }
1206
 
1207
    redisplay:
1208
    if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin)
1209
            && !(butPtr->flags & REDRAW_PENDING)) {
1210
        Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1211
        butPtr->flags |= REDRAW_PENDING;
1212
    }
1213
    return (char *) NULL;
1214
}
1215
 
1216
/*
1217
 *--------------------------------------------------------------
1218
 *
1219
 * ButtonTextVarProc --
1220
 *
1221
 *      This procedure is invoked when someone changes the variable
1222
 *      whose contents are to be displayed in a button.
1223
 *
1224
 * Results:
1225
 *      NULL is always returned.
1226
 *
1227
 * Side effects:
1228
 *      The text displayed in the button will change to match the
1229
 *      variable.
1230
 *
1231
 *--------------------------------------------------------------
1232
 */
1233
 
1234
        /* ARGSUSED */
1235
static char *
1236
ButtonTextVarProc(clientData, interp, name1, name2, flags)
1237
    ClientData clientData;      /* Information about button. */
1238
    Tcl_Interp *interp;         /* Interpreter containing variable. */
1239
    char *name1;                /* Not used. */
1240
    char *name2;                /* Not used. */
1241
    int flags;                  /* Information about what happened. */
1242
{
1243
    register TkButton *butPtr = (TkButton *) clientData;
1244
    char *value;
1245
 
1246
    /*
1247
     * If the variable is unset, then immediately recreate it unless
1248
     * the whole interpreter is going away.
1249
     */
1250
 
1251
    if (flags & TCL_TRACE_UNSETS) {
1252
        if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
1253
            Tcl_SetVar(interp, butPtr->textVarName, butPtr->text,
1254
                    TCL_GLOBAL_ONLY);
1255
            Tcl_TraceVar(interp, butPtr->textVarName,
1256
                    TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1257
                    ButtonTextVarProc, clientData);
1258
        }
1259
        return (char *) NULL;
1260
    }
1261
 
1262
    value = Tcl_GetVar(interp, butPtr->textVarName, TCL_GLOBAL_ONLY);
1263
    if (value == NULL) {
1264
        value = "";
1265
    }
1266
    if (butPtr->text != NULL) {
1267
        ckfree(butPtr->text);
1268
    }
1269
    butPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1));
1270
    strcpy(butPtr->text, value);
1271
    TkpComputeButtonGeometry(butPtr);
1272
 
1273
    if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin)
1274
            && !(butPtr->flags & REDRAW_PENDING)) {
1275
        Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1276
        butPtr->flags |= REDRAW_PENDING;
1277
    }
1278
    return (char *) NULL;
1279
}
1280
 
1281
/*
1282
 *----------------------------------------------------------------------
1283
 *
1284
 * ButtonImageProc --
1285
 *
1286
 *      This procedure is invoked by the image code whenever the manager
1287
 *      for an image does something that affects the size of contents
1288
 *      of an image displayed in a button.
1289
 *
1290
 * Results:
1291
 *      None.
1292
 *
1293
 * Side effects:
1294
 *      Arranges for the button to get redisplayed.
1295
 *
1296
 *----------------------------------------------------------------------
1297
 */
1298
 
1299
static void
1300
ButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
1301
    ClientData clientData;              /* Pointer to widget record. */
1302
    int x, y;                           /* Upper left pixel (within image)
1303
                                         * that must be redisplayed. */
1304
    int width, height;                  /* Dimensions of area to redisplay
1305
                                         * (may be <= 0). */
1306
    int imgWidth, imgHeight;            /* New dimensions of image. */
1307
{
1308
    register TkButton *butPtr = (TkButton *) clientData;
1309
 
1310
    if (butPtr->tkwin != NULL) {
1311
        TkpComputeButtonGeometry(butPtr);
1312
        if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) {
1313
            Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1314
            butPtr->flags |= REDRAW_PENDING;
1315
        }
1316
    }
1317
}
1318
 
1319
/*
1320
 *----------------------------------------------------------------------
1321
 *
1322
 * ButtonSelectImageProc --
1323
 *
1324
 *      This procedure is invoked by the image code whenever the manager
1325
 *      for an image does something that affects the size of contents
1326
 *      of the image displayed in a button when it is selected.
1327
 *
1328
 * Results:
1329
 *      None.
1330
 *
1331
 * Side effects:
1332
 *      May arrange for the button to get redisplayed.
1333
 *
1334
 *----------------------------------------------------------------------
1335
 */
1336
 
1337
static void
1338
ButtonSelectImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
1339
    ClientData clientData;              /* Pointer to widget record. */
1340
    int x, y;                           /* Upper left pixel (within image)
1341
                                         * that must be redisplayed. */
1342
    int width, height;                  /* Dimensions of area to redisplay
1343
                                         * (may be <= 0). */
1344
    int imgWidth, imgHeight;            /* New dimensions of image. */
1345
{
1346
    register TkButton *butPtr = (TkButton *) clientData;
1347
 
1348
    /*
1349
     * Don't recompute geometry:  it's controlled by the primary image.
1350
     */
1351
 
1352
    if ((butPtr->flags & SELECTED) && (butPtr->tkwin != NULL)
1353
            && Tk_IsMapped(butPtr->tkwin)
1354
            && !(butPtr->flags & REDRAW_PENDING)) {
1355
        Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1356
        butPtr->flags |= REDRAW_PENDING;
1357
    }
1358
}

powered by: WebSVN 2.1.0

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