Source code: org/eclipse/swt/widgets/Button.java
1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-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.gtk.*;
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 public class Button extends Control {
44 long /*int*/ boxHandle, labelHandle, imageHandle, arrowHandle, groupHandle;
45 boolean selected;
46 Image image;
47 String text;
48
49 /**
50 * Constructs a new instance of this class given its parent
51 * and a style value describing its behavior and appearance.
52 * <p>
53 * The style value is either one of the style constants defined in
54 * class <code>SWT</code> which is applicable to instances of this
55 * class, or must be built by <em>bitwise OR</em>'ing together
56 * (that is, using the <code>int</code> "|" operator) two or more
57 * of those <code>SWT</code> style constants. The class description
58 * lists the style constants that are applicable to the class.
59 * Style bits are also inherited from superclasses.
60 * </p>
61 *
62 * @param parent a composite control which will be the parent of the new instance (cannot be null)
63 * @param style the style of control to construct
64 *
65 * @exception IllegalArgumentException <ul>
66 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
67 * </ul>
68 * @exception SWTException <ul>
69 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
70 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
71 * </ul>
72 *
73 * @see SWT#ARROW
74 * @see SWT#CHECK
75 * @see SWT#PUSH
76 * @see SWT#RADIO
77 * @see SWT#TOGGLE
78 * @see SWT#FLAT
79 * @see SWT#LEFT
80 * @see SWT#RIGHT
81 * @see SWT#CENTER
82 * @see Widget#checkSubclass
83 * @see Widget#getStyle
84 */
85 public Button (Composite parent, int style) {
86 super (parent, checkStyle (style));
87 }
88
89 static int checkStyle (int style) {
90 style = checkBits (style, SWT.PUSH, SWT.ARROW, SWT.CHECK, SWT.RADIO, SWT.TOGGLE, 0);
91 if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) {
92 return checkBits (style, SWT.CENTER, SWT.LEFT, SWT.RIGHT, 0, 0, 0);
93 }
94 if ((style & (SWT.CHECK | SWT.RADIO)) != 0) {
95 return checkBits (style, SWT.LEFT, SWT.RIGHT, SWT.CENTER, 0, 0, 0);
96 }
97 if ((style & SWT.ARROW) != 0) {
98 style |= SWT.NO_FOCUS;
99 return checkBits (style, SWT.UP, SWT.DOWN, SWT.LEFT, SWT.RIGHT, 0, 0);
100 }
101 return style;
102 }
103
104 /**
105 * Adds the listener to the collection of listeners who will
106 * be notified when the control is selected, by sending
107 * it one of the messages defined in the <code>SelectionListener</code>
108 * interface.
109 * <p>
110 * <code>widgetSelected</code> is called when the control is selected.
111 * <code>widgetDefaultSelected</code> is not called.
112 * </p>
113 *
114 * @param listener the listener which should be notified
115 *
116 * @exception IllegalArgumentException <ul>
117 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
118 * </ul>
119 * @exception SWTException <ul>
120 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
121 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
122 * </ul>
123 *
124 * @see SelectionListener
125 * @see #removeSelectionListener
126 * @see SelectionEvent
127 */
128 public void addSelectionListener (SelectionListener listener) {
129 checkWidget ();
130 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
131 TypedListener typedListener = new TypedListener (listener);
132 addListener (SWT.Selection,typedListener);
133 addListener (SWT.DefaultSelection,typedListener);
134 }
135
136 public Point computeSize (int wHint, int hHint, boolean changed) {
137 checkWidget ();
138 if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
139 if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
140 int width = OS.GTK_WIDGET_WIDTH (fixedHandle);
141 int height = OS.GTK_WIDGET_HEIGHT (fixedHandle);
142 OS.gtk_widget_set_size_request (handle, wHint, hHint);
143 GtkRequisition requisition = new GtkRequisition ();
144 OS.gtk_widget_size_request (handle, requisition);
145 OS.gtk_widget_set_size_request (handle, width, height);
146 width = wHint == SWT.DEFAULT ? requisition.width : wHint;
147 height = hHint == SWT.DEFAULT ? requisition.height : hHint;
148 return new Point (width, height);
149 }
150
151 void createHandle (int index) {
152 state |= HANDLE;
153 int bits = SWT.ARROW | SWT.TOGGLE | SWT.CHECK | SWT.RADIO | SWT.PUSH;
154 fixedHandle = OS.gtk_fixed_new ();
155 if (fixedHandle == 0) error (SWT.ERROR_NO_HANDLES);
156 OS.gtk_fixed_set_has_window (fixedHandle, true);
157 switch (style & bits) {
158 case SWT.ARROW:
159 int arrow_type = OS.GTK_ARROW_UP;
160 if ((style & SWT.UP) != 0) arrow_type = OS.GTK_ARROW_UP;
161 if ((style & SWT.DOWN) != 0) arrow_type = OS.GTK_ARROW_DOWN;
162 if ((style & SWT.LEFT) != 0) arrow_type = OS.GTK_ARROW_LEFT;
163 if ((style & SWT.RIGHT) != 0) arrow_type = OS.GTK_ARROW_RIGHT;
164 handle = OS.gtk_button_new ();
165 if (handle == 0) error (SWT.ERROR_NO_HANDLES);
166 arrowHandle = OS.gtk_arrow_new (arrow_type, OS.GTK_SHADOW_OUT);
167 if (arrowHandle == 0) error (SWT.ERROR_NO_HANDLES);
168 break;
169 case SWT.TOGGLE:
170 handle = OS.gtk_toggle_button_new ();
171 if (handle == 0) error (SWT.ERROR_NO_HANDLES);
172 break;
173 case SWT.CHECK:
174 handle = OS.gtk_check_button_new ();
175 if (handle == 0) error (SWT.ERROR_NO_HANDLES);
176 break;
177 case SWT.RADIO:
178 groupHandle = OS.gtk_radio_button_new (0);
179 if (groupHandle == 0) error (SWT.ERROR_NO_HANDLES);
180 OS.g_object_ref (groupHandle);
181 OS.gtk_object_sink (groupHandle);
182 handle = OS.gtk_radio_button_new (OS.gtk_radio_button_get_group (groupHandle));
183 if (handle == 0) error (SWT.ERROR_NO_HANDLES);
184 break;
185 case SWT.PUSH:
186 default:
187 handle = OS.gtk_button_new ();
188 if (handle == 0) error (SWT.ERROR_NO_HANDLES);
189 OS.GTK_WIDGET_SET_FLAGS(handle, OS.GTK_CAN_DEFAULT);
190 break;
191 }
192 if ((style & SWT.ARROW) != 0) {
193 OS.gtk_container_add (handle, arrowHandle);
194 OS.gtk_widget_show (arrowHandle);
195 } else {
196 boxHandle = OS.gtk_hbox_new (false, 0);
197 if (boxHandle == 0) error (SWT.ERROR_NO_HANDLES);
198 labelHandle = OS.gtk_label_new_with_mnemonic (null);
199 if (labelHandle == 0) error (SWT.ERROR_NO_HANDLES);
200 imageHandle = OS.gtk_image_new ();
201 if (imageHandle == 0) error (SWT.ERROR_NO_HANDLES);
202 OS.gtk_container_add (handle, boxHandle);
203 OS.gtk_container_add (boxHandle, labelHandle);
204 OS.gtk_container_add (boxHandle, imageHandle);
205 OS.gtk_widget_show (boxHandle);
206 OS.gtk_widget_show (labelHandle);
207 }
208 long /*int*/ parentHandle = parent.parentingHandle ();
209 OS.gtk_container_add (parentHandle, fixedHandle);
210 OS.gtk_container_add (fixedHandle, handle);
211 OS.gtk_widget_show (fixedHandle);
212 OS.gtk_widget_show (handle);
213
214 if ((style & SWT.ARROW) != 0) return;
215 if ((style & SWT.LEFT) != 0) {
216 OS.gtk_misc_set_alignment (labelHandle, 0.0f, 0.5f);
217 OS.gtk_label_set_justify (labelHandle, OS.GTK_JUSTIFY_LEFT);
218 OS.gtk_misc_set_alignment (imageHandle, 0.0f, 0.5f);
219 return;
220 }
221 if ((style & SWT.CENTER) != 0) {
222 OS.gtk_misc_set_alignment (labelHandle, 0.5f, 0.5f);
223 OS.gtk_label_set_justify (labelHandle, OS.GTK_JUSTIFY_CENTER);
224 OS.gtk_misc_set_alignment (imageHandle, 0.5f, 0.5f);
225 return;
226 }
227 if ((style & SWT.RIGHT) != 0) {
228 OS.gtk_misc_set_alignment (labelHandle, 1.0f, 0.5f);
229 OS.gtk_label_set_justify (labelHandle, OS.GTK_JUSTIFY_RIGHT);
230 OS.gtk_misc_set_alignment (imageHandle, 1.0f, 0.5f);
231 return;
232 }
233 }
234
235 void createWidget (int index) {
236 super.createWidget (index);
237 text = "";
238 }
239
240 void deregister () {
241 super.deregister ();
242 if (boxHandle != 0) display.removeWidget (boxHandle);
243 if (labelHandle != 0) display.removeWidget (labelHandle);
244 if (imageHandle != 0) display.removeWidget (imageHandle);
245 if (arrowHandle != 0) display.removeWidget (arrowHandle);
246 }
247
248 long /*int*/ fontHandle () {
249 if (labelHandle != 0) return labelHandle;
250 return super.fontHandle ();
251 }
252
253 /**
254 * Returns a value which describes the position of the
255 * text or image in the receiver. The value will be one of
256 * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>
257 * unless the receiver is an <code>ARROW</code> button, in
258 * which case, the alignment will indicate the direction of
259 * the arrow (one of <code>LEFT</code>, <code>RIGHT</code>,
260 * <code>UP</code> or <code>DOWN</code>).
261 *
262 * @return the alignment
263 *
264 * @exception SWTException <ul>
265 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
266 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
267 * </ul>
268 */
269 public int getAlignment () {
270 checkWidget ();
271 if ((style & SWT.ARROW) != 0) {
272 if ((style & SWT.UP) != 0) return SWT.UP;
273 if ((style & SWT.DOWN) != 0) return SWT.DOWN;
274 if ((style & SWT.LEFT) != 0) return SWT.LEFT;
275 if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
276 return SWT.UP;
277 }
278 if ((style & SWT.LEFT) != 0) return SWT.LEFT;
279 if ((style & SWT.CENTER) != 0) return SWT.CENTER;
280 if ((style & SWT.RIGHT) != 0) return SWT.RIGHT;
281 return SWT.LEFT;
282 }
283
284 /**
285 * Returns the receiver's image if it has one, or null
286 * if it does not.
287 *
288 * @return the receiver's image
289 *
290 * @exception SWTException <ul>
291 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
292 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
293 * </ul>
294 */
295 public Image getImage () {
296 checkWidget ();
297 return image;
298 }
299
300 String getNameText () {
301 return getText ();
302 }
303
304 /**
305 * Returns <code>true</code> if the receiver is selected,
306 * and false otherwise.
307 * <p>
308 * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
309 * it is selected when it is checked. When it is of type <code>TOGGLE</code>,
310 * it is selected when it is pushed in. If the receiver is of any other type,
311 * this method returns false.
312 *
313 * @return the selection state
314 *
315 * @exception SWTException <ul>
316 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
317 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
318 * </ul>
319 */
320 public boolean getSelection () {
321 checkWidget ();
322 if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return false;
323 return OS.gtk_toggle_button_get_active (handle);
324 }
325
326 /**
327 * Returns the receiver's text, which will be an empty
328 * string if it has never been set or if the receiver is
329 * an <code>ARROW</code> button.
330 *
331 * @return the receiver's text
332 *
333 * @exception SWTException <ul>
334 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
335 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
336 * </ul>
337 */
338 public String getText () {
339 checkWidget();
340 if ((style & SWT.ARROW) != 0) return "";
341 return text;
342 }
343
344 long /*int*/ gtk_button_press_event (long /*int*/ widget, long /*int*/ event) {
345 long /*int*/ result = super.gtk_button_press_event (widget, event);
346 if (result != 0) return result;
347 if ((style & SWT.RADIO) != 0) selected = getSelection ();
348 return result;
349 }
350
351 long /*int*/ gtk_clicked (long /*int*/ widget) {
352 if ((style & SWT.RADIO) != 0) {
353 if ((parent.getStyle () & SWT.NO_RADIO_GROUP) != 0) {
354 setSelection (!selected);
355 } else {
356 selectRadio ();
357 }
358 }
359 postEvent (SWT.Selection);
360 return 0;
361 }
362
363 long /*int*/ gtk_focus_in_event (long /*int*/ widget, long /*int*/ event) {
364 long /*int*/ result = super.gtk_focus_in_event (widget, event);
365 // widget could be disposed at this point
366 if (handle == 0) return 0;
367 if ((style & SWT.PUSH) != 0 && OS.GTK_WIDGET_HAS_DEFAULT (handle)) {
368 Decorations menuShell = menuShell ();
369 menuShell.defaultButton = this;
370 }
371 return result;
372 }
373
374 long /*int*/ gtk_focus_out_event (long /*int*/ widget, long /*int*/ event) {
375 long /*int*/ result = super.gtk_focus_out_event (widget, event);
376 // widget could be disposed at this point
377 if (handle == 0) return 0;
378 if ((style & SWT.PUSH) != 0 && !OS.GTK_WIDGET_HAS_DEFAULT (handle)) {
379 Decorations menuShell = menuShell ();
380 if (menuShell.defaultButton == this) {
381 menuShell.defaultButton = null;
382 }
383 }
384 return result;
385 }
386
387 long /*int*/ gtk_key_press_event (long /*int*/ widget, long /*int*/ event) {
388 long /*int*/ result = super.gtk_key_press_event (widget, event);
389 if (result != 0) return result;
390 if ((style & SWT.RADIO) != 0) selected = getSelection ();
391 return result;
392 }
393
394 void hookEvents () {
395 super.hookEvents();
396 OS.g_signal_connect (handle, OS.clicked, display.windowProc2, CLICKED);
397 if (labelHandle != 0) {
398 OS.g_signal_connect (labelHandle, OS.mnemonic_activate, display.windowProc3, MNEMONIC_ACTIVATE);
399 }
400 }
401
402 boolean mnemonicHit (char key) {
403 if (labelHandle == 0) return false;
404 boolean result = super.mnemonicHit (labelHandle, key);
405 if (result) setFocus ();
406 return result;
407 }
408
409 boolean mnemonicMatch (char key) {
410 if (labelHandle == 0) return false;
411 return mnemonicMatch (labelHandle, key);
412 }
413
414 void register () {
415 super.register ();
416 if (boxHandle != 0) display.addWidget (boxHandle, this);
417 if (labelHandle != 0) display.addWidget (labelHandle, this);
418 if (imageHandle != 0) display.addWidget (imageHandle, this);
419 if (arrowHandle != 0) display.addWidget (arrowHandle, this);
420 }
421
422 void releaseHandle () {
423 super.releaseHandle ();
424 boxHandle = imageHandle = labelHandle = arrowHandle = 0;
425 }
426
427 void releaseWidget () {
428 super.releaseWidget ();
429 if (groupHandle != 0) OS.g_object_unref (groupHandle);
430 groupHandle = 0;
431 image = null;
432 text = null;
433 }
434
435 /**
436 * Removes the listener from the collection of listeners who will
437 * be notified when the control is selected.
438 *
439 * @param listener the listener which should be notified
440 *
441 * @exception IllegalArgumentException <ul>
442 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
443 * </ul>
444 * @exception SWTException <ul>
445 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
446 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
447 * </ul>
448 *
449 * @see SelectionListener
450 * @see #addSelectionListener
451 */
452 public void removeSelectionListener (SelectionListener listener) {
453 checkWidget();
454 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
455 if (eventTable == null) return;
456 eventTable.unhook (SWT.Selection, listener);
457 eventTable.unhook (SWT.DefaultSelection,listener);
458 }
459
460 void selectRadio () {
461 /*
462 * This code is intentionally commented. When two groups
463 * of radio buttons with the same parent are separated by
464 * another control, the correct behavior should be that
465 * the two groups act independently. This is consistent
466 * with radio tool and menu items. The commented code
467 * implements this behavior.
468 */
469 // int index = 0;
470 // Control [] children = parent._getChildren ();
471 // while (index < children.length && children [index] != this) index++;
472 // int i = index - 1;
473 // while (i >= 0 && children [i].setRadioSelection (false)) --i;
474 // int j = index + 1;
475 // while (j < children.length && children [j].setRadioSelection (false)) j++;
476 // setSelection (true);
477 Control [] children = parent._getChildren ();
478 for (int i=0; i<children.length; i++) {
479 Control child = children [i];
480 if (this != child) child.setRadioSelection (false);
481 }
482 setSelection (true);
483 }
484
485 /**
486 * Controls how text, images and arrows will be displayed
487 * in the receiver. The argument should be one of
488 * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>
489 * unless the receiver is an <code>ARROW</code> button, in
490 * which case, the argument indicates the direction of
491 * the arrow (one of <code>LEFT</code>, <code>RIGHT</code>,
492 * <code>UP</code> or <code>DOWN</code>).
493 *
494 * @param alignment the new alignment
495 *
496 * @exception SWTException <ul>
497 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
498 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
499 * </ul>
500 */
501 public void setAlignment (int alignment) {
502 checkWidget ();
503 if ((style & SWT.ARROW) != 0) {
504 if ((style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) == 0) return;
505 style &= ~(SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
506 style |= alignment & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
507 int arrow_type = OS.GTK_ARROW_UP;
508 boolean isRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
509 switch (alignment) {
510 case SWT.UP: arrow_type = OS.GTK_ARROW_UP; break;
511 case SWT.DOWN: arrow_type = OS.GTK_ARROW_DOWN; break;
512 case SWT.LEFT: arrow_type = isRTL? OS.GTK_ARROW_RIGHT : OS.GTK_ARROW_LEFT; break;
513 case SWT.RIGHT: arrow_type = isRTL? OS.GTK_ARROW_LEFT : OS.GTK_ARROW_RIGHT; break;
514 }
515 OS.gtk_arrow_set (arrowHandle, arrow_type, OS.GTK_SHADOW_OUT);
516 return;
517 }
518 if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return;
519 style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
520 style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
521 if ((style & SWT.LEFT) != 0) {
522 OS.gtk_misc_set_alignment (labelHandle, 0.0f, 0.5f);
523 OS.gtk_label_set_justify (labelHandle, OS.GTK_JUSTIFY_LEFT);
524 OS.gtk_misc_set_alignment (imageHandle, 0.0f, 0.5f);
525 return;
526 }
527 if ((style & SWT.CENTER) != 0) {
528 OS.gtk_misc_set_alignment (labelHandle, 0.5f, 0.5f);
529 OS.gtk_label_set_justify (labelHandle, OS.GTK_JUSTIFY_CENTER);
530 OS.gtk_misc_set_alignment (imageHandle, 0.5f, 0.5f);
531 return;
532 }
533 if ((style & SWT.RIGHT) != 0) {
534 OS.gtk_misc_set_alignment (labelHandle, 1.0f, 0.5f);
535 OS.gtk_label_set_justify (labelHandle, OS.GTK_JUSTIFY_RIGHT);
536 OS.gtk_misc_set_alignment (imageHandle, 1.0f, 0.5f);
537 return;
538 }
539 }
540
541 void setBackgroundColor (GdkColor color) {
542 super.setBackgroundColor (color);
543 setBackgroundColor(fixedHandle, color);
544 if (labelHandle != 0) setBackgroundColor(labelHandle, color);
545 if (imageHandle != 0) setBackgroundColor(imageHandle, color);
546 }
547
548 boolean setBounds (int x, int y, int width, int height, boolean move, boolean resize) {
549 boolean result = super.setBounds (x, y, width, height, move, resize);
550 /*
551 * Feature in GTK, GtkCheckButton and GtkRadioButton allocate
552 * only the minimum size necessary for its child. This causes the child
553 * alignment to fail. The fix is to set the child size to all available space
554 * excluding trimmings.
555 */
556 if (result && (style & (SWT.CHECK | SWT.RADIO)) != 0) {
557 int childHeight = 0, buttonWidth = 0, buttonHeight = 0;
558 GtkRequisition requisition = new GtkRequisition ();
559 OS.gtk_widget_size_request (handle, requisition);
560 buttonWidth = requisition.width;
561 buttonHeight = requisition.height;
562 OS.gtk_widget_size_request (boxHandle, requisition);
563 childHeight = requisition.height;
564 OS.gtk_widget_set_size_request (handle, -1, -1);
565 OS.gtk_widget_set_size_request (boxHandle, -1, -1);
566 OS.gtk_widget_size_request (handle, requisition);
567 int trim = requisition.width;
568 OS.gtk_widget_size_request (boxHandle, requisition);
569 trim -= requisition.width;
570 OS.gtk_widget_set_size_request (handle, buttonWidth, buttonHeight);
571 OS.gtk_widget_set_size_request (boxHandle, Math.max (1, width - trim), childHeight);
572 }
573 return result;
574 }
575
576 void setFontDescription (long /*int*/ font) {
577 super.setFontDescription (font);
578 if (labelHandle != 0) OS.gtk_widget_modify_font (labelHandle, font);
579 if (imageHandle != 0) OS.gtk_widget_modify_font (imageHandle, font);
580 }
581
582 boolean setRadioSelection (boolean value) {
583 if ((style & SWT.RADIO) == 0) return false;
584 if (getSelection () != value) {
585 setSelection (value);
586 postEvent (SWT.Selection);
587 }
588 return true;
589 }
590
591 void setForegroundColor (GdkColor color) {
592 super.setForegroundColor (color);
593 OS.gtk_widget_modify_fg (fixedHandle, OS.GTK_STATE_NORMAL, color);
594 if (labelHandle != 0) OS.gtk_widget_modify_fg (labelHandle, OS.GTK_STATE_NORMAL, color);
595 if (imageHandle != 0) OS.gtk_widget_modify_fg (imageHandle, OS.GTK_STATE_NORMAL, color);
596 }
597
598 /**
599 * Sets the receiver's image to the argument, which may be
600 * null indicating that no image should be displayed.
601 *
602 * @param image the image to display on the receiver (may be null)
603 *
604 * @exception IllegalArgumentException <ul>
605 * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
606 * </ul>
607 * @exception SWTException <ul>
608 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
609 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
610 * </ul>
611 */
612 public void setImage (Image image) {
613 checkWidget ();
614 if ((style & SWT.ARROW) != 0) return;
615 if (image != null) {
616 if (image.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
617 OS.gtk_image_set_from_pixmap (imageHandle, image.pixmap, image.mask);
618 OS.gtk_widget_hide (labelHandle);
619 OS.gtk_widget_show (imageHandle);
620 } else {
621 OS.gtk_image_set_from_pixmap (imageHandle, 0, 0);
622 OS.gtk_widget_show (labelHandle);
623 OS.gtk_widget_hide (imageHandle);
624 }
625 this.image = image;
626 /*
627 * Bug in GTK. For some reason, the button does not allocate the size of its internal
628 * children if its bounds is set before the image is set. The fix is to force this by calling
629 * gtk_widget_size_request() (and throw the results away).
630 */
631 GtkRequisition requisition = new GtkRequisition ();
632 OS.gtk_widget_size_request (handle, requisition);
633 }
634
635 void setOrientation () {
636 if ((style & SWT.RIGHT_TO_LEFT) != 0) {
637 OS.gtk_widget_set_direction (handle, OS.GTK_TEXT_DIR_RTL);
638 if (labelHandle != 0) OS.gtk_widget_set_direction (labelHandle, OS.GTK_TEXT_DIR_RTL);
639 if (imageHandle != 0) OS.gtk_widget_set_direction (imageHandle, OS.GTK_TEXT_DIR_RTL);
640 if (arrowHandle != 0) {
641 switch (style & (SWT.LEFT | SWT.RIGHT)) {
642 case SWT.LEFT: OS.gtk_arrow_set (arrowHandle, OS.GTK_ARROW_RIGHT, OS.GTK_SHADOW_OUT); break;
643 case SWT.RIGHT: OS.gtk_arrow_set (arrowHandle, OS.GTK_ARROW_LEFT, OS.GTK_SHADOW_OUT); break;
644 }
645 }
646 }
647 }
648
649 /**
650 * Sets the selection state of the receiver, if it is of type <code>CHECK</code>,
651 * <code>RADIO</code>, or <code>TOGGLE</code>.
652 *
653 * <p>
654 * When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
655 * it is selected when it is checked. When it is of type <code>TOGGLE</code>,
656 * it is selected when it is pushed in.
657 *
658 * @param selected the new selection state
659 *
660 * @exception SWTException <ul>
661 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
662 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
663 * </ul>
664 */
665 public void setSelection (boolean selected) {
666 checkWidget();
667 if ((style & (SWT.CHECK | SWT.RADIO | SWT.TOGGLE)) == 0) return;
668 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CLICKED);
669 OS.gtk_toggle_button_set_active (handle, selected);
670 if ((style & SWT.RADIO) != 0) OS.gtk_toggle_button_set_active (groupHandle, !selected);
671 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CLICKED);
672 }
673
674 /**
675 * Sets the receiver's text.
676 * <p>
677 * This method sets the button label. The label may include
678 * the mnemonic character but must not contain line delimiters.
679 * </p>
680 * <p>
681 * Mnemonics are indicated by an '&' that causes the next
682 * character to be the mnemonic. When the user presses a
683 * key sequence that matches the mnemonic, a selection
684 * event occurs. On most platforms, the mnemonic appears
685 * underlined but may be emphasised in a platform specific
686 * manner. The mnemonic indicator character '&' can be
687 * escaped by doubling it in the string, causing a single
688 *'&' to be displayed.
689 * </p>
690 *
691 * @param string the new text
692 *
693 * @exception IllegalArgumentException <ul>
694 * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
695 * </ul>
696 * @exception SWTException <ul>
697 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
698 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
699 * </ul>
700 */
701 public void setText (String string) {
702 checkWidget ();
703 if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
704 if ((style & SWT.ARROW) != 0) return;
705 text = string;
706 char [] chars = fixMnemonic (string);
707 byte [] buffer = Converter.wcsToMbcs (null, chars, true);
708 OS.gtk_label_set_text_with_mnemonic (labelHandle, buffer);
709 OS.gtk_widget_hide (imageHandle);
710 OS.gtk_widget_show (labelHandle);
711 /*
712 * Bug in GTK. For some reason, the button does not allocate the size of its internal
713 * children if its bounds is set before the text is set. The fix is to force this by calling
714 * gtk_widget_size_request() (and throw the results away).
715 */
716 GtkRequisition requisition = new GtkRequisition ();
717 OS.gtk_widget_size_request (handle, requisition);
718 }
719
720 int traversalCode (int key, GdkEventKey event) {
721 int code = super.traversalCode (key, event);
722 if ((style & SWT.RADIO) != 0) code |= SWT.TRAVERSE_ARROW_NEXT | SWT.TRAVERSE_ARROW_PREVIOUS;
723 return code;
724 }
725
726 }