KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > widgets > Button


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.widgets;
12
13
14 import org.eclipse.swt.internal.*;
15 import org.eclipse.swt.internal.win32.*;
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.graphics.*;
18 import org.eclipse.swt.events.*;
19
20 /**
21  * Instances of this class represent a selectable user interface object that
22  * issues notification when pressed and released.
23  * <dl>
24  * <dt><b>Styles:</b></dt>
25  * <dd>ARROW, CHECK, PUSH, RADIO, TOGGLE, FLAT</dd>
26  * <dd>UP, DOWN, LEFT, RIGHT, CENTER</dd>
27  * <dt><b>Events:</b></dt>
28  * <dd>Selection</dd>
29  * </dl>
30  * <p>
31  * Note: Only one of the styles ARROW, CHECK, PUSH, RADIO, and TOGGLE
32  * may be specified.
33  * </p><p>
34  * Note: Only one of the styles LEFT, RIGHT, and CENTER may be specified.
35  * </p><p>
36  * Note: Only one of the styles UP, DOWN, LEFT, and RIGHT may be specified
37  * when the ARROW style is specified.
38  * </p><p>
39  * IMPORTANT: This class is intended to be subclassed <em>only</em>
40  * within the SWT implementation.
41  * </p>
42  */

43
44 public class Button extends Control {
45     String JavaDoc text = "", message = "";
46     Image image, image2, disabledImage;
47     ImageList imageList;
48     boolean ignoreMouse;
49     static final int MARGIN = 4;
50     static final int CHECK_WIDTH, CHECK_HEIGHT;
51     static final int ICON_WIDTH = 128, ICON_HEIGHT = 128;
52     static final boolean COMMAND_LINK = false;
53     static final int ButtonProc;
54     static final TCHAR ButtonClass = new TCHAR (0, "BUTTON", true);
55     static {
56         int hBitmap = OS.LoadBitmap (0, OS.OBM_CHECKBOXES);
57         if (hBitmap == 0) {
58             CHECK_WIDTH = OS.GetSystemMetrics (OS.IsWinCE ? OS.SM_CXSMICON : OS.SM_CXVSCROLL);
59             CHECK_HEIGHT = OS.GetSystemMetrics (OS.IsWinCE ? OS.SM_CYSMICON : OS.SM_CYVSCROLL);
60         } else {
61             BITMAP bitmap = new BITMAP ();
62             OS.GetObject (hBitmap, BITMAP.sizeof, bitmap);
63             OS.DeleteObject (hBitmap);
64             CHECK_WIDTH = bitmap.bmWidth / 4;
65             CHECK_HEIGHT = bitmap.bmHeight / 3;
66         }
67         WNDCLASS lpWndClass = new WNDCLASS ();
68         OS.GetClassInfo (0, ButtonClass, lpWndClass);
69         ButtonProc = lpWndClass.lpfnWndProc;
70     }
71
72 /**
73  * Constructs a new instance of this class given its parent
74  * and a style value describing its behavior and appearance.
75  * <p>
76  * The style value is either one of the style constants defined in
77  * class <code>SWT</code> which is applicable to instances of this
78  * class, or must be built by <em>bitwise OR</em>'ing together
79  * (that is, using the <code>int</code> "|" operator) two or more
80  * of those <code>SWT</code> style constants. The class description
81  * lists the style constants that are applicable to the class.
82  * Style bits are also inherited from superclasses.
83  * </p>
84  *
85  * @param parent a composite control which will be the parent of the new instance (cannot be null)
86  * @param style the style of control to construct
87  *
88  * @exception IllegalArgumentException <ul>
89  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
90  * </ul>
91  * @exception SWTException <ul>
92  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
93  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
94  * </ul>
95  *
96  * @see SWT#ARROW
97  * @see SWT#CHECK
98  * @see SWT#PUSH
99  * @see SWT#RADIO
100  * @see SWT#TOGGLE
101  * @see SWT#FLAT
102  * @see SWT#LEFT
103  * @see SWT#RIGHT
104  * @see SWT#CENTER
105  * @see Widget#checkSubclass
106  * @see Widget#getStyle
107  */

108 public Button (Composite parent, int style) {
109     super (parent, checkStyle (style));
110 }
111
112 void _setImage (Image image) {
113     if ((style & SWT.COMMAND) != 0) return;
114     if (OS.COMCTL32_MAJOR >= 6) {
115         if (imageList != null) imageList.dispose ();
116         imageList = null;
117         if (image != null) {
118             imageList = new ImageList (style & SWT.RIGHT_TO_LEFT);
119             if (OS.IsWindowEnabled (handle)) {
120                 imageList.add (image);
121             } else {
122                 if (disabledImage != null) disabledImage.dispose ();
123                 disabledImage = new Image (display, image, SWT.IMAGE_DISABLE);
124                 imageList.add (disabledImage);
125             }
126             BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
127             buttonImageList.himl = imageList.getHandle ();
128             int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
129             newBits &= ~(OS.BS_LEFT | OS.BS_CENTER | OS.BS_RIGHT);
130             if ((style & SWT.LEFT) != 0) newBits |= OS.BS_LEFT;
131             if ((style & SWT.CENTER) != 0) newBits |= OS.BS_CENTER;
132             if ((style & SWT.RIGHT) != 0) newBits |= OS.BS_RIGHT;
133             if (text.length () == 0) {
134                 if ((style & SWT.LEFT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
135                 if ((style & SWT.CENTER) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_CENTER;
136                 if ((style & SWT.RIGHT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_RIGHT;
137             } else {
138                 buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
139                 buttonImageList.margin_left = computeLeftMargin ();
140                 buttonImageList.margin_right = MARGIN;
141                 newBits &= ~(OS.BS_CENTER | OS.BS_RIGHT);
142                 newBits |= OS.BS_LEFT;
143             }
144             if (newBits != oldBits) {
145                 OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
146                 OS.InvalidateRect (handle, null, true);
147             }
148             OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
149         } else {
150             OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, 0);
151         }
152         /*
153         * Bug in Windows. Under certain cirumstances yet to be
154         * isolated, BCM_SETIMAGELIST does not redraw the control
155         * when a new image is set. The fix is to force a redraw.
156         */

157         OS.InvalidateRect (handle, null, true);
158     } else {
159         if (image2 != null) image2.dispose ();
160         image2 = null;
161         int hImage = 0, imageBits = 0, fImageType = 0;
162         if (image != null) {
163             switch (image.type) {
164                 case SWT.BITMAP: {
165                     Rectangle rect = image.getBounds ();
166                     ImageData data = image.getImageData ();
167                     switch (data.getTransparencyType ()) {
168                         case SWT.TRANSPARENCY_PIXEL:
169                             if (rect.width <= ICON_WIDTH && rect.height <= ICON_HEIGHT) {
170                                 image2 = new Image (display, data, data.getTransparencyMask ());
171                                 hImage = image2.handle;
172                                 imageBits = OS.BS_ICON;
173                                 fImageType = OS.IMAGE_ICON;
174                                 break;
175                             }
176                             //FALL THROUGH
177
case SWT.TRANSPARENCY_ALPHA:
178                             image2 = new Image (display, rect.width, rect.height);
179                             GC gc = new GC (image2);
180                             gc.setBackground (getBackground ());
181                             gc.fillRectangle (rect);
182                             gc.drawImage (image, 0, 0);
183                             gc.dispose ();
184                             hImage = image2.handle;
185                             imageBits = OS.BS_BITMAP;
186                             fImageType = OS.IMAGE_BITMAP;
187                             break;
188                         case SWT.TRANSPARENCY_NONE:
189                             hImage = image.handle;
190                             imageBits = OS.BS_BITMAP;
191                             fImageType = OS.IMAGE_BITMAP;
192                             break;
193                     }
194                     break;
195                 }
196                 case SWT.ICON: {
197                     hImage = image.handle;
198                     imageBits = OS.BS_ICON;
199                     fImageType = OS.IMAGE_ICON;
200                     break;
201                 }
202             }
203             /*
204             * Feature in Windows. The button control mirrors its image when the
205             * flag WS_EX_LAYOUTRTL is set. This behaviour is not desirable in SWT.
206             * The fix is to set a mirrored version of real image in the button.
207             */

208             if ((style & SWT.RIGHT_TO_LEFT) != 0) {
209                 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
210                     Rectangle rect = image.getBounds ();
211                     int hDC = OS.GetDC (handle);
212                     int dstHdc = OS.CreateCompatibleDC (hDC);
213                     int hBitmap = OS.CreateCompatibleBitmap (hDC, rect.width, rect.height);
214                     int oldBitmap = OS.SelectObject (dstHdc, hBitmap);
215                     OS.SetLayout (dstHdc, OS.LAYOUT_RTL);
216                     if (fImageType == OS.IMAGE_BITMAP) {
217                         int srcHdc = OS.CreateCompatibleDC (hDC);
218                         int oldSrcBitmap = OS.SelectObject (srcHdc, hImage);
219                         OS.SetLayout (dstHdc, 0);
220                         OS.BitBlt (dstHdc, 0, 0, rect.width, rect.height, srcHdc, 0, 0, OS.SRCCOPY);
221                         OS.SelectObject (srcHdc, oldSrcBitmap);
222                         OS.DeleteDC (srcHdc);
223                     } else {
224                         Control control = findBackgroundControl ();
225                         if (control == null) control = this;
226                         int newBrush = OS.CreateSolidBrush (control.getBackgroundPixel ());
227                         int oldBrush = OS.SelectObject (dstHdc, newBrush);
228                         OS.PatBlt (dstHdc, 0, 0, rect.width, rect.height, OS.PATCOPY);
229                         OS.DrawIconEx (dstHdc, 0, 0, hImage, 0, 0, 0, 0, OS.DI_NORMAL);
230                         OS.SelectObject (dstHdc, oldBrush);
231                         OS.DeleteObject (newBrush);
232                     }
233                     OS.SelectObject (dstHdc, oldBitmap);
234                     OS.DeleteDC (dstHdc);
235                     OS.ReleaseDC (handle, hDC);
236                     if (image2 != null) image2.dispose ();
237                     image2 = Image.win32_new (display, SWT.BITMAP, hBitmap);
238                     imageBits = OS.BS_BITMAP;
239                     fImageType = OS.IMAGE_BITMAP;
240                     hImage = hBitmap;
241                 }
242             }
243         }
244         int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE), oldBits = newBits;
245         newBits &= ~(OS.BS_BITMAP | OS.BS_ICON);
246         newBits |= imageBits;
247         if (newBits != oldBits) OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
248         OS.SendMessage (handle, OS.BM_SETIMAGE, fImageType, hImage);
249     }
250 }
251
252 void _setText (String JavaDoc text) {
253     int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
254     if (OS.COMCTL32_MAJOR >= 6) {
255         newBits &= ~(OS.BS_LEFT | OS.BS_CENTER | OS.BS_RIGHT);
256         if ((style & SWT.LEFT) != 0) newBits |= OS.BS_LEFT;
257         if ((style & SWT.CENTER) != 0) newBits |= OS.BS_CENTER;
258         if ((style & SWT.RIGHT) != 0) newBits |= OS.BS_RIGHT;
259         if (imageList != null) {
260             BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
261             buttonImageList.himl = imageList.getHandle ();
262             if (text.length () == 0) {
263                 if ((style & SWT.LEFT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
264                 if ((style & SWT.CENTER) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_CENTER;
265                 if ((style & SWT.RIGHT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_RIGHT;
266             } else {
267                 buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
268                 buttonImageList.margin_left = computeLeftMargin ();
269                 buttonImageList.margin_right = MARGIN;
270                 newBits &= ~(OS.BS_CENTER | OS.BS_RIGHT);
271                 newBits |= OS.BS_LEFT;
272             }
273             OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
274         }
275     } else {
276         newBits &= ~(OS.BS_BITMAP | OS.BS_ICON);
277     }
278     if (newBits != oldBits) {
279         OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
280         OS.InvalidateRect (handle, null, true);
281     }
282     /*
283     * Bug in Windows. When a Button control is right-to-left and
284     * is disabled, the first pixel of the text is clipped. The
285     * fix is to add a space to both sides of the text.
286     */

287     if ((style & SWT.RIGHT_TO_LEFT) != 0) {
288         if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
289             text = OS.IsWindowEnabled (handle) ? text : " " + text + " ";
290         }
291     }
292     TCHAR buffer = new TCHAR (getCodePage (), text, true);
293     OS.SetWindowText (handle, buffer);
294 }
295
296 /**
297  * Adds the listener to the collection of listeners who will
298  * be notified when the control is selected by the user, by sending
299  * it one of the messages defined in the <code>SelectionListener</code>
300  * interface.
301  * <p>
302  * <code>widgetSelected</code> is called when the control is selected by the user.
303  * <code>widgetDefaultSelected</code> is not called.
304  * </p>
305  *
306  * @param listener the listener which should be notified
307  *
308  * @exception IllegalArgumentException <ul>
309  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
310  * </ul>
311  * @exception SWTException <ul>
312  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
313  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
314  * </ul>
315  *
316  * @see SelectionListener
317  * @see #removeSelectionListener
318  * @see SelectionEvent
319  */

320 public void addSelectionListener (SelectionListener listener) {
321     checkWidget ();
322     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
323     TypedListener typedListener = new TypedListener (listener);
324     addListener (SWT.Selection,typedListener);
325     addListener (SWT.DefaultSelection,typedListener);
326 }
327
328 int callWindowProc (int hwnd, int msg, int wParam, int lParam) {
329     if (handle == 0) return 0;
330     return OS.CallWindowProc (ButtonProc, hwnd, msg, wParam, lParam);
331 }
332
333 static int checkStyle (int style) {
334     style = checkBits (style, SWT.PUSH, SWT.ARROW, SWT.CHECK, SWT.RADIO, SWT.TOGGLE, COMMAND_LINK ? SWT.COMMAND : 0);
335     if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
336         return checkBits (style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0, 0, 0);
337     }
338     if ((style & (SWT.CHECK | SWT.RADIO)) != 0) {
339         return checkBits (style, SWT.LEFT, SWT.RIGHT, SWT.CENTER, 0, 0, 0);
340     }
341     if ((style & SWT.ARROW) != 0) {
342         style |= SWT.NO_FOCUS;
343         return checkBits (style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT, 0, 0);
344     }
345     return style;
346 }
347
348 void click () {
349     /*
350     * Feature in Windows. BM_CLICK sends a fake WM_LBUTTONDOWN and
351     * WM_LBUTTONUP in order to click the button. This causes the
352     * application to get unexpected mouse events. The fix is to
353     * ignore mouse events when they are caused by BM_CLICK.
354     */

355     ignoreMouse = true;
356     OS.SendMessage (handle, OS.BM_CLICK, 0, 0);
357     ignoreMouse = false;
358 }
359
360 int computeLeftMargin () {
361     if (OS.COMCTL32_MAJOR < 6) return MARGIN;
362     if ((style & (SWT.PUSH | SWT.TOGGLE)) == 0) return MARGIN;
363     int margin = 0;
364     if (image != null && text.length () != 0) {
365         Rectangle bounds = image.getBounds ();
366         margin += bounds.width + MARGIN * 2;
367         int oldFont = 0;
368         int hDC = OS.GetDC (handle);
369         int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
370         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
371         TCHAR buffer = new TCHAR (getCodePage (), text, true);
372         RECT rect = new RECT ();
373         int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE;
374         OS.DrawText (hDC, buffer, -1, rect, flags);
375         margin += rect.right - rect.left;
376         if (newFont != 0) OS.SelectObject (hDC, oldFont);
377         OS.ReleaseDC (handle, hDC);
378         OS.GetClientRect (handle, rect);
379         margin = Math.max (MARGIN, (rect.right - rect.left - margin) / 2);
380     }
381     return margin;
382 }
383
384 public Point computeSize (int wHint, int hHint, boolean changed) {
385     checkWidget ();
386     int width = 0, height = 0, border = getBorderWidth ();
387     if ((style & SWT.ARROW) != 0) {
388         if ((style & (SWT.UP | SWT.DOWN)) != 0) {
389             width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
390             height += OS.GetSystemMetrics (OS.SM_CYVSCROLL);
391         } else {
392             width += OS.GetSystemMetrics (OS.SM_CXHSCROLL);
393             height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
394         }
395     } else {
396         if ((style & SWT.COMMAND) != 0) {
397             SIZE size = new SIZE ();
398             if (wHint != SWT.DEFAULT) {
399                 size.cx = wHint;
400                 OS.SendMessage (handle, OS.BCM_GETIDEALSIZE, 0, size);
401                 width = size.cx;
402                 height = size.cy;
403             } else {
404                 OS.SendMessage (handle, OS.BCM_GETIDEALSIZE, 0, size);
405                 width = size.cy;
406                 height = size.cy;
407                 size.cy = 0;
408                 while (size.cy != height) {
409                     size.cx = width++;
410                     size.cy = 0;
411                     OS.SendMessage (handle, OS.BCM_GETIDEALSIZE, 0, size);
412                 }
413             }
414         } else {
415             int extra = 0;
416             boolean hasImage = image != null, hasText = true;
417             if (OS.COMCTL32_MAJOR < 6) {
418                 if ((style & SWT.PUSH) == 0) {
419                     int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
420                     hasImage = (bits & (OS.BS_BITMAP | OS.BS_ICON)) != 0;
421                     if (hasImage) hasText = false;
422                 }
423             }
424             if (hasImage) {
425                 if (image != null) {
426                     Rectangle rect = image.getBounds ();
427                     width = rect.width;
428                     if (hasText && text.length () != 0) {
429                         width += MARGIN * 2;
430                     }
431                     height = rect.height;
432                     extra = MARGIN * 2;
433                 }
434             }
435             if (hasText) {
436                 int oldFont = 0;
437                 int hDC = OS.GetDC (handle);
438                 int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
439                 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
440                 TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC) new TEXTMETRICW () : new TEXTMETRICA ();
441                 OS.GetTextMetrics (hDC, lptm);
442                 int length = text.length ();
443                 if (length == 0) {
444                     height = Math.max (height, lptm.tmHeight);
445                 } else {
446                     extra = Math.max (MARGIN * 2, lptm.tmAveCharWidth);
447                     TCHAR buffer = new TCHAR (getCodePage (), text, true);
448                     RECT rect = new RECT ();
449                     int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE;
450                     OS.DrawText (hDC, buffer, -1, rect, flags);
451                     width += rect.right - rect.left;
452                     height = Math.max (height, rect.bottom - rect.top);
453                 }
454                 if (newFont != 0) OS.SelectObject (hDC, oldFont);
455                 OS.ReleaseDC (handle, hDC);
456             }
457             if ((style & (SWT.CHECK | SWT.RADIO)) != 0) {
458                 width += CHECK_WIDTH + extra;
459                 height = Math.max (height, CHECK_HEIGHT + 3);
460             }
461             if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
462                 width += 12; height += 10;
463             }
464         }
465     }
466     if (wHint != SWT.DEFAULT) width = wHint;
467     if (hHint != SWT.DEFAULT) height = hHint;
468     width += border * 2;
469     height += border * 2;
470     return new Point (width, height);
471 }
472
473 void createHandle () {
474     super.createHandle ();
475     if ((style & SWT.PUSH) == 0) state |= THEME_BACKGROUND;
476     /*
477     * Bug in Windows. For some reason, the HBRUSH that
478     * is returned from WM_CTRLCOLOR is misaligned when
479     * the button uses it to draw. If the brush is a solid
480     * color, this does not matter. However, if the brush
481     * contains an image, the image is misaligned. The
482     * fix is to draw the background in WM_CTRLCOLOR.
483     *
484     * NOTE: For comctl32.dll 6.0 with themes disabled,
485     * drawing in WM_ERASEBKGND will draw on top of the
486     * text of the control.
487     */

488     if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
489         if ((style & SWT.RADIO) != 0) state |= DRAW_BACKGROUND;
490     }
491 }
492
493 int defaultBackground () {
494     if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
495         return OS.GetSysColor (OS.COLOR_BTNFACE);
496     }
497     return super.defaultBackground ();
498 }
499
500 int defaultForeground () {
501     return OS.GetSysColor (OS.COLOR_BTNTEXT);
502 }
503
504 void enableWidget (boolean enabled) {
505     super.enableWidget (enabled);
506     /*
507     * Bug in Windows. When a button control is right-to-left and
508     * is disabled, the first pixel of the text is clipped. The
509     * fix is to add a space to both sides of the text.
510     */

511     if ((style & SWT.RIGHT_TO_LEFT) != 0) {
512         if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
513             int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
514             boolean hasImage = (bits & (OS.BS_BITMAP | OS.BS_ICON)) != 0;
515             if (!hasImage) {
516                 String JavaDoc string = enabled ? text : " " + text + " ";
517                 TCHAR buffer = new TCHAR (getCodePage (), string, true);
518                 OS.SetWindowText (handle, buffer);
519             }
520         }
521     }
522     /*
523     * Bug in Windows. When a button has the style BS_CHECKBOX
524     * or BS_RADIOBUTTON, is checked, and is displaying both an
525     * image and some text, when BCM_SETIMAGELIST is used to
526     * assign an image list for each of the button states, the
527     * button does not draw properly. When the user drags the
528     * mouse in and out of the button, it draws using a blank
529     * image. The fix is to set the complete image list only
530     * when the button is disabled.
531     */

532     if (OS.COMCTL32_MAJOR >= 6) {
533         if (imageList != null) {
534             BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
535             OS.SendMessage (handle, OS.BCM_GETIMAGELIST, 0, buttonImageList);
536             if (imageList != null) imageList.dispose ();
537             imageList = new ImageList (style & SWT.RIGHT_TO_LEFT);
538             if (OS.IsWindowEnabled (handle)) {
539                 imageList.add (image);
540             } else {
541                 if (disabledImage != null) disabledImage.dispose ();
542                 disabledImage = new Image (display, image, SWT.IMAGE_DISABLE);
543                 imageList.add (disabledImage);
544             }
545             buttonImageList.himl = imageList.getHandle ();
546             OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
547             /*
548             * Bug in Windows. Under certain cirumstances yet to be
549             * isolated, BCM_SETIMAGELIST does not redraw the control
550             * when an image is set. The fix is to force a redraw.
551             */

552             OS.InvalidateRect (handle, null, true);
553         }
554     }
555 }
556
557 /**
558  * Returns a value which describes the position of the
559  * text or image in the receiver. The value will be one of
560  * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>
561  * unless the receiver is an <code>ARROW</code> button, in
562  * which case, the alignment will indicate the direction of
563  * the arrow (one of <code>LEFT</code>, <code>RIGHT</code>,
564  * <code>UP</code> or <code>DOWN</code>).
565  *
566  * @return the alignment
567  *
568  * @exception SWTException <ul>
569  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
570  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
571  * </ul>
572  */

573 public int getAlignment () {
574     checkWidget ();
575     if ((style & SWT.ARROW) != 0) {
576         if ((style & SWT.UP) != 0) return SWT.UP;
577         if ((style & SWT.DOWN) != 0) return SWT.DOWN;
578         if ((style & SWT.LEFT) != 0) return SWT.LEFT;
579         if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
580         return SWT.UP;
581     }
582     if ((style & SWT.LEFT) != 0) return SWT.LEFT;
583     if ((style & SWT.CENTER) != 0) return SWT.CENTER;
584     if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
585     return SWT.LEFT;
586 }
587
588 boolean getDefault () {
589     if ((style & SWT.PUSH) == 0) return false;
590     int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
591     return (bits & OS.BS_DEFPUSHBUTTON) != 0;
592 }
593
594 /**
595  * Returns the receiver's image if it has one, or null
596  * if it does not.
597  *
598  * @return the receiver's image
599  *
600  * @exception SWTException <ul>
601  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
602  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
603  * </ul>
604  */

605 public Image getImage () {
606     checkWidget ();
607     return image;
608 }
609
610 /**
611  * Returns the widget message. When the widget is created
612  * with the style <code>SWT.COMMAND</code>, the message text
613  * is displayed to provide further information for the user.
614  *
615  * @return the widget message
616  *
617  * @exception SWTException <ul>
618  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
619  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
620  * </ul>
621  *
622  * @since 3.3
623  */

624 /*public*/ String JavaDoc getMessage () {
625     checkWidget ();
626     return message;
627 }
628
629 String JavaDoc getNameText () {
630     return getText ();
631 }
632
633 /**
634  * Returns <code>true</code> if the receiver is selected,
635  * and false otherwise.
636  * <p>
637  * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
638  * it is selected when it is checked. When it is of type <code>TOGGLE</code>,
639  * it is selected when it is pushed in. If the receiver is of any other type,
640  * this method returns false.
641  *
642  * @return the selection state
643  *
644  * @exception SWTException <ul>
645  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
646  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
647  * </ul>
648  */

649 public boolean getSelection () {
650     checkWidget ();
651     if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return false;
652     int state = OS.SendMessage (handle, OS.BM_GETCHECK, 0, 0);
653     return (state & OS.BST_CHECKED) != 0;
654 }
655
656 /**
657  * Returns the receiver's text, which will be an empty
658  * string if it has never been set or if the receiver is
659  * an <code>ARROW</code> button.
660  *
661  * @return the receiver's text
662  *
663  * @exception SWTException <ul>
664  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
665  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
666  * </ul>
667  */

668 public String JavaDoc getText () {
669     checkWidget ();
670     if ((style & SWT.ARROW) != 0) return "";
671     return text;
672 }
673
674 boolean isTabItem () {
675     //TEMPORARY CODE
676
//if ((style & SWT.PUSH) != 0) return true;
677
return super.isTabItem ();
678 }
679
680 boolean mnemonicHit (char ch) {
681     if (!setFocus ()) return false;
682     /*
683     * Feature in Windows. When a radio button gets focus,
684     * it selects the button in WM_SETFOCUS. Therefore, it
685     * is not necessary to click the button or send events
686     * because this has already happened in WM_SETFOCUS.
687     */

688     if ((style & SWT.RADIO) == 0) click ();
689     return true;
690 }
691
692 boolean mnemonicMatch (char key) {
693     char mnemonic = findMnemonic (getText ());
694     if (mnemonic == '\0') return false;
695     return Character.toUpperCase (key) == Character.toUpperCase (mnemonic);
696 }
697
698 void releaseWidget () {
699     super.releaseWidget ();
700     if (imageList != null) imageList.dispose ();
701     imageList = null;
702     if (disabledImage != null) disabledImage.dispose ();
703     disabledImage = null;
704     if (image2 != null) image2.dispose ();
705     image2 = null;
706     text = null;
707     image = null;
708 }
709
710 /**
711  * Removes the listener from the collection of listeners who will
712  * be notified when the control is selected by the user.
713  *
714  * @param listener the listener which should no longer be notified
715  *
716  * @exception IllegalArgumentException <ul>
717  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
718  * </ul>
719  * @exception SWTException <ul>
720  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
721  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
722  * </ul>
723  *
724  * @see SelectionListener
725  * @see #addSelectionListener
726  */

727 public void removeSelectionListener (SelectionListener listener) {
728     checkWidget ();
729     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
730     if (eventTable == null) return;
731     eventTable.unhook (SWT.Selection, listener);
732     eventTable.unhook (SWT.DefaultSelection,listener);
733 }
734
735 void selectRadio () {
736     /*
737     * This code is intentionally commented. When two groups
738     * of radio buttons with the same parent are separated by
739     * another control, the correct behavior should be that
740     * the two groups act independently. This is consistent
741     * with radio tool and menu items. The commented code
742     * implements this behavior.
743     */

744 // int index = 0;
745
// Control [] children = parent._getChildren ();
746
// while (index < children.length && children [index] != this) index++;
747
// int i = index - 1;
748
// while (i >= 0 && children [i].setRadioSelection (false)) --i;
749
// int j = index + 1;
750
// while (j < children.length && children [j].setRadioSelection (false)) j++;
751
// setSelection (true);
752
Control [] children = parent._getChildren ();
753     for (int i=0; i<children.length; i++) {
754         Control child = children [i];
755         if (this != child) child.setRadioSelection (false);
756     }
757     setSelection (true);
758 }
759
760 /**
761  * Controls how text, images and arrows will be displayed
762  * in the receiver. The argument should be one of
763  * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>
764  * unless the receiver is an <code>ARROW</code> button, in
765  * which case, the argument indicates the direction of
766  * the arrow (one of <code>LEFT</code>, <code>RIGHT</code>,
767  * <code>UP</code> or <code>DOWN</code>).
768  *
769  * @param alignment the new alignment
770  *
771  * @exception SWTException <ul>
772  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
773  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
774  * </ul>
775  */

776 public void setAlignment (int alignment) {
777     checkWidget ();
778     if ((style & SWT.ARROW) != 0) {
779         if ((style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) == 0) return;
780         style &= ~(SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
781         style |= alignment & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
782         OS.InvalidateRect (handle, null, true);
783         return;
784     }
785     if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
786     style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
787     style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
788     int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
789     newBits &= ~(OS.BS_LEFT | OS.BS_CENTER | OS.BS_RIGHT);
790     if ((style & SWT.LEFT) != 0) newBits |= OS.BS_LEFT;
791     if ((style & SWT.CENTER) != 0) newBits |= OS.BS_CENTER;
792     if ((style & SWT.RIGHT) != 0) newBits |= OS.BS_RIGHT;
793     if (OS.COMCTL32_MAJOR >= 6) {
794         if (imageList != null) {
795             BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
796             buttonImageList.himl = imageList.getHandle ();
797             if (text.length () == 0) {
798                 if ((style & SWT.LEFT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
799                 if ((style & SWT.CENTER) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_CENTER;
800                 if ((style & SWT.RIGHT) != 0) buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_RIGHT;
801             } else {
802                 buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
803                 buttonImageList.margin_left = computeLeftMargin ();
804                 buttonImageList.margin_right = MARGIN;
805                 newBits &= ~(OS.BS_CENTER | OS.BS_RIGHT);
806                 newBits |= OS.BS_LEFT;
807             }
808             OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
809         }
810     }
811     if (newBits != oldBits) {
812         OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
813         OS.InvalidateRect (handle, null, true);
814     }
815 }
816
817 void setDefault (boolean value) {
818     if ((style & SWT.PUSH) == 0) return;
819     int hwndShell = menuShell ().handle;
820     int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
821     if (value) {
822         bits |= OS.BS_DEFPUSHBUTTON;
823         OS.SendMessage (hwndShell, OS.DM_SETDEFID, handle, 0);
824     } else {
825         bits &= ~OS.BS_DEFPUSHBUTTON;
826         OS.SendMessage (hwndShell, OS.DM_SETDEFID, 0, 0);
827     }
828     OS.SendMessage (handle, OS.BM_SETSTYLE, bits, 1);
829 }
830
831 boolean setFixedFocus () {
832     /*
833     * Feature in Windows. When a radio button gets focus,
834     * it selects the button in WM_SETFOCUS. The fix is to
835     * not assign focus to an unselected radio button.
836     */

837     if ((style & SWT.RADIO) != 0 && !getSelection ()) return false;
838     return super.setFixedFocus ();
839 }
840
841 /**
842  * Sets the receiver's image to the argument, which may be
843  * <code>null</code> indicating that no image should be displayed.
844  * <p>
845  * Note that a Button can display an image and text simultaneously
846  * on Windows (starting with XP), GTK+ and OSX. On other platforms,
847  * a Button that has an image and text set into it will display the
848  * image or text that was set most recently.
849  * </p>
850  * @param image the image to display on the receiver (may be <code>null</code>)
851  *
852  * @exception IllegalArgumentException <ul>
853  * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
854  * </ul>
855  * @exception SWTException <ul>
856  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
857  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
858  * </ul>
859  */

860 public void setImage (Image image) {
861     checkWidget ();
862     if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
863     if ((style & SWT.ARROW) != 0) return;
864     this.image = image;
865     /* This code is intentionally commented */
866 // if (OS.COMCTL32_MAJOR < 6) {
867
// if (image == null || text.length () != 0) {
868
// _setText (text);
869
// return;
870
// }
871
// }
872
_setImage (image);
873 }
874
875 /**
876  * Sets the widget message. When the widget is created
877  * with the style <code>SWT.COMMAND</code>, the message text
878  * is displayed to provide further information for the user.
879  *
880  * @param message the new message
881  *
882  * @exception IllegalArgumentException <ul>
883  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
884  * </ul>
885  * @exception SWTException <ul>
886  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
887  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
888  * </ul>
889  *
890  * @since 3.3
891  */

892 /*public*/ void setMessage (String JavaDoc message) {
893     checkWidget ();
894     if (message == null) error (SWT.ERROR_NULL_ARGUMENT);
895     this.message = message;
896     if (OS.COMCTL32_VERSION >= OS.VERSION (6, 1)) {
897         if ((style & SWT.COMMAND) != 0) {
898             int length = message.length ();
899             char [] chars = new char [length + 1];
900             message.getChars(0, length, chars, 0);
901             OS.SendMessage (handle, OS.BCM_SETNOTE, 0, chars);
902         }
903     }
904 }
905
906 boolean setRadioFocus () {
907     if ((style & SWT.RADIO) == 0 || !getSelection ()) return false;
908     return setFocus ();
909 }
910
911 boolean setRadioSelection (boolean value) {
912     if ((style & SWT.RADIO) == 0) return false;
913     if (getSelection () != value) {
914         setSelection (value);
915         postEvent (SWT.Selection);
916     }
917     return true;
918 }
919
920 boolean setSavedFocus () {
921     /*
922     * Feature in Windows. When a radio button gets focus,
923     * it selects the button in WM_SETFOCUS. If the previous
924     * saved focus widget was a radio button, allowing the shell
925     * to automatically restore the focus to the previous radio
926     * button will unexpectedly check that button. The fix is to
927     * not assign focus to an unselected radio button.
928     */

929     if ((style & SWT.RADIO) != 0 && !getSelection ()) return false;
930     return super.setSavedFocus ();
931 }
932
933 /**
934  * Sets the selection state of the receiver, if it is of type <code>CHECK</code>,
935  * <code>RADIO</code>, or <code>TOGGLE</code>.
936  *
937  * <p>
938  * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
939  * it is selected when it is checked. When it is of type <code>TOGGLE</code>,
940  * it is selected when it is pushed in.
941  *
942  * @param selected the new selection state
943  *
944  * @exception SWTException <ul>
945  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
946  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
947  * </ul>
948  */

949 public void setSelection (boolean selected) {
950     checkWidget ();
951     if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return;
952     int flags = selected ? OS.BST_CHECKED : OS.BST_UNCHECKED;
953     /*
954     * Feature in Windows. When BM_SETCHECK is used
955     * to set the checked state of a radio or check
956     * button, it sets the WM_TABSTOP style. This
957     * is undocumented and unwanted. The fix is
958     * to save and restore the window style bits.
959     */

960     int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
961     OS.SendMessage (handle, OS.BM_SETCHECK, flags, 0);
962     OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
963 }
964
965 /**
966  * Sets the receiver's text.
967  * <p>
968  * This method sets the button label. The label may include
969  * the mnemonic character but must not contain line delimiters.
970  * </p>
971  * <p>
972  * Mnemonics are indicated by an '&amp;' that causes the next
973  * character to be the mnemonic. When the user presses a
974  * key sequence that matches the mnemonic, a selection
975  * event occurs. On most platforms, the mnemonic appears
976  * underlined but may be emphasized in a platform specific
977  * manner. The mnemonic indicator character '&amp;' can be
978  * escaped by doubling it in the string, causing a single
979  * '&amp;' to be displayed.
980  * </p><p>
981  * Note that a Button can display an image and text simultaneously
982  * on Windows (starting with XP), GTK+ and OSX. On other platforms,
983  * a Button that has an image and text set into it will display the
984  * image or text that was set most recently.
985  * </p>
986  * @param string the new text
987  *
988  * @exception IllegalArgumentException <ul>
989  * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
990  * </ul>
991  * @exception SWTException <ul>
992  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
993  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
994  * </ul>
995  */

996 public void setText (String JavaDoc string) {
997     checkWidget ();
998     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
999     if ((style & SWT.ARROW) != 0) return;
1000    text = string;
1001    /* This code is intentionally commented */
1002// if (OS.COMCTL32_MAJOR < 6) {
1003
// if (text.length () == 0 && image != null) {
1004
// _setImage (image);
1005
// return;
1006
// }
1007
// }
1008
_setText (string);
1009}
1010
1011int widgetStyle () {
1012    int bits = super.widgetStyle ();
1013    if ((style & SWT.FLAT) != 0) bits |= OS.BS_FLAT;
1014    if ((style & SWT.ARROW) != 0) return bits | OS.BS_OWNERDRAW;
1015    if ((style & SWT.LEFT) != 0) bits |= OS.BS_LEFT;
1016    if ((style & SWT.CENTER) != 0) bits |= OS.BS_CENTER;
1017    if ((style & SWT.RIGHT) != 0) bits |= OS.BS_RIGHT;
1018    if ((style & SWT.PUSH) != 0) return bits | OS.BS_PUSHBUTTON | OS.WS_TABSTOP;
1019    if ((style & SWT.CHECK) != 0) return bits | OS.BS_CHECKBOX | OS.WS_TABSTOP;
1020    if ((style & SWT.RADIO) != 0) return bits | OS.BS_RADIOBUTTON;
1021    if ((style & SWT.TOGGLE) != 0) return bits | OS.BS_PUSHLIKE | OS.BS_CHECKBOX | OS.WS_TABSTOP;
1022    if ((style & SWT.COMMAND) != 0) return bits | OS.BS_COMMANDLINK | OS.WS_TABSTOP;
1023    return bits | OS.BS_PUSHBUTTON | OS.WS_TABSTOP;
1024}
1025
1026TCHAR windowClass () {
1027    return ButtonClass;
1028}
1029
1030int windowProc () {
1031    return ButtonProc;
1032}
1033
1034
1035LRESULT WM_ERASEBKGND (int wParam, int lParam) {
1036    LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
1037    if (result != null) return result;
1038    /*
1039    * Bug in Windows. For some reason, the HBRUSH that
1040    * is returned from WM_CTRLCOLOR is misaligned when
1041    * the button uses it to draw. If the brush is a solid
1042    * color, this does not matter. However, if the brush
1043    * contains an image, the image is misaligned. The
1044    * fix is to draw the background in WM_ERASEBKGND.
1045    */

1046    if (OS.COMCTL32_MAJOR < 6) {
1047        if ((style & (SWT.RADIO | SWT.CHECK)) != 0) {
1048            if (findImageControl () != null) {
1049                drawBackground (wParam);
1050                return LRESULT.ONE;
1051            }
1052        }
1053    }
1054    return result;
1055}
1056
1057LRESULT WM_GETDLGCODE (int wParam, int lParam) {
1058    LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
1059    if (result != null) return result;
1060    if ((style & SWT.ARROW) != 0) {
1061        return new LRESULT (OS.DLGC_STATIC);
1062    }
1063    return result;
1064}
1065
1066LRESULT WM_KILLFOCUS (int wParam, int lParam) {
1067    LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
1068    if ((style & SWT.PUSH) != 0 && getDefault ()) {
1069        menuShell ().setDefaultButton (null, false);
1070    }
1071    return result;
1072}
1073
1074LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
1075    if (ignoreMouse) return null;
1076    return super.WM_LBUTTONDOWN (wParam, lParam);
1077}
1078
1079LRESULT WM_LBUTTONUP (int wParam, int lParam) {
1080    if (ignoreMouse) return null;
1081    return super.WM_LBUTTONUP (wParam, lParam);
1082}
1083
1084LRESULT WM_SETFOCUS (int wParam, int lParam) {
1085    /*
1086    * Feature in Windows. When Windows sets focus to
1087    * a radio button, it sets the WM_TABSTOP style.
1088    * This is undocumented and unwanted. The fix is
1089    * to save and restore the window style bits.
1090    */

1091    int bits = 0;
1092    if ((style & SWT.RADIO) != 0) {
1093        bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1094    }
1095    LRESULT result = super.WM_SETFOCUS (wParam, lParam);
1096    if ((style & SWT.RADIO) != 0) {
1097        OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
1098    }
1099    if ((style & SWT.PUSH) != 0) {
1100        menuShell ().setDefaultButton (this, false);
1101    }
1102    return result;
1103}
1104
1105LRESULT WM_SIZE (int wParam, int lParam) {
1106    LRESULT result = super.WM_SIZE (wParam, lParam);
1107    if (result != null) return result;
1108    if (OS.COMCTL32_MAJOR >= 6) {
1109        if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
1110            if (imageList != null && text.length () != 0) {
1111                BUTTON_IMAGELIST buttonImageList = new BUTTON_IMAGELIST ();
1112                OS.SendMessage (handle, OS.BCM_GETIMAGELIST, 0, buttonImageList);
1113                buttonImageList.uAlign = OS.BUTTON_IMAGELIST_ALIGN_LEFT;
1114                buttonImageList.margin_left = computeLeftMargin ();
1115                buttonImageList.margin_right = MARGIN;
1116                OS.SendMessage (handle, OS.BCM_SETIMAGELIST, 0, buttonImageList);
1117            }
1118        }
1119    }
1120    return result;
1121}
1122
1123LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) {
1124    LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
1125    if (result != null) return result;
1126    if (image2 != null) _setImage (image);
1127    return result;
1128}
1129
1130LRESULT WM_UPDATEUISTATE (int wParam, int lParam) {
1131    LRESULT result = super.WM_UPDATEUISTATE (wParam, lParam);
1132    if (result != null) return result;
1133    /*
1134    * Feature in Windows. When WM_UPDATEUISTATE is sent to
1135    * a button, it sends WM_CTLCOLORBTN to get the foreground
1136    * and background. If drawing happens in WM_CTLCOLORBTN,
1137    * it will overwrite the contents of the control. The
1138    * fix is draw the button without drawing the background
1139    * and avoid the button window proc.
1140    *
1141    * NOTE: This only happens for radio, check and toggle
1142    * buttons.
1143    */

1144    if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1145        if ((style & (SWT.RADIO | SWT.CHECK | SWT.TOGGLE)) != 0) {
1146            boolean redraw = findImageControl () != null;
1147            if (!redraw) {
1148                if ((state & THEME_BACKGROUND) != 0) {
1149                    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
1150                        redraw = findThemeControl () != null;
1151                    }
1152                }
1153                if (!redraw) redraw = findBackgroundControl () != null;
1154            }
1155            if (redraw) {
1156                OS.InvalidateRect (handle, null, false);
1157                int code = OS.DefWindowProc (handle, OS.WM_UPDATEUISTATE, wParam, lParam);
1158                return new LRESULT (code);
1159            }
1160        }
1161    }
1162    return result;
1163}
1164
1165LRESULT wmCommandChild (int wParam, int lParam) {
1166    int code = wParam >> 16;
1167    switch (code) {
1168        case OS.BN_CLICKED:
1169        case OS.BN_DOUBLECLICKED:
1170            if ((style & (SWT.CHECK | SWT.TOGGLE)) != 0) {
1171                setSelection (!getSelection ());
1172            } else {
1173                if ((style & SWT.RADIO) != 0) {
1174                    if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) {
1175                        setSelection (!getSelection ());
1176                    } else {
1177                        selectRadio ();
1178                    }
1179                }
1180            }
1181            postEvent (SWT.Selection);
1182    }
1183    return super.wmCommandChild (wParam, lParam);
1184}
1185
1186LRESULT wmColorChild (int wParam, int lParam) {
1187    /*
1188    * Bug in Windows. For some reason, the HBRUSH that
1189    * is returned from WM_CTRLCOLOR is misaligned when
1190    * the button uses it to draw. If the brush is a solid
1191    * color, this does not matter. However, if the brush
1192    * contains an image, the image is misaligned. The
1193    * fix is to draw the background in WM_ERASEBKGND.
1194    */

1195    LRESULT result = super.wmColorChild (wParam, lParam);
1196    if (OS.COMCTL32_MAJOR < 6) {
1197        if ((style & (SWT.RADIO | SWT.CHECK)) != 0) {
1198            if (findImageControl () != null) {
1199                OS.SetBkMode (wParam, OS.TRANSPARENT);
1200                return new LRESULT (OS.GetStockObject (OS.NULL_BRUSH));
1201            }
1202        }
1203    }
1204    return result;
1205}
1206
1207LRESULT wmDrawChild (int wParam, int lParam) {
1208    if ((style & SWT.ARROW) == 0) return super.wmDrawChild (wParam, lParam);
1209    DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
1210    OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
1211    RECT rect = new RECT ();
1212    OS.SetRect (rect, struct.left, struct.top, struct.right, struct.bottom);
1213    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
1214        int iStateId = OS.ABS_LEFTNORMAL;
1215        switch (style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) {
1216            case SWT.UP: iStateId = OS.ABS_UPNORMAL; break;
1217            case SWT.DOWN: iStateId = OS.ABS_DOWNNORMAL; break;
1218            case SWT.LEFT: iStateId = OS.ABS_LEFTNORMAL; break;
1219            case SWT.RIGHT: iStateId = OS.ABS_RIGHTNORMAL; break;
1220        }
1221        /*
1222        * NOTE: The normal, hot, pressed and disabled state is
1223        * computed relying on the fact that the increment between
1224        * the direction states is invariant (always separated by 4).
1225        */

1226        if (!getEnabled ()) iStateId += OS.ABS_UPDISABLED - OS.ABS_UPNORMAL;
1227        if ((struct.itemState & OS.ODS_SELECTED) != 0) iStateId += OS.ABS_UPPRESSED - OS.ABS_UPNORMAL;
1228        OS.DrawThemeBackground (display.hScrollBarTheme (), struct.hDC, OS.SBP_ARROWBTN, iStateId, rect, null);
1229    } else {
1230        int uState = OS.DFCS_SCROLLLEFT;
1231        switch (style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) {
1232            case SWT.UP: uState = OS.DFCS_SCROLLUP; break;
1233            case SWT.DOWN: uState = OS.DFCS_SCROLLDOWN; break;
1234            case SWT.LEFT: uState = OS.DFCS_SCROLLLEFT; break;
1235            case SWT.RIGHT: uState = OS.DFCS_SCROLLRIGHT; break;
1236        }
1237        if (!getEnabled ()) uState |= OS.DFCS_INACTIVE;
1238        if ((style & SWT.FLAT) == SWT.FLAT) uState |= OS.DFCS_FLAT;
1239        if ((struct.itemState & OS.ODS_SELECTED) != 0) uState |= OS.DFCS_PUSHED;
1240        OS.DrawFrameControl (struct.hDC, rect, OS.DFC_SCROLL, uState);
1241    }
1242    return null;
1243}
1244
1245}
1246
Popular Tags