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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [win/] [tkWinButton.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
 * tkWinButton.c --
3
 *
4
 *      This file implements the Windows specific portion of the button
5
 *      widgets.
6
 *
7
 * Copyright (c) 1996 by Sun Microsystems, Inc.
8
 *
9
 * See the file "license.terms" for information on usage and redistribution
10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
 *
12
 * RCS: @(#) $Id: tkWinButton.c,v 1.1.1.1 2002-01-16 10:26:02 markom Exp $
13
 */
14
 
15
#define OEMRESOURCE
16
#include "tkWinInt.h"
17
#include "tkButton.h"
18
 
19
/*
20
 * These macros define the base style flags for the different button types.
21
 */
22
 
23
#define LABEL_STYLE (BS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS)
24
#define PUSH_STYLE (BS_OWNERDRAW | BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS)
25
#define CHECK_STYLE (BS_OWNERDRAW | BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS)
26
#define RADIO_STYLE (BS_OWNERDRAW | BS_RADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS)
27
 
28
static DWORD buttonStyles[] = {
29
    LABEL_STYLE, PUSH_STYLE, CHECK_STYLE, RADIO_STYLE
30
};
31
 
32
/*
33
 * Declaration of Windows specific button structure.
34
 */
35
 
36
typedef struct WinButton {
37
    TkButton info;              /* Generic button info. */
38
    WNDPROC oldProc;            /* Old window procedure. */
39
    HWND hwnd;                  /* Current window handle. */
40
    Pixmap pixmap;              /* Bitmap for rendering the button. */
41
    int pixFlags;               /* Button flags for pixmap field. */
42
    DWORD style;                /* Window style flags. */
43
} WinButton;
44
 
45
 
46
/*
47
 * The following macro reverses the order of RGB bytes to convert
48
 * between RGBQUAD and COLORREF values.
49
 */
50
 
51
#define FlipColor(rgb) (RGB(GetBValue(rgb),GetGValue(rgb),GetRValue(rgb)))
52
 
53
/*
54
 * The following enumeration defines the meaning of the palette entries
55
 * in the "buttons" image used to draw checkbox and radiobutton indicators.
56
 */
57
 
58
enum {
59
    PAL_CHECK = 0,
60
    PAL_TOP_OUTER = 1,
61
    PAL_BOTTOM_OUTER = 2,
62
    PAL_BOTTOM_INNER = 3,
63
    PAL_INTERIOR = 4,
64
    PAL_TOP_INNER = 5,
65
    PAL_BACKGROUND = 6
66
};
67
 
68
/*
69
 * Set to non-zero if this module is initialized.
70
 */
71
 
72
static int initialized = 0;
73
 
74
/*
75
 * Variables for the cached information about the boxes bitmap.
76
 */
77
 
78
static BITMAPINFOHEADER *boxesPtr = NULL;   /* Information about the bitmap. */
79
static DWORD *boxesPalette = NULL;          /* Pointer to color palette. */
80
static LPSTR boxesBits = NULL;              /* Pointer to bitmap data. */
81
static DWORD boxHeight = 0, boxWidth = 0;    /* Size of each sub-image. */
82
 
83
/*
84
 * This variable holds the default border width for a button in string
85
 * form for use in a Tk_ConfigSpec.
86
 */
87
 
88
static char defWidth[8];
89
 
90
/*
91
 * Declarations for functions defined in this file.
92
 */
93
 
94
static int              ButtonBindProc _ANSI_ARGS_((ClientData clientData,
95
                            Tcl_Interp *interp, XEvent *eventPtr,
96
                            Tk_Window tkwin, KeySym keySym));
97
static LRESULT CALLBACK ButtonProc _ANSI_ARGS_((HWND hwnd, UINT message,
98
                            WPARAM wParam, LPARAM lParam));
99
static DWORD            ComputeStyle _ANSI_ARGS_((WinButton* butPtr));
100
static Window           CreateProc _ANSI_ARGS_((Tk_Window tkwin,
101
                            Window parent, ClientData instanceData));
102
static void             InitBoxes _ANSI_ARGS_((void));
103
static void             UpdateButtonDefaults _ANSI_ARGS_((void));
104
 
105
/* CYGNUS LOCAL.  */
106
static void             TkpRealDisplayButton _ANSI_ARGS_((ClientData, int));
107
 
108
/*
109
 * The class procedure table for the button widgets.
110
 */
111
 
112
TkClassProcs tkpButtonProcs = {
113
    CreateProc,                 /* createProc. */
114
    TkButtonWorldChanged,       /* geometryProc. */
115
    NULL                        /* modalProc. */
116
};
117
 
118
 
119
/*
120
 *----------------------------------------------------------------------
121
 *
122
 * InitBoxes --
123
 *
124
 *      This function load the Tk 3d button bitmap.  "buttons" is a 16
125
 *      color bitmap that is laid out such that the top row contains
126
 *      the 4 checkbox images, and the bottom row contains the radio
127
 *      button images. Note that the bitmap is stored in bottom-up
128
 *      format.  Also, the first seven palette entries are used to
129
 *      identify the different parts of the bitmaps so we can do the
130
 *      appropriate color mappings based on the current button colors.
131
 *
132
 * Results:
133
 *      None.
134
 *
135
 * Side effects:
136
 *      Loads the "buttons" resource.
137
 *
138
 *----------------------------------------------------------------------
139
 */
140
 
141
static void
142
InitBoxes()
143
{
144
    /*
145
     * For DLLs like Tk, the HINSTANCE is the same as the HMODULE.
146
     */
147
 
148
    HMODULE module = (HINSTANCE) Tk_GetHINSTANCE();
149
    HRSRC hrsrc;
150
    HGLOBAL hblk;
151
    LPBITMAPINFOHEADER newBitmap;
152
    DWORD size;
153
 
154
    hrsrc = FindResource(module, "buttons", RT_BITMAP);
155
    if (hrsrc) {
156
        hblk = LoadResource(module, hrsrc);
157
        boxesPtr = (LPBITMAPINFOHEADER)LockResource(hblk);
158
    }
159
 
160
    /*
161
     * Copy the DIBitmap into writable memory.
162
     */
163
 
164
    if (boxesPtr != NULL && !(boxesPtr->biWidth % 4)
165
            && !(boxesPtr->biHeight % 2)) {
166
        size = boxesPtr->biSize + (1 << boxesPtr->biBitCount) * sizeof(RGBQUAD)
167
            + boxesPtr->biSizeImage;
168
        newBitmap = (LPBITMAPINFOHEADER) ckalloc(size);
169
        memcpy(newBitmap, boxesPtr, size);
170
        boxesPtr = newBitmap;
171
        boxWidth = boxesPtr->biWidth / 4;
172
        boxHeight = boxesPtr->biHeight / 2;
173
        boxesPalette = (DWORD*) (((LPSTR)boxesPtr) + boxesPtr->biSize);
174
        boxesBits = ((LPSTR)boxesPalette)
175
            + ((1 << boxesPtr->biBitCount) * sizeof(RGBQUAD));
176
    } else {
177
        boxesPtr = NULL;
178
    }
179
}
180
 
181
/*
182
 *----------------------------------------------------------------------
183
 *
184
 * UpdateButtonDefaults --
185
 *
186
 *      This function retrieves the current system defaults for
187
 *      the button widgets.
188
 *
189
 * Results:
190
 *      None.
191
 *
192
 * Side effects:
193
 *      Updates the configuration defaults for buttons.
194
 *
195
 *----------------------------------------------------------------------
196
 */
197
 
198
void
199
UpdateButtonDefaults()
200
{
201
    Tk_ConfigSpec *specPtr;
202
    int width = GetSystemMetrics(SM_CXEDGE);
203
 
204
    if (width == 0) {
205
        width = 1;
206
    }
207
    sprintf(defWidth, "%d", width);
208
    for (specPtr = tkpButtonConfigSpecs; specPtr->type != TK_CONFIG_END;
209
            specPtr++) {
210
        if (specPtr->offset == Tk_Offset(TkButton, borderWidth)) {
211
            specPtr->defValue = defWidth;
212
        }
213
    }
214
}
215
 
216
/*
217
 *----------------------------------------------------------------------
218
 *
219
 * TkpCreateButton --
220
 *
221
 *      Allocate a new TkButton structure.
222
 *
223
 * Results:
224
 *      Returns a newly allocated TkButton structure.
225
 *
226
 * Side effects:
227
 *      Registers an event handler for the widget.
228
 *
229
 *----------------------------------------------------------------------
230
 */
231
 
232
TkButton *
233
TkpCreateButton(tkwin)
234
    Tk_Window tkwin;
235
{
236
    WinButton *butPtr;
237
 
238
    if (!initialized) {
239
        UpdateButtonDefaults();
240
        initialized = 1;
241
    }
242
 
243
    butPtr = (WinButton *)ckalloc(sizeof(WinButton));
244
    butPtr->hwnd = NULL;
245
    /* CYGNUS LOCAL: Use the pixmap field.  */
246
    butPtr->pixmap = 0;
247
    butPtr->pixFlags = 0;
248
    return (TkButton *) butPtr;
249
}
250
 
251
/*
252
 *----------------------------------------------------------------------
253
 *
254
 * CreateProc --
255
 *
256
 *      This function creates a new Button control, subclasses
257
 *      the instance, and generates a new Window object.
258
 *
259
 * Results:
260
 *      Returns the newly allocated Window object, or None on failure.
261
 *
262
 * Side effects:
263
 *      Causes a new Button control to come into existence.
264
 *
265
 *----------------------------------------------------------------------
266
 */
267
 
268
static Window
269
CreateProc(tkwin, parentWin, instanceData)
270
    Tk_Window tkwin;            /* Token for window. */
271
    Window parentWin;           /* Parent of new window. */
272
    ClientData instanceData;    /* Button instance data. */
273
{
274
    Window window;
275
    HWND parent;
276
    char *class;
277
    WinButton *butPtr = (WinButton *)instanceData;
278
 
279
    parent = Tk_GetHWND(parentWin);
280
    if (butPtr->info.type == TYPE_LABEL) {
281
        class = "STATIC";
282
        butPtr->style = SS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
283
    } else {
284
        class = "BUTTON";
285
        butPtr->style = BS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
286
    }
287
    butPtr->hwnd = CreateWindow(class, NULL, butPtr->style,
288
            Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin),
289
            parent, NULL, Tk_GetHINSTANCE(), NULL);
290
    SetWindowPos(butPtr->hwnd, HWND_TOP, 0, 0, 0, 0,
291
                    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
292
    butPtr->oldProc = (WNDPROC)SetWindowLong(butPtr->hwnd, GWL_WNDPROC,
293
            (DWORD) ButtonProc);
294
 
295
    window = Tk_AttachHWND(tkwin, butPtr->hwnd);
296
    return window;
297
}
298
 
299
/*
300
 *----------------------------------------------------------------------
301
 *
302
 * TkpDestroyButton --
303
 *
304
 *      Free data structures associated with the button control.
305
 *
306
 * Results:
307
 *      None.
308
 *
309
 * Side effects:
310
 *      Restores the default control state.
311
 *
312
 *----------------------------------------------------------------------
313
 */
314
 
315
void
316
TkpDestroyButton(butPtr)
317
    TkButton *butPtr;
318
{
319
    WinButton *winButPtr = (WinButton *)butPtr;
320
    HWND hwnd = winButPtr->hwnd;
321
    if (hwnd) {
322
        SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) winButPtr->oldProc);
323
    }
324
    /* CYGNUS LOCAL: Free the pixmap.  */
325
    if (winButPtr->pixmap != 0) {
326
        Tk_FreePixmap(butPtr->display, winButPtr->pixmap);
327
        winButPtr->pixmap = 0;
328
    }
329
}
330
 
