/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwinbutton.c
ViewVC logotype

Annotation of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkwinbutton.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25