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

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinbutton.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (show annotations) (download)
Fri Oct 14 02:09:58 2016 UTC (7 years, 4 months ago) by dashley
File MIME type: text/plain
File size: 26195 byte(s)
Rename for reorganization.
1 /* $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