331
/*
332
 *----------------------------------------------------------------------
333
 *
334
 * TkpDisplayButton --
335
 *
336
 *      This procedure is invoked to display a button widget.  It is
337
 *      normally invoked as an idle handler.
338
 *
339
 * Results:
340
 *      None.
341
 *
342
 * Side effects:
343
 *      Information appears on the screen.  The REDRAW_PENDING flag
344
 *      is cleared.
345
 *
346
 *----------------------------------------------------------------------
347
 */
348
 
349
void
350
TkpDisplayButton(clientData)
351
    ClientData clientData;      /* Information about widget. */
352
{
353
    /* CYGNUS LOCAL: Use a subroutine.  */
354
    TkpRealDisplayButton(clientData, 1);
355
}
356
 
357
/* CYGNUS LOCAL: This is the old TkpDisplayButton, with a force
358
   argument added.  The idea is to speed up redrawing a button due to
359
   a WM_PAINT event by saving a pixmap of the image.  */
360
 
361
static void
362
TkpRealDisplayButton(clientData, force)
363
    ClientData clientData;
364
    int force;
365
{
366
    TkWinDCState state;
367
    HDC dc;
368
    register TkButton *butPtr = (TkButton *) clientData;
369
    GC gc;
370
    Tk_3DBorder border;
371
    Pixmap pixmap;
372
    int x = 0;                   /* Initialization only needed to stop
373
                                 * compiler warning. */
374
    int y, relief;
375
    register Tk_Window tkwin = butPtr->tkwin;
376
    int width, height;
377
    int defaultWidth;           /* Width of default ring. */
378
    int offset;                 /* 0 means this is a label widget.  1 means
379
                                 * it is a flavor of button, so we offset
380
                                 * the text to make the button appear to
381
                                 * move up and down as the relief changes. */
382
 
383
    /* CYGNUS LOCAL: If the generic code has asked us to draw
384
       ourselves, force a full refresh.  */
385
    if ((butPtr->flags & REDRAW_PENDING) != 0) {
386
        force = 1;
387
    }
388
 
389
    butPtr->flags &= ~REDRAW_PENDING;
390
    if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
391
        return;
392
    }
