1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 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  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.widgets.Label;
14 
15 
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.internal.gtk.OS;
18 import org.eclipse.swt.graphics.Point;
19 import org.eclipse.swt.graphics.Image;
20 import org.eclipse.swt.widgets.Control;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.ImageList;
23 
24 import java.lang.all;
25 
26 /**
27  * Instances of this class represent a non-selectable
28  * user interface object that displays a string or image.
29  * When SEPARATOR is specified, displays a single
30  * vertical or horizontal line.
31  * <p>
32  * Shadow styles are hints and may not be honoured
33  * by the platform.  To create a separator label
34  * with the default shadow style for the platform,
35  * do not specify a shadow style.
36  * </p>
37  * <dl>
38  * <dt><b>Styles:</b></dt>
39  * <dd>SEPARATOR, HORIZONTAL, VERTICAL</dd>
40  * <dd>SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd>
41  * <dd>CENTER, LEFT, RIGHT, WRAP</dd>
42  * <dt><b>Events:</b></dt>
43  * <dd>(none)</dd>
44  * </dl>
45  * <p>
46  * Note: Only one of SHADOW_IN, SHADOW_OUT and SHADOW_NONE may be specified.
47  * SHADOW_NONE is a HINT. Only one of HORIZONTAL and VERTICAL may be specified.
48  * Only one of CENTER, LEFT and RIGHT may be specified.
49  * </p><p>
50  * IMPORTANT: This class is intended to be subclassed <em>only</em>
51  * within the SWT implementation.
52  * </p>
53  *
54  * @see <a href="http://www.eclipse.org/swt/snippets/#label">Label snippets</a>
55  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
56  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
57  */
58 public class Label : Control {
59 
60     alias Control.computeSize computeSize;
61     alias Control.mnemonicHit mnemonicHit;
62     alias Control.mnemonicMatch mnemonicMatch;
63     alias Control.setBackgroundColor setBackgroundColor;
64     alias Control.setBounds setBounds;
65     alias Control.setForegroundColor setForegroundColor;
66 
67     GtkWidget* frameHandle, labelHandle, imageHandle;
68     ImageList imageList;
69     Image image;
70     String text;
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#SEPARATOR
97  * @see SWT#HORIZONTAL
98  * @see SWT#VERTICAL
99  * @see SWT#SHADOW_IN
100  * @see SWT#SHADOW_OUT
101  * @see SWT#SHADOW_NONE
102  * @see SWT#CENTER
103  * @see SWT#LEFT
104  * @see SWT#RIGHT
105  * @see SWT#WRAP
106  * @see Widget#checkSubclass
107  * @see Widget#getStyle
108  */
109 public this (Composite parent, int style) {
110     super (parent, checkStyle (style));
111 }
112 
113 static int checkStyle (int style) {
114     style |= SWT.NO_FOCUS;
115     if ((style & SWT.SEPARATOR) !is 0) {
116         style = checkBits (style, SWT.VERTICAL, SWT.HORIZONTAL, 0, 0, 0, 0);
117         return checkBits (style, SWT.SHADOW_OUT, SWT.SHADOW_IN, SWT.SHADOW_NONE, 0, 0, 0);
118     }
119     return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0);
120 }
121 
122 override void addRelation (Control control) {
123     if (!control.isDescribedByLabel ()) return;
124     if (labelHandle is null) return;
125     auto accessible = OS.gtk_widget_get_accessible (labelHandle);
126     auto controlAccessible = OS.gtk_widget_get_accessible (control.handle);
127     if (accessible !is null && controlAccessible !is null) {
128         OS.atk_object_add_relationship (controlAccessible, OS.ATK_RELATION_LABELLED_BY, accessible);
129     }
130 }
131 
132 public override Point computeSize (int wHint, int hHint, bool changed) {
133     checkWidget ();
134     if (wHint !is SWT.DEFAULT && wHint < 0) wHint = 0;
135     if (hHint !is SWT.DEFAULT && hHint < 0) hHint = 0;
136     if ((style & SWT.SEPARATOR) !is 0) {
137         if ((style & SWT.HORIZONTAL) !is 0) {
138             if (wHint is SWT.DEFAULT) wHint = DEFAULT_WIDTH;
139         } else {
140             if (hHint is SWT.DEFAULT) hHint = DEFAULT_HEIGHT;
141         }
142     }
143     bool fixWrap = labelHandle !is null && (style & SWT.WRAP) !is 0;
144     if (fixWrap || frameHandle !is null) forceResize ();
145     int labelWidth, labelHeight;
146     if (fixWrap) {
147         OS.gtk_widget_get_size_request (labelHandle, &labelWidth, &labelHeight);
148         OS.gtk_widget_set_size_request (labelHandle, wHint, hHint);
149     }
150     Point size;
151     if (frameHandle !is null) {
152         int reqWidth, reqHeight;
153         OS.gtk_widget_get_size_request (handle, &reqWidth, &reqHeight);
154         OS.gtk_widget_set_size_request (handle, wHint, hHint);
155         size = computeNativeSize (frameHandle, -1, -1, changed);
156         OS.gtk_widget_set_size_request (handle, reqWidth, reqHeight);
157     } else {
158         size = computeNativeSize (handle, wHint, hHint, changed);
159     }
160     if (fixWrap) {
161         OS.gtk_widget_set_size_request (labelHandle, labelWidth, labelHeight);
162     }
163     /*
164     * Feature in GTK.  Instead of using the font height to determine
165     * the preferred height of the widget, GTK uses the text metrics.
166     * The fix is to ensure that the preferred height is at least as
167     * tall as the font height.
168     *
169     * NOTE: This work around does not fix the case when there are
170     * muliple lines of text.
171     */
172     if (hHint is SWT.DEFAULT && labelHandle !is null) {
173         auto layout = OS.gtk_label_get_layout (cast(GtkLabel*)labelHandle);
174         auto context = OS.pango_layout_get_context (layout);
175         auto lang = OS.pango_context_get_language (context);
176         auto font = getFontDescription ();
177         auto metrics = OS.pango_context_get_metrics (context, font, lang);
178         int ascent = OS.PANGO_PIXELS (OS.pango_font_metrics_get_ascent (metrics));
179         int descent = OS.PANGO_PIXELS (OS.pango_font_metrics_get_descent (metrics));
180         OS.pango_font_metrics_unref (metrics);
181         int fontHeight = ascent + descent;
182         int  buffer;
183         OS.g_object_get1 (labelHandle, OS.ypad.ptr, &buffer);
184         fontHeight += 2 * buffer;
185         if (frameHandle !is null) {
186             auto style = OS.gtk_widget_get_style (frameHandle);
187             fontHeight += 2 * OS.gtk_style_get_ythickness (style);
188             fontHeight += 2 * OS.gtk_container_get_border_width (cast(GtkContainer*)frameHandle);
189         }
190         size.y = Math.max (size.y, fontHeight);
191     }
192     return size;
193 }
194 
195 override void createHandle (int index) {
196     state |= HANDLE | THEME_BACKGROUND;
197     fixedHandle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null);
198     if (fixedHandle is null) error (SWT.ERROR_NO_HANDLES);
199     OS.gtk_fixed_set_has_window (cast(GtkFixed*)fixedHandle, true);
200     if ((style & SWT.SEPARATOR) !is 0) {
201         if ((style & SWT.HORIZONTAL)!is 0) {
202             handle = OS.gtk_hseparator_new ();
203         } else {
204             handle = OS.gtk_vseparator_new ();
205         }
206         if (handle is null) error (SWT.ERROR_NO_HANDLES);
207     } else {
208         handle = OS.gtk_hbox_new (false, 0);
209         if (handle is null) error (SWT.ERROR_NO_HANDLES);
210         labelHandle = OS.gtk_label_new_with_mnemonic (null);
211         if (labelHandle is null) error (SWT.ERROR_NO_HANDLES);
212         imageHandle = OS.gtk_image_new ();
213         if (imageHandle is null) error (SWT.ERROR_NO_HANDLES);
214         OS.gtk_container_add (cast(GtkContainer*)handle, labelHandle);
215         OS.gtk_container_add (cast(GtkContainer*)handle, imageHandle);
216     }
217     if ((style & SWT.BORDER) !is 0) {
218         frameHandle = OS.gtk_frame_new (null);
219         if (frameHandle is null) error (SWT.ERROR_NO_HANDLES);
220         OS.gtk_container_add (cast(GtkContainer*)fixedHandle, frameHandle);
221         OS.gtk_container_add (cast(GtkContainer*)frameHandle, handle);
222         OS.gtk_frame_set_shadow_type (cast(GtkFrame*)frameHandle, OS.GTK_SHADOW_ETCHED_IN);
223     } else {
224         OS.gtk_container_add (cast(GtkContainer*)fixedHandle, handle);
225     }
226     if ((style & SWT.SEPARATOR) !is 0) return;
227     if ((style & SWT.WRAP) !is 0) {
228         OS.gtk_label_set_line_wrap (labelHandle, true);
229         if (OS.GTK_VERSION >= OS.buildVERSION (2, 10, 0)) {
230             OS.gtk_label_set_line_wrap_mode (labelHandle, OS.PANGO_WRAP_WORD_CHAR);
231         }
232     }
233     setAlignment ();
234 }
235 
236 override void createWidget (int index) {
237     super.createWidget (index);
238     text = "";
239 }
240 
241 override void deregister () {
242     super.deregister ();
243     if (frameHandle !is null) display.removeWidget (frameHandle);
244     if (labelHandle !is null) display.removeWidget (labelHandle);
245     if (imageHandle !is null) display.removeWidget (imageHandle);
246 }
247 
248 override GtkWidget* eventHandle () {
249     return fixedHandle;
250 }
251 
252 /**
253  * Returns a value which describes the position of the
254  * text or image in the receiver. The value will be one of
255  * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>
256  * unless the receiver is a <code>SEPARATOR</code> label, in
257  * which case, <code>NONE</code> is returned.
258  *
259  * @return the alignment
260  *
261  * @exception SWTException <ul>
262  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
263  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
264  * </ul>
265  */
266 public int getAlignment () {
267     checkWidget ();
268     if ((style & SWT.SEPARATOR) !is 0) return 0;
269     if ((style & SWT.LEFT) !is 0) return SWT.LEFT;
270     if ((style & SWT.CENTER) !is 0) return SWT.CENTER;
271     if ((style & SWT.RIGHT) !is 0) return SWT.RIGHT;
272     return SWT.LEFT;
273 }
274 
275 public override int getBorderWidth () {
276     checkWidget();
277     if (frameHandle !is null) {
278         return OS.gtk_style_get_xthickness (OS.gtk_widget_get_style (frameHandle));
279     }
280     return 0;
281 }
282 
283 /**
284  * Returns the receiver's image if it has one, or null
285  * if it does not.
286  *
287  * @return the receiver's image
288  *
289  * @exception SWTException <ul>
290  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
291  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
292  * </ul>
293  */
294 public Image getImage () {
295     checkWidget ();
296     return image;
297 }
298 
299 override String getNameText () {
300     return getText ();
301 }
302 
303 /**
304  * Returns the receiver's text, which will be an empty
305  * string if it has never been set or if the receiver is
306  * a <code>SEPARATOR</code> label.
307  *
308  * @return the receiver's text
309  *
310  * @exception SWTException <ul>
311  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
312  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
313  * </ul>
314  */
315 public String getText () {
316     checkWidget ();
317     if ((style & SWT.SEPARATOR) !is 0) return "";
318     return text;
319 }
320 
321 override void hookEvents () {
322     super.hookEvents();
323     if (labelHandle !is null) {
324         OS.g_signal_connect_closure_by_id (labelHandle, display.signalIds [MNEMONIC_ACTIVATE], 0, display.closures [MNEMONIC_ACTIVATE], false);
325     }
326 }
327 
328 override bool isDescribedByLabel () {
329     return false;
330 }
331 
332 override bool mnemonicHit (wchar key) {
333     if (labelHandle is null) return false;
334     bool result = super.mnemonicHit (labelHandle, key);
335     if (result) {
336         Composite control = this.parent;
337         while (control !is null) {
338             Control [] children = control._getChildren ();
339             int index = 0;
340             while (index < children.length) {
341                 if (children [index] is this) break;
342                 index++;
343             }
344             index++;
345             if (index < children.length) {
346                 if (children [index].setFocus ()) return result;
347             }
348             control = control.parent;
349         }
350     }
351     return result;
352 }
353 
354 override bool mnemonicMatch (wchar key) {
355     if (labelHandle is null) return false;
356     return mnemonicMatch (labelHandle, key);
357 }
358 
359 override void register () {
360     super.register ();
361     if (frameHandle !is null) display.addWidget (frameHandle, this);
362     if (labelHandle !is null) display.addWidget (labelHandle, this);
363     if (imageHandle !is null) display.addWidget (imageHandle, this);
364 }
365 
366 override void releaseHandle () {
367     super.releaseHandle ();
368     frameHandle = imageHandle = labelHandle = null;
369 }
370 
371 override void releaseWidget () {
372     super.releaseWidget ();
373     if (imageList !is null) imageList.dispose ();
374     imageList = null;
375     image = null;
376     text = null;
377 }
378 
379 override void resizeHandle (int width, int height) {
380     OS.gtk_widget_set_size_request (fixedHandle, width, height);
381     OS.gtk_widget_set_size_request (frameHandle !is null ? frameHandle : handle, width, height);
382 }
383 
384 /**
385  * Controls how text and images will be displayed in the receiver.
386  * The argument should be one of <code>LEFT</code>, <code>RIGHT</code>
387  * or <code>CENTER</code>.  If the receiver is a <code>SEPARATOR</code>
388  * label, the argument is ignored and the alignment is not changed.
389  *
390  * @param alignment the new alignment
391  *
392  * @exception SWTException <ul>
393  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
394  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
395  * </ul>
396  */
397 public void setAlignment (int alignment) {
398     checkWidget ();
399     if ((style & SWT.SEPARATOR) !is 0) return;
400     if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) is 0) return;
401     style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
402     style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER);
403     setAlignment ();
404 }
405 
406 void setAlignment () {
407     bool isRTL = (style & SWT.RIGHT_TO_LEFT) !is 0;
408     if (text !is null && text.length !is 0) {
409         if (OS.GTK_VERSION >= OS.buildVERSION(2, 4, 0)) {
410             auto layout = OS.gtk_label_get_layout (labelHandle);
411             auto linePtr = OS.pango_layout_get_line (layout, 0);
412             int resolved_dir = OS.pango_layout_line_get_resolved_dir (linePtr);
413             if (resolved_dir is OS.PANGO_DIRECTION_RTL) {
414                 isRTL = !isRTL;
415             }
416         }
417     }
418     if ((style & SWT.LEFT) !is 0) {
419         OS.gtk_misc_set_alignment (cast(GtkMisc*)labelHandle, 0.0f, 0.0f);
420         OS.gtk_label_set_justify (cast(GtkLabel*)labelHandle, isRTL ? OS.GTK_JUSTIFY_RIGHT : OS.GTK_JUSTIFY_LEFT);
421         OS.gtk_misc_set_alignment (cast(GtkMisc*)imageHandle, 0.0f, 0.5f);
422         return;
423     }
424     if ((style & SWT.CENTER) !is 0) {
425         OS.gtk_misc_set_alignment (cast(GtkMisc*)labelHandle, 0.5f, 0.0f);
426         OS.gtk_label_set_justify (cast(GtkLabel*)labelHandle, OS.GTK_JUSTIFY_CENTER);
427         OS.gtk_misc_set_alignment (cast(GtkMisc*)imageHandle, 0.5f, 0.5f);
428         return;
429     }
430     if ((style & SWT.RIGHT) !is 0) {
431         OS.gtk_misc_set_alignment (cast(GtkMisc*)labelHandle, 1.0f, 0.0f);
432         OS.gtk_label_set_justify (cast(GtkLabel*)labelHandle, isRTL ? OS.GTK_JUSTIFY_LEFT : OS.GTK_JUSTIFY_RIGHT);
433         OS.gtk_misc_set_alignment (cast(GtkMisc*)imageHandle, 1.0f, 0.5f);
434         return;
435     }
436 }
437 
438 override void setBackgroundColor (GdkColor* color) {
439     super.setBackgroundColor (color);
440     setBackgroundColor(fixedHandle, color);
441     if (labelHandle !is null) setBackgroundColor(labelHandle, color);
442     if (imageHandle !is null) setBackgroundColor(imageHandle, color);
443 }
444 
445 override int setBounds (int x, int y, int width, int height, bool move, bool resize) {
446     /*
447     * Bug in GTK.  For some reason, when the label is
448     * wrappable and its container is resized, it does not
449     * cause the label to be wrapped.  The fix is to
450     * determine the size that will wrap the label
451     * and expilictly set that size to force the label
452     * to wrap.
453     *
454     * This part of the fix causes the label to be
455     * resized to the preferred size but it still
456     * won't draw properly.
457     */
458     bool fixWrap = resize && labelHandle !is null && (style & SWT.WRAP) !is 0;
459     if (fixWrap) OS.gtk_widget_set_size_request (labelHandle, -1, -1);
460     int result = super.setBounds (x, y, width, height, move, resize);
461     /*
462     * Bug in GTK.  For some reason, when the label is
463     * wrappable and its container is resized, it does not
464     * cause the label to be wrapped.  The fix is to
465     * determine the size that will wrap the label
466     * and expilictly set that size to force the label
467     * to wrap.
468     *
469     * This part of the fix forces the label to be
470     * resized so that it will draw wrapped.
471     */
472     if (fixWrap) {
473         int labelWidth = OS.GTK_WIDGET_WIDTH (handle);
474         int labelHeight = OS.GTK_WIDGET_HEIGHT (handle);
475         OS.gtk_widget_set_size_request (labelHandle, labelWidth, labelHeight);
476         /*
477         * Bug in GTK.  Setting the size request should invalidate the label's
478         * layout, but it does not.  The fix is to resize the label directly.
479         */
480         GtkRequisition requisition;
481         OS.gtk_widget_size_request (labelHandle, &requisition);
482         GtkAllocation allocation;
483         allocation.x = OS.GTK_WIDGET_X (labelHandle);
484         allocation.y = OS.GTK_WIDGET_Y (labelHandle);
485         allocation.width = labelWidth;
486         allocation.height = labelHeight;
487         OS.gtk_widget_size_allocate (labelHandle, &allocation);
488     }
489     return result;
490 }
491 
492 override void setFontDescription (PangoFontDescription* font) {
493     super.setFontDescription (font);
494     if (labelHandle !is null) OS.gtk_widget_modify_font (labelHandle, font);
495     if (imageHandle !is null) OS.gtk_widget_modify_font (imageHandle, font);
496 }
497 
498 override void setForegroundColor (GdkColor* color) {
499     super.setForegroundColor (color);
500     setForegroundColor (fixedHandle, color);
501     if (labelHandle !is null) setForegroundColor (labelHandle, color);
502     if (imageHandle !is null) setForegroundColor (imageHandle, color);
503 }
504 
505 override void setOrientation () {
506     super.setOrientation ();
507     if ((style & SWT.RIGHT_TO_LEFT) !is 0) {
508         if (labelHandle !is null) OS.gtk_widget_set_direction (labelHandle, OS.GTK_TEXT_DIR_RTL);
509         if (imageHandle !is null) OS.gtk_widget_set_direction (imageHandle, OS.GTK_TEXT_DIR_RTL);
510     }
511 }
512 
513 /**
514  * Sets the receiver's image to the argument, which may be
515  * null indicating that no image should be displayed.
516  *
517  * @param image the image to display on the receiver (may be null)
518  *
519  * @exception IllegalArgumentException <ul>
520  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
521  * </ul>
522  * @exception SWTException <ul>
523  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
524  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
525  * </ul>
526  */
527 public void setImage (Image image) {
528     checkWidget ();
529     if ((style & SWT.SEPARATOR) !is 0) return;
530     this.image = image;
531     if (imageList !is null) imageList.dispose ();
532     imageList = null;
533     if (image !is null) {
534         imageList = new ImageList ();
535         int imageIndex = imageList.add (image);
536         auto pixbuf = imageList.getPixbuf (imageIndex);
537         OS.gtk_image_set_from_pixbuf (cast(GtkImage*)imageHandle, pixbuf);
538         OS.gtk_widget_hide (labelHandle);
539         OS.gtk_widget_show (imageHandle);
540     } else {
541         OS.gtk_image_set_from_pixbuf (cast(GtkImage*)imageHandle, null);
542         OS.gtk_widget_show (labelHandle);
543         OS.gtk_widget_hide (imageHandle);
544     }
545 }
546 
547 /**
548  * Sets the receiver's text.
549  * <p>
550  * This method sets the widget label.  The label may include
551  * the mnemonic character and line delimiters.
552  * </p>
553  * <p>
554  * Mnemonics are indicated by an '&amp;' that causes the next
555  * character to be the mnemonic.  When the user presses a
556  * key sequence that matches the mnemonic, focus is assigned
557  * to the control that follows the label. On most platforms,
558  * the mnemonic appears underlined but may be emphasised in a
559  * platform specific manner.  The mnemonic indicator character
560  * '&amp;' can be escaped by doubling it in the string, causing
561  * a single '&amp;' to be displayed.
562  * </p>
563  *
564  * @param string the new text
565  *
566  * @exception SWTException <ul>
567  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
568  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
569  * </ul>
570  */
571 public void setText (String string) {
572     checkWidget ();
573     // SWT extension: allow null for zero length string
574     //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
575     if ((style & SWT.SEPARATOR) !is 0) return;
576     text = string;
577     char [] chars = fixMnemonic (string);
578     OS.gtk_label_set_text_with_mnemonic (cast(GtkLabel*)labelHandle, chars.toStringzValidPtr());
579     OS.gtk_widget_hide (imageHandle);
580     OS.gtk_widget_show (labelHandle);
581     setAlignment ();
582 }
583 
584 override void showWidget () {
585     super.showWidget ();
586     if (frameHandle !is null) OS.gtk_widget_show (frameHandle);
587     if (labelHandle !is null) OS.gtk_widget_show (labelHandle);
588 }
589 }