393
 
394
    /* CYGNUS LOCAL: Use the saved pixmap if we can.  */
395
    if (! force && ((WinButton *)butPtr)->pixmap != 0
396
            && ((WinButton *)butPtr)->pixFlags == butPtr->flags) {
397
        XCopyArea(butPtr->display, ((WinButton *)butPtr)->pixmap,
398
                Tk_WindowId(tkwin), butPtr->copyGC, 0, 0,
399
                (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
400
                0, 0);
401
        return;
402
    }
403
 
404
    if (((WinButton *)butPtr)->pixmap != 0) {
405
        Tk_FreePixmap(butPtr->display, ((WinButton*)butPtr)->pixmap);
406
        ((WinButton*)butPtr)->pixmap = 0;
407
    }
408
 
409
    border = butPtr->normalBorder;
410
    if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) {
411
        gc = butPtr->disabledGC;
412
    } else if ((butPtr->state == tkActiveUid)
413
            && !Tk_StrictMotif(butPtr->tkwin)) {
414
        gc = butPtr->activeTextGC;
415
        border = butPtr->activeBorder;
416
    } else {
417
        gc = butPtr->normalTextGC;
418
    }
419
    if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid)
420
            && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) {
421
        border = butPtr->selectBorder;
422
    }
423
 
424
    /*
425
     * Override the relief specified for the button if this is a
426
     * checkbutton or radiobutton and there's no indicator.
427
     */
428
 
429
    relief = butPtr->relief;
430
    if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
431
        relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN
432
                : TK_RELIEF_RAISED;
433
    }
434
 
435
    /*
436
     * Compute width of default ring and offset for pushed buttons.
437
     */
438
 
439
    if (butPtr->type == TYPE_BUTTON) {
440
        defaultWidth = ((butPtr->defaultState == tkActiveUid)
441
                ? butPtr->highlightWidth : 0);
442
        offset = 1;
443
    } else {
444
        defaultWidth = 0;
445
        if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) {
446
            offset = 1;
447
        } else {
448
            offset = 0;
449
        }
450
    }
451
 
452
    /*
453
     * In order to avoid screen flashes, this procedure redraws
454
     * the button in a pixmap, then copies the pixmap to the
455
     * screen in a single operation.  This means that there's no
456
     * point in time where the on-sreen image has been cleared.
457
     */
458
 
459
    pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin),
460
            Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
461
    Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
462
            Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
463
 
464
    /*
465
     * Display image or bitmap or text for button.
466
     */
467
 
468
    if (butPtr->image != None) {
469
        Tk_SizeOfImage(butPtr->image, &width, &height);
470
 
471
        imageOrBitmap:
472
        TkComputeAnchor(butPtr->anchor, tkwin, 0, 0,
473
                butPtr->indicatorSpace + width, height, &x, &y);
474
        x += butPtr->indicatorSpace;
475
 
476
        if (relief == TK_RELIEF_SUNKEN) {
477
            x += offset;
478
            y += offset;
479
        }
480
        if (butPtr->image != NULL) {
481
            if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) {
482
                Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height,
483
                        pixmap, x, y);
484
            } else {
485
                Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap,
486
                        x, y);
487
            }
488
        } else {
489
            XSetClipOrigin(butPtr->display, gc, x, y);
490
            XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0,
491
                    (unsigned int) width, (unsigned int) height, x, y, 1);
492
            XSetClipOrigin(butPtr->display, gc, 0, 0);
493
        }
494
        y += height/2;
495
    } else if (butPtr->bitmap != None) {
496
        Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
497
        goto imageOrBitmap;
498
    } else {
499
        RECT rect;
500
        TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY,
501
                butPtr->indicatorSpace + butPtr->textWidth, butPtr->textHeight,
502
                &x, &y);
503
 
504
        x += butPtr->indicatorSpace;
505
 
506
        if (relief == TK_RELIEF_SUNKEN) {
507
            x += offset;
508
            y += offset;
509
        }
510
        Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout,
511
                x, y, 0, -1);
512
        Tk_UnderlineTextLayout(butPtr->display, pixmap, gc,
513
                butPtr->textLayout, x, y, butPtr->underline);
514
 
515
        /*
516
         * Draw the focus ring.  If this is a push button then we need to put
517
         * it around the inner edge of the border, otherwise we put it around
518
         * the text.
519
         */
520
 
521
        if (butPtr->flags & GOT_FOCUS && butPtr->type != TYPE_LABEL) {
522
            dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state);
523
            if (butPtr->type == TYPE_BUTTON || !butPtr->indicatorOn) {
524
                rect.top = butPtr->borderWidth + 1 + defaultWidth;
525
                rect.left = rect.top;
526
                rect.right = Tk_Width(tkwin) - rect.left;
527
                rect.bottom = Tk_Height(tkwin) - rect.top;
528
            } else {
529
                rect.top = y-2;
530
                rect.left = x-2;
531
                rect.right = x+butPtr->textWidth + 1;
532
                rect.bottom = y+butPtr->textHeight + 1;
533
            }
534
            SetTextColor(dc, gc->foreground);
535
            SetBkColor(dc, gc->background);
536
            DrawFocusRect(dc, &rect);
537
            TkWinReleaseDrawableDC(pixmap, dc, &state);
538
        }
539
        y += butPtr->textHeight/2;
540
    }
541
 
542
    /*
543
     * Draw the indicator for check buttons and radio buttons.  At this
544
     * point x and y refer to the top-left corner of the text or image
545
     * or bitmap.
546
     */
547
 
548
    if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn
549
            && boxesPtr) {
550
        int xSrc, ySrc;
551
 
552
        x -= butPtr->indicatorSpace;
553
        y -= butPtr->indicatorDiameter / 2;
554
 
555
        xSrc = (butPtr->flags & SELECTED) ? boxWidth : 0;
556
        if (butPtr->state == tkActiveUid) {
557
            xSrc += boxWidth*2;
558
        }
559
        ySrc = (butPtr->type == TYPE_RADIO_BUTTON) ? 0 : boxHeight;
560
 
561
        /*
562
         * Update the palette in the boxes bitmap to reflect the current
563
         * button colors.  Note that this code relies on the layout of the
564
         * bitmap's palette.  Also, all of the colors used to draw the
565
         * bitmap must be in the palette that is selected into the DC of
566
         * the offscreen pixmap.  This requires that the static colors
567
         * be placed into the palette.
568
         */
569
 
570
        boxesPalette[PAL_CHECK] = FlipColor(gc->foreground);
571
        boxesPalette[PAL_TOP_OUTER] = FlipColor(TkWinGetBorderPixels(tkwin,
572
                border, TK_3D_DARK_GC));
573
        boxesPalette[PAL_TOP_INNER] = FlipColor(TkWinGetBorderPixels(tkwin,
574
                border, TK_3D_DARK2));
575
        boxesPalette[PAL_BOTTOM_INNER] = FlipColor(TkWinGetBorderPixels(tkwin,
576
                border, TK_3D_LIGHT2));
577
        boxesPalette[PAL_BOTTOM_OUTER] = FlipColor(TkWinGetBorderPixels(tkwin,
578
                border, TK_3D_LIGHT_GC));
579
        if (butPtr->state == tkDisabledUid) {
580
            boxesPalette[PAL_INTERIOR] = FlipColor(TkWinGetBorderPixels(tkwin,
581
                border, TK_3D_LIGHT2));
582
        } else if (butPtr->selectBorder != NULL) {
583
            boxesPalette[PAL_INTERIOR] = FlipColor(TkWinGetBorderPixels(tkwin,
584
                    butPtr->selectBorder, TK_3D_FLAT_GC));
585
        } else {
586
            boxesPalette[PAL_INTERIOR] = FlipColor(GetSysColor(COLOR_WINDOW));
587
        }
588
        boxesPalette[PAL_BACKGROUND] = FlipColor(TkWinGetBorderPixels(tkwin,
589
                border, TK_3D_FLAT_GC));
590
 
591
        dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state);
592
        StretchDIBits(dc, x, y, boxWidth, boxHeight, xSrc, ySrc,
593
                boxWidth, boxHeight, boxesBits, (LPBITMAPINFO)boxesPtr,
594
                DIB_RGB_COLORS, SRCCOPY);
595
        TkWinReleaseDrawableDC(pixmap, dc, &state);
596
    }
597
 
598
    /*
599
     * If the button is disabled with a stipple rather than a special
600
     * foreground color, generate the stippled effect.  If the widget
601
     * is selected and we use a different background color when selected,
602
     * must temporarily modify the GC.
603
     */
604
 
605
    if ((butPtr->state == tkDisabledUid)
606
            && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) {
607
        if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
608
                && (butPtr->selectBorder != NULL)) {
609
            XSetForeground(butPtr->display, butPtr->disabledGC,
610
                    Tk_3DBorderColor(butPtr->selectBorder)->pixel);
611
        }
612
        XFillRectangle(butPtr->display, pixmap, butPtr->disabledGC,
613
                butPtr->inset, butPtr->inset,
614
                (unsigned) (Tk_Width(tkwin) - 2*butPtr->inset),
615
                (unsigned) (Tk_Height(tkwin) - 2*butPtr->inset));
616
        if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn
617
                && (butPtr->selectBorder != NULL)) {
618
            XSetForeground(butPtr->display, butPtr->disabledGC,
619
                    Tk_3DBorderColor(butPtr->normalBorder)->pixel);
620
        }
621
    }
622
 
623
    /*
624
     * Draw the border and traversal highlight last.  This way, if the
625
     * button's contents overflow they'll be covered up by the border.
626
     */
627
 
628
    if (relief != TK_RELIEF_FLAT) {
629
        Tk_Draw3DRectangle(tkwin, pixmap, border,
630
                defaultWidth, defaultWidth,
631
                Tk_Width(tkwin) - 2*defaultWidth,
632
                Tk_Height(tkwin) - 2*defaultWidth,
633
                butPtr->borderWidth, relief);
634
    }
635
    if (defaultWidth != 0) {
636
        dc = TkWinGetDrawableDC(butPtr->display, pixmap, &state);
637
        TkWinFillRect(dc, 0, 0, Tk_Width(tkwin), defaultWidth,
638
                butPtr->highlightColorPtr->pixel);
639
        TkWinFillRect(dc, 0, 0, defaultWidth, Tk_Height(tkwin),
640
                butPtr->highlightColorPtr->pixel);
641
        TkWinFillRect(dc, 0, Tk_Height(tkwin) - defaultWidth,
642
                Tk_Width(tkwin), defaultWidth,
643
                butPtr->highlightColorPtr->pixel);
644
        TkWinFillRect(dc, Tk_Width(tkwin) - defaultWidth, 0,
645
                defaultWidth, Tk_Height(tkwin),
646
                butPtr->highlightColorPtr->pixel);
647
        TkWinReleaseDrawableDC(pixmap, dc, &state);
648
    }
649
 
650
    /*
651
     * Copy the information from the off-screen pixmap onto the screen,
652
     * then delete the pixmap.
653
     */
654
 
655
    XCopyArea(butPtr->display, pixmap, Tk_WindowId(tkwin),
656
            butPtr->copyGC, 0, 0, (unsigned) Tk_Width(tkwin),
657
            (unsigned) Tk_Height(tkwin), 0, 0);
658
 
659
    /* CYGNUS LOCAL: Don't free the pixmap; save it for the next
660
       redisplay.
661
       Tk_FreePixmap(butPtr->display, pixmap);
662
    */
663
    ((WinButton*)butPtr)->pixmap = pixmap;
664
    ((WinButton*)butPtr)->pixFlags = butPtr->flags;
665
}
666
 
667
/*
668
 *----------------------------------------------------------------------
669
 *
670
 * TkpComputeButtonGeometry --
671
 *
672
 *      After changes in a button's text or bitmap, this procedure
673
 *      recomputes the button's geometry and passes this information
674
 *      along to the geometry manager for the window.
675
 *
676
 * Results:
677
 *      None.
678
 *
679
 * Side effects:
680
 *      The button's window may change size.
681
 *
682
 *----------------------------------------------------------------------
683
 */
684
 
685
void
686
TkpComputeButtonGeometry(butPtr)
687
    register TkButton *butPtr;  /* Button whose geometry may have changed. */
688
{
689
    int width, height, avgWidth;
690
    Tk_FontMetrics fm;
691
 
692
    if (butPtr->highlightWidth < 0) {
693
        butPtr->highlightWidth = 0;
694
    }
695
    butPtr->inset = butPtr->highlightWidth + butPtr->borderWidth;
696
    butPtr->indicatorSpace = 0;
697
 
698
    if (!boxesPtr) {
699
        InitBoxes();
700
    }
701
 
702
    if (butPtr->image != NULL) {
703
        Tk_SizeOfImage(butPtr->image, &width, &height);
704
        imageOrBitmap:
705
        if (butPtr->width > 0) {
706
            width = butPtr->width;
707
        }
708
        if (butPtr->height > 0) {
709
            height = butPtr->height;
710
        }
711
        if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
712
            butPtr->indicatorSpace = boxWidth * 2;
713
            butPtr->indicatorDiameter = boxHeight;
714
        }
715
    } else if (butPtr->bitmap != None) {
716
        Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height);
717
        goto imageOrBitmap;
718
    } else {
719
        Tk_FreeTextLayout(butPtr->textLayout);
720
        butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont,
721
                butPtr->text, -1, butPtr->wrapLength, butPtr->justify, 0,
722
                &butPtr->textWidth, &butPtr->textHeight);
723
 
724
        width = butPtr->textWidth;
725
        height = butPtr->textHeight;
726
        avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1);
727
        Tk_GetFontMetrics(butPtr->tkfont, &fm);
728
 
729
        if (butPtr->width > 0) {
730
            width = butPtr->width * avgWidth;
731
        }
732
        if (butPtr->height > 0) {
733
            height = butPtr->height * fm.linespace;
734
        }
735
 
736
        if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) {
737
            butPtr->indicatorDiameter = boxHeight;
738
            butPtr->indicatorSpace = butPtr->indicatorDiameter + avgWidth;
739
        }
740
 
741
        /*
742
         * Increase the inset to allow for the focus ring.
743
         */
744
 
745
        if (butPtr->type != TYPE_LABEL) {
746
            butPtr->inset += 3;
747
        }
748
    }
749
 
750
    /*
751
     * When issuing the geometry request, add extra space for the indicator,
752
     * if any, and for the border and padding, plus an extra pixel so the
753
     * display can be offset by 1 pixel in either direction for the raised
754
     * or lowered effect.
755
     */
756
 
757
    if ((butPtr->image == NULL) && (butPtr->bitmap == None)) {
758
        width += 2*butPtr->padX;
759
        height += 2*butPtr->padY;
760
    }
761
    if ((butPtr->type == TYPE_BUTTON)
762
            || ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn)) {
763
        width += 1;
764
        height += 1;
765
    }
766
    Tk_GeometryRequest(butPtr->tkwin, (int) (width + butPtr->indicatorSpace
767
            + 2*butPtr->inset), (int) (height + 2*butPtr->inset));
768
    Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
769
 
770
    /* CYGNUS LOCAL: Discard any saved pixmap.  */
771
    if (((WinButton*)butPtr)->pixmap != 0) {
772
        Tk_FreePixmap(butPtr->display, ((WinButton*)butPtr)->pixmap);
773
        ((WinButton*)butPtr)->pixmap = 0;
774
    }
775
}
776
 
777
/*
778
 *----------------------------------------------------------------------
779
 *
780
 * ButtonProc --
781
 *
782
 *      This function is call by Windows whenever an event occurs on
783
 *      a button control created by Tk.
784
 *
785
 * Results:
786
 *      Standard Windows return value.
787
 *
788
 * Side effects:
789
 *      May generate events.
790
 *
791
 *----------------------------------------------------------------------
792
 */
793
 
794
static LRESULT CALLBACK
795
ButtonProc(hwnd, message, wParam, lParam)
796
    HWND hwnd;
797
    UINT message;
798
    WPARAM wParam;
799
    LPARAM lParam;
800
{
801
    LRESULT result;
802
    WinButton *butPtr;
803
    Tk_Window tkwin = Tk_HWNDToWindow(hwnd);
804
 
805
    if (tkwin == NULL) {
806
        panic("ButtonProc called on an invalid HWND");
807
    }
808
    butPtr = (WinButton *)((TkWindow*)tkwin)->instanceData;
809
 
810
    switch(message) {
811
        case WM_ERASEBKGND:
812
            return 0;
813
 
814
        case BM_GETCHECK:
815
            if (((butPtr->info.type == TYPE_CHECK_BUTTON)
816
                    || (butPtr->info.type == TYPE_RADIO_BUTTON))
817
                    && butPtr->info.indicatorOn) {
818
                return (butPtr->info.flags & SELECTED)
819
                    ? BST_CHECKED : BST_UNCHECKED;
820
            }
821
            return 0;
822
 
823
        case BM_GETSTATE: {
824
            DWORD state = 0;
825
            if (((butPtr->info.type == TYPE_CHECK_BUTTON)
826
                    || (butPtr->info.type == TYPE_RADIO_BUTTON))
827
                    && butPtr->info.indicatorOn) {
828
                state = (butPtr->info.flags & SELECTED)
829
                    ? BST_CHECKED : BST_UNCHECKED;
830
            }
831
            if (butPtr->info.flags & GOT_FOCUS) {
832
                state |= BST_FOCUS;
833
            }
834
            return state;
835
        }
836
        case WM_ENABLE:
837
            break;
838
 
839
        case WM_PAINT: {
840
            PAINTSTRUCT ps;
841
            BeginPaint(hwnd, &ps);
842
            EndPaint(hwnd, &ps);
843
            /* CYGNUS LOCAL: Don't force the button to be recomputed.  */
844
            TkpRealDisplayButton((ClientData)butPtr, 0);
845
            return 0;
846
        }
847
        case BN_CLICKED: {
848
            int code;
849
            Tcl_Interp *interp = butPtr->info.interp;
850
            if (butPtr->info.state != tkDisabledUid) {
851
                Tcl_Preserve((ClientData)interp);
852
                code = TkInvokeButton((TkButton*)butPtr);
853
                if (code != TCL_OK && code != TCL_CONTINUE
854
                        && code != TCL_BREAK) {
855
                    Tcl_AddErrorInfo(interp, "\n    (button invoke)");
856
                    Tcl_BackgroundError(interp);
857
                }
858
                Tcl_Release((ClientData)interp);
859
            }
860
            Tcl_ServiceAll();
861
            return 0;
862
        }
863
 
864
        default:
865
            if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) {
866
                return result;
867
            }
868
    }
869
    return DefWindowProc(hwnd, message, wParam, lParam);
870
}

powered by: WebSVN 2.1.0

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