comparison dwt/custom/CLabel.d @ 41:6337764516f1

Sync dwt/custom with dwt-linux (took copy of complete folder)
author Frank Benoit <benoit@tionex.de>
date Tue, 07 Oct 2008 16:29:55 +0200
parents f565d3a95c0a
children
comparison
equal deleted inserted replaced
40:fbe68c33eeee 41:6337764516f1
1 /******************************************************************************* 1 /*******************************************************************************
2 * Copyright (c) 2000, 2006 IBM Corporation and others. 2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials 3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0 4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at 5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html 6 * http://www.eclipse.org/legal/epl-v10.html
7 * 7 *
8 * Contributors: 8 * Contributors:
9 * IBM Corporation - initial API and implementation 9 * IBM Corporation - initial API and implementation
10 *
11 * Port to the D programming language: 10 * Port to the D programming language:
12 * Jacob Carlborg <jacob.carlborg@gmail.com> 11 * Frank Benoit <benoit@tionex.de>
13 *******************************************************************************/ 12 *******************************************************************************/
14 module dwt.custom.CLabel; 13 module dwt.custom.CLabel;
14
15 15
16 import dwt.DWT; 16 import dwt.DWT;
17 import dwt.DWTException; 17 import dwt.DWTException;
18 import dwt.accessibility.ACC; 18 import dwt.accessibility.ACC;
19 import dwt.accessibility.Accessible; 19 import dwt.accessibility.Accessible;
36 import dwt.graphics.TextLayout; 36 import dwt.graphics.TextLayout;
37 import dwt.widgets.Canvas; 37 import dwt.widgets.Canvas;
38 import dwt.widgets.Composite; 38 import dwt.widgets.Composite;
39 import dwt.widgets.Control; 39 import dwt.widgets.Control;
40 import dwt.widgets.Display; 40 import dwt.widgets.Display;
41
42 import dwt.dwthelper.utils; 41 import dwt.dwthelper.utils;
42
43 static import tango.text.Unicode;
44 static import tango.text.convert.Utf;
43 45
44 /** 46 /**
45 * A Label which supports aligned text and/or an image and different border styles. 47 * A Label which supports aligned text and/or an image and different border styles.
46 * <p> 48 * <p>
47 * If there is not enough space a CLabel uses the following strategy to fit the 49 * If there is not enough space a CLabel uses the following strategy to fit the
48 * information into the available space: 50 * information into the available space:
49 * <pre> 51 * <pre>
50 * ignores the indent in left align mode 52 * ignores the indent in left align mode
51 * ignores the image and the gap 53 * ignores the image and the gap
52 * shortens the text by replacing the center portion of the label with an ellipsis 54 * shortens the text by replacing the center portion of the label with an ellipsis
57 * <dt><b>Styles:</b> 59 * <dt><b>Styles:</b>
58 * <dd>LEFT, RIGHT, CENTER, SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd> 60 * <dd>LEFT, RIGHT, CENTER, SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd>
59 * <dt><b>Events:</b> 61 * <dt><b>Events:</b>
60 * <dd></dd> 62 * <dd></dd>
61 * </dl> 63 * </dl>
62 * 64 *
63 * </p><p> 65 * </p><p>
64 * IMPORTANT: This class is <em>not</em> intended to be subclassed. 66 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
65 * </p> 67 * </p>
66 */ 68 *
67 public class CLabel : Canvas 69 * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: CustomControlExample</a>
68 { 70 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
71 */
72 public class CLabel : Canvas {
73
74 alias Canvas.computeSize computeSize;
69 75
70 /** Gap between icon and text */ 76 /** Gap between icon and text */
71 private static const int GAP = 5; 77 private static const int GAP = 5;
72 /** Left and right margins */ 78 /** Left and right margins */
73 private static const int INDENT = 3; 79 private static const int INDENT = 3;
74 /** a String inserted in the middle of text that has been shortened */ 80 /** a string inserted in the middle of text that has been shortened */
75 private static const String ELLIPSIS = "..."; //$NON-NLS-1$ // could use the ellipsis glyph on some platforms "\u2026" 81 private static const String ELLIPSIS = "..."; //$NON-NLS-1$ // could use the ellipsis glyph on some platforms "\u2026"
76 /** the alignnment. Either CENTER, RIGHT, LEFT. Default is LEFT*/ 82 /** the alignment. Either CENTER, RIGHT, LEFT. Default is LEFT*/
77 private int alignn = DWT.LEFT; 83 private int align_ = DWT.LEFT;
78 private int hIndent = INDENT; 84 private int hIndent = INDENT;
79 private int vIndent = INDENT; 85 private int vIndent = INDENT;
80 /** the current text */ 86 /** the current text */
81 private String text; 87 private String text;
82 /** the current icon */ 88 /** the current icon */
83 private Image image; 89 private Image image;
84 // The tooltip is used for two purposes - the application can set 90 // The tooltip is used for two purposes - the application can set
85 // a tooltip or the tooltip can be used to display the full text when the 91 // a tooltip or the tooltip can be used to display the full text when the
86 // the text has been truncated due to the label being too short. 92 // the text has been truncated due to the label being too short.
87 // The appToolTip stores the tooltip set by the application. Control.tooltiptext 93 // The appToolTip stores the tooltip set by the application. Control.tooltiptext
88 // contains whatever tooltip is currently being displayed. 94 // contains whatever tooltip is currently being displayed.
89 private String appToolTipText; 95 private String appToolTipText;
90 96
91 private Image backgroundImage; 97 private Image backgroundImage;
92 private Color[] gradientColors; 98 private Color[] gradientColors;
93 private int[] gradientPercents; 99 private int[] gradientPercents;
94 private bool gradientVertical; 100 private bool gradientVertical;
95 private Color background; 101 private Color background;
96 102
97 private static int 103 private static int DRAW_FLAGS = DWT.DRAW_MNEMONIC | DWT.DRAW_TAB | DWT.DRAW_TRANSPARENT | DWT.DRAW_DELIMITER;
98 DRAW_FLAGS = DWT.DRAW_MNEMONIC | DWT.DRAW_TAB | DWT.DRAW_TRANSPARENT | DWT.DRAW_DELIMITER; 104
99 105 /**
100 /** 106 * Constructs a new instance of this class given its parent
101 * Constructs a new instance of this class given its parent 107 * and a style value describing its behavior and appearance.
102 * and a style value describing its behavior and appearance. 108 * <p>
103 * <p> 109 * The style value is either one of the style constants defined in
104 * The style value is either one of the style constants defined in 110 * class <code>DWT</code> which is applicable to instances of this
105 * class <code>DWT</code> which is applicable to instances of this 111 * class, or must be built by <em>bitwise OR</em>'ing together
106 * class, or must be built by <em>bitwise OR</em>'ing together 112 * (that is, using the <code>int</code> "|" operator) two or more
107 * (that is, using the <code>int</code> "|" operator) two or more 113 * of those <code>DWT</code> style constants. The class description
108 * of those <code>DWT</code> style constants. The class description 114 * lists the style constants that are applicable to the class.
109 * lists the style constants that are applicable to the class. 115 * Style bits are also inherited from superclasses.
110 * Style bits are also inherited from superclasses. 116 * </p>
111 * </p> 117 *
112 * 118 * @param parent a widget which will be the parent of the new instance (cannot be null)
113 * @param parent a widget which will be the parent of the new instance (cannot be null) 119 * @param style the style of widget to construct
114 * @param style the style of widget to construct 120 *
115 * 121 * @exception IllegalArgumentException <ul>
116 * @exception IllegalArgumentException <ul> 122 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
117 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> 123 * </ul>
118 * </ul> 124 * @exception DWTException <ul>
119 * @exception DWTException <ul> 125 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
120 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> 126 * </ul>
121 * </ul> 127 *
122 * 128 * @see DWT#LEFT
123 * @see DWT#LEFT 129 * @see DWT#RIGHT
124 * @see DWT#RIGHT 130 * @see DWT#CENTER
125 * @see DWT#CENTER 131 * @see DWT#SHADOW_IN
126 * @see DWT#SHADOW_IN 132 * @see DWT#SHADOW_OUT
127 * @see DWT#SHADOW_OUT 133 * @see DWT#SHADOW_NONE
128 * @see DWT#SHADOW_NONE 134 * @see #getStyle()
129 * @see #getStyle() 135 */
130 */ 136 public this(Composite parent, int style) {
131 public this (Composite parent, int style) 137 super(parent, checkStyle(style));
132 { 138 if ((style & (DWT.CENTER | DWT.RIGHT)) is 0) style |= DWT.LEFT;
133 super(parent, checkStyle(style)); 139 if ((style & DWT.CENTER) !is 0) align_ = DWT.CENTER;
134 if ((style & (DWT.CENTER | DWT.RIGHT)) is 0) 140 if ((style & DWT.RIGHT) !is 0) align_ = DWT.RIGHT;
135 style |= DWT.LEFT; 141 if ((style & DWT.LEFT) !is 0) align_ = DWT.LEFT;
136 if ((style & DWT.CENTER) !is 0) 142
137 alignn = DWT.CENTER; 143 addPaintListener(new class() PaintListener{
138 if ((style & DWT.RIGHT) !is 0) 144 public void paintControl(PaintEvent event) {
139 alignn = DWT.RIGHT; 145 onPaint(event);
140 if ((style & DWT.LEFT) !is 0) 146 }
141 alignn = DWT.LEFT; 147 });
142 148
143 addPaintListener(new class PaintListener 149 addDisposeListener(new class() DisposeListener{
144 { 150 public void widgetDisposed(DisposeEvent event) {
145 public void paintControl (PaintEvent event) 151 onDispose(event);
146 { 152 }
147 onPaint(event); 153 });
148 } 154
149 }); 155 addTraverseListener(new class() TraverseListener {
150 156 public void keyTraversed(TraverseEvent event) {
151 addDisposeListener(new class DisposeListener 157 if (event.detail is DWT.TRAVERSE_MNEMONIC) {
152 { 158 onMnemonic(event);
153 public void widgetDisposed (DisposeEvent event) 159 }
154 { 160 }
155 onDispose(event); 161 });
156 } 162
157 }); 163 initAccessible();
158 164
159 addTraverseListener(new class TraverseListener 165 }
160 { 166 /**
161 public void keyTraversed (TraverseEvent event) 167 * Check the style bits to ensure that no invalid styles are applied.
162 { 168 */
163 if (event.detail is DWT.TRAVERSE_MNEMONIC) 169 private static int checkStyle (int style) {
164 { 170 if ((style & DWT.BORDER) !is 0) style |= DWT.SHADOW_IN;
165 onMnemonic(event); 171 int mask = DWT.SHADOW_IN | DWT.SHADOW_OUT | DWT.SHADOW_NONE | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
172 style = style & mask;
173 return style |= DWT.NO_FOCUS | DWT.DOUBLE_BUFFERED;
174 }
175
176 //protected void checkSubclass () {
177 // String name = getClass().getName ();
178 // String validName = CLabel.class.getName();
179 // if (!validName.equals(name)) {
180 // DWT.error (DWT.ERROR_INVALID_SUBCLASS);
181 // }
182 //}
183
184 public override Point computeSize(int wHint, int hHint, bool changed) {
185 checkWidget();
186 Point e = getTotalSize(image, text);
187 if (wHint is DWT.DEFAULT){
188 e.x += 2*hIndent;
189 } else {
190 e.x = wHint;
191 }
192 if (hHint is DWT.DEFAULT) {
193 e.y += 2*vIndent;
194 } else {
195 e.y = hHint;
196 }
197 return e;
198 }
199 /**
200 * Draw a rectangle in the given colors.
201 */
202 private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topleft, Color bottomright) {
203 gc.setForeground(bottomright);
204 gc.drawLine(x+w, y, x+w, y+h);
205 gc.drawLine(x, y+h, x+w, y+h);
206
207 gc.setForeground(topleft);
208 gc.drawLine(x, y, x+w-1, y);
209 gc.drawLine(x, y, x, y+h-1);
210 }
211 /*
212 * Return the lowercase of the first non-'&' character following
213 * an '&' character in the given string. If there are no '&'
214 * characters in the given string, return '\0'.
215 */
216 dchar _findMnemonic (String string) {
217 if (string is null) return '\0';
218 int index = 0;
219 int length = string.length;
220 do {
221 while (index < length && string[index] !is '&') index++;
222 if (++index >= length) return '\0';
223 if (string[index] !is '&') {
224 dchar[1] tmp; uint ate;
225 dchar[] tmp2 = tango.text.convert.Utf.toString32( string[index .. Math.min( index + 4, string.length ) ], tmp, &ate );
226 assert( tmp2.length == 1 );
227 return tango.text.Unicode.toLower( tmp2 )[0];
228 }
229 index++;
230 } while (index < length);
231 return '\0';
232 }
233 /**
234 * Returns the alignment.
235 * The alignment style (LEFT, CENTER or RIGHT) is returned.
236 *
237 * @return DWT.LEFT, DWT.RIGHT or DWT.CENTER
238 */
239 public int getAlignment() {
240 //checkWidget();
241 return align_;
242 }
243 /**
244 * Return the CLabel's image or <code>null</code>.
245 *
246 * @return the image of the label or null
247 */
248 public Image getImage() {
249 //checkWidget();
250 return image;
251 }
252 /**
253 * Compute the minimum size.
254 */
255 private Point getTotalSize(Image image, String text) {
256 Point size = new Point(0, 0);
257
258 if (image !is null) {
259 Rectangle r = image.getBounds();
260 size.x += r.width;
261 size.y += r.height;
262 }
263
264 GC gc = new GC(this);
265 if (text !is null && text.length > 0) {
266 Point e = gc.textExtent(text, DRAW_FLAGS);
267 size.x += e.x;
268 size.y = Math.max(size.y, e.y);
269 if (image !is null) size.x += GAP;
270 } else {
271 size.y = Math.max(size.y, gc.getFontMetrics().getHeight());
272 }
273 gc.dispose();
274
275 return size;
276 }
277 public override int getStyle () {
278 int style = super.getStyle();
279 switch (align_) {
280 case DWT.RIGHT: style |= DWT.RIGHT; break;
281 case DWT.CENTER: style |= DWT.CENTER; break;
282 case DWT.LEFT: style |= DWT.LEFT; break;
283 default:
284 }
285 return style;
286 }
287
288 /**
289 * Return the Label's text.
290 *
291 * @return the text of the label or null
292 */
293 public String getText() {
294 //checkWidget();
295 return text;
296 }
297 public override String getToolTipText () {
298 checkWidget();
299 return appToolTipText;
300 }
301 private void initAccessible() {
302 Accessible accessible = getAccessible();
303 accessible.addAccessibleListener(new class() AccessibleAdapter {
304 public void getName(AccessibleEvent e) {
305 e.result = getText();
306 }
307
308 public void getHelp(AccessibleEvent e) {
309 e.result = getToolTipText();
310 }
311
312 public void getKeyboardShortcut(AccessibleEvent e) {
313 dchar mnemonic = _findMnemonic(this.outer.text);
314 if (mnemonic !is '\0') {
315 dchar[1] d;
316 d[0] = mnemonic;
317 e.result = "Alt+" ~ tango.text.convert.Utf.toString(d); //$NON-NLS-1$
318 }
319 }
320 });
321
322 accessible.addAccessibleControlListener(new class() AccessibleControlAdapter {
323 public void getChildAtPoint(AccessibleControlEvent e) {
324 e.childID = ACC.CHILDID_SELF;
325 }
326
327 public void getLocation(AccessibleControlEvent e) {
328 Rectangle rect = getDisplay().map(getParent(), null, getBounds());
329 e.x = rect.x;
330 e.y = rect.y;
331 e.width = rect.width;
332 e.height = rect.height;
333 }
334
335 public void getChildCount(AccessibleControlEvent e) {
336 e.detail = 0;
337 }
338
339 public void getRole(AccessibleControlEvent e) {
340 e.detail = ACC.ROLE_LABEL;
341 }
342
343 public void getState(AccessibleControlEvent e) {
344 e.detail = ACC.STATE_READONLY;
345 }
346 });
347 }
348 void onDispose(DisposeEvent event) {
349 gradientColors = null;
350 gradientPercents = null;
351 backgroundImage = null;
352 text = null;
353 image = null;
354 appToolTipText = null;
355 }
356 void onMnemonic(TraverseEvent event) {
357 dchar mnemonic = _findMnemonic(text);
358 if (mnemonic is '\0') return;
359 dchar[1] d; uint ate;
360 auto r = tango.text.convert.Utf.toString32( [event.character][], d, &ate );
361 if (tango.text.Unicode.toLower(r)[0] !is mnemonic) return;
362 Composite control = this.getParent();
363 while (control !is null) {
364 Control [] children = control.getChildren();
365 int index = 0;
366 while (index < children.length) {
367 if (children [index] is this) break;
368 index++;
369 }
370 index++;
371 if (index < children.length) {
372 if (children [index].setFocus ()) {
373 event.doit = true;
374 event.detail = DWT.TRAVERSE_NONE;
375 }
376 }
377 control = control.getParent();
378 }
379 }
380
381 void onPaint(PaintEvent event) {
382 Rectangle rect = getClientArea();
383 if (rect.width is 0 || rect.height is 0) return;
384
385 bool shortenText_ = false;
386 String t = text;
387 Image img = image;
388 int availableWidth = Math.max(0, rect.width - 2*hIndent);
389 Point extent = getTotalSize(img, t);
390 if (extent.x > availableWidth) {
391 img = null;
392 extent = getTotalSize(img, t);
393 if (extent.x > availableWidth) {
394 shortenText_ = true;
395 }
396 }
397
398 GC gc = event.gc;
399 String[] lines = text is null ? null : splitString(text);
400
401 // shorten the text
402 if (shortenText_) {
403 extent.x = 0;
404 for(int i = 0; i < lines.length; i++) {
405 Point e = gc.textExtent(lines[i], DRAW_FLAGS);
406 if (e.x > availableWidth) {
407 lines[i] = shortenText(gc, lines[i], availableWidth);
408 extent.x = Math.max(extent.x, getTotalSize(null, lines[i]).x);
409 } else {
410 extent.x = Math.max(extent.x, e.x);
411 }
412 }
413 if (appToolTipText is null) {
414 super.setToolTipText(text);
415 }
416 } else {
417 super.setToolTipText(appToolTipText);
418 }
419
420 // determine horizontal position
421 int x = rect.x + hIndent;
422 if (align_ is DWT.CENTER) {
423 x = (rect.width - extent.x)/2;
424 }
425 if (align_ is DWT.RIGHT) {
426 x = rect.width - hIndent - extent.x;
427 }
428
429 // draw a background image behind the text
430 try {
431 if (backgroundImage !is null) {
432 // draw a background image behind the text
433 Rectangle imageRect = backgroundImage.getBounds();
434 // tile image to fill space
435 gc.setBackground(getBackground());
436 gc.fillRectangle(rect);
437 int xPos = 0;
438 while (xPos < rect.width) {
439 int yPos = 0;
440 while (yPos < rect.height) {
441 gc.drawImage(backgroundImage, xPos, yPos);
442 yPos += imageRect.height;
166 } 443 }
167 } 444 xPos += imageRect.width;
168 }); 445 }
169 446 } else if (gradientColors !is null) {
170 initAccessible(); 447 // draw a gradient behind the text
171 448 final Color oldBackground = gc.getBackground();
172 } 449 if (gradientColors.length is 1) {
173 450 if (gradientColors[0] !is null) gc.setBackground(gradientColors[0]);
174 /** 451 gc.fillRectangle(0, 0, rect.width, rect.height);
175 * Check the style bits to ensure that no invalid styles are applied. 452 } else {
176 */ 453 final Color oldForeground = gc.getForeground();
177 private static int checkStyle (int style) 454 Color lastColor = gradientColors[0];
178 { 455 if (lastColor is null) lastColor = oldBackground;
179 if ((style & DWT.BORDER) !is 0) 456 int pos = 0;
180 style |= DWT.SHADOW_IN; 457 for (int i = 0; i < gradientPercents.length; ++i) {
181 int 458 gc.setForeground(lastColor);
182 mask = DWT.SHADOW_IN | DWT.SHADOW_OUT | DWT.SHADOW_NONE | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT; 459 lastColor = gradientColors[i + 1];
183 style = style & mask; 460 if (lastColor is null) lastColor = oldBackground;
184 return style |= DWT.NO_FOCUS | DWT.DOUBLE_BUFFERED; 461 gc.setBackground(lastColor);
185 } 462 if (gradientVertical) {
186 463 final int gradientHeight = (gradientPercents[i] * rect.height / 100) - pos;
187 //protected void checkSubclass () { 464 gc.fillGradientRectangle(0, pos, rect.width, gradientHeight, true);
188 // String name = getClass().getName (); 465 pos += gradientHeight;
189 // String validName = CLabel.class.getName(); 466 } else {
190 // if (!validName.opEquals(name)) { 467 final int gradientWidth = (gradientPercents[i] * rect.width / 100) - pos;
191 // DWT.error (DWT.ERROR_INVALID_SUBCLASS); 468 gc.fillGradientRectangle(pos, 0, gradientWidth, rect.height, false);
192 // } 469 pos += gradientWidth;
193 //} 470 }
194 471 }
195 public Point computeSize (int wHint, int hHint, bool changed) 472 if (gradientVertical && pos < rect.height) {
196 { 473 gc.setBackground(getBackground());
197 checkWidget(); 474 gc.fillRectangle(0, pos, rect.width, rect.height - pos);
198 Point e = getTotalSize(image, text); 475 }
199 if (wHint is DWT.DEFAULT) 476 if (!gradientVertical && pos < rect.width) {
200 { 477 gc.setBackground(getBackground());
201 e.x += 2 * hIndent; 478 gc.fillRectangle(pos, 0, rect.width - pos, rect.height);
202 } 479 }
203 else 480 gc.setForeground(oldForeground);
204 { 481 }
205 e.x = wHint; 482 gc.setBackground(oldBackground);
206 } 483 } else {
207 if (hHint is DWT.DEFAULT) 484 if (background !is null || (getStyle() & DWT.DOUBLE_BUFFERED) is 0) {
208 { 485 gc.setBackground(getBackground());
209 e.y += 2 * vIndent; 486 gc.fillRectangle(rect);
210 } 487 }
211 else 488 }
212 { 489 } catch (DWTException e) {
213 e.y = hHint; 490 if ((getStyle() & DWT.DOUBLE_BUFFERED) is 0) {
214 } 491 gc.setBackground(getBackground());
215 return e; 492 gc.fillRectangle(rect);
216 } 493 }
217 494 }
218 /** 495
219 * Draw a rectangle in the given colors. 496 // draw border
220 */ 497 int style = getStyle();
221 private void drawBevelRect (GC gc, int x, int y, int w, int h, 498 if ((style & DWT.SHADOW_IN) !is 0 || (style & DWT.SHADOW_OUT) !is 0) {
222 Color topleft, Color bottomright) 499 paintBorder(gc, rect);
223 { 500 }
224 gc.setForeground(bottomright); 501
225 gc.drawLine(x + w, y, x + w, y + h); 502 // draw the image
226 gc.drawLine(x, y + h, x + w, y + h); 503 if (img !is null) {
227 504 Rectangle imageRect = img.getBounds();
228 gc.setForeground(topleft); 505 gc.drawImage(img, 0, 0, imageRect.width, imageRect.height,
229 gc.drawLine(x, y, x + w - 1, y); 506 x, (rect.height-imageRect.height)/2, imageRect.width, imageRect.height);
230 gc.drawLine(x, y, x, y + h - 1); 507 x += imageRect.width + GAP;
231 } 508 extent.x -= imageRect.width + GAP;
232 509 }
233 /* 510 // draw the text
234 * Return the lowercase of the first non-'&' character following 511 if (lines !is null) {
235 * an '&' character in the given String. If there are no '&' 512 int lineHeight = gc.getFontMetrics().getHeight();
236 * characters in the given String, return '\0'. 513 int textHeight = lines.length * lineHeight;
237 */ 514 int lineY = Math.max(vIndent, rect.y + (rect.height - textHeight) / 2);
238 char _findMnemonic (String str) 515 gc.setForeground(getForeground());
239 { 516 for (int i = 0; i < lines.length; i++) {
240 if (str is null) 517 int lineX = x;
241 return '\0'; 518 if (lines.length > 1) {
242 int index = 0; 519 if (align_ is DWT.CENTER) {
243 int length = str.length(); 520 int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
244 do 521 lineX = x + Math.max(0, (extent.x - lineWidth) / 2);
245 { 522 }
246 while (index < length && str.charAt(index) !is '&') 523 if (align_ is DWT.RIGHT) {
247 index++; 524 int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
248 if (++index >= length) 525 lineX = Math.max(x, rect.x + rect.width - hIndent - lineWidth);
249 return '\0'; 526 }
250 if (str.charAt(index) !is '&') 527 }
251 return CharacterToLower(str.charAt(index)); 528 gc.drawText(lines[i], lineX, lineY, DRAW_FLAGS);
252 index++; 529 lineY += lineHeight;
253 } while (index < length); 530 }
254 return '\0'; 531 }
255 } 532 }
256 533 /**
257 /** 534 * Paint the Label's border.
258 * Returns the alignnment. 535 */
259 * The alignnment style (LEFT, CENTER or RIGHT) is returned. 536 private void paintBorder(GC gc, Rectangle r) {
260 * 537 Display disp= getDisplay();
261 * @return DWT.LEFT, DWT.RIGHT or DWT.CENTER 538
262 */ 539 Color c1 = null;
263 public int getAlignment () 540 Color c2 = null;
264 { 541
265 //checkWidget(); 542 int style = getStyle();
266 return alignn; 543 if ((style & DWT.SHADOW_IN) !is 0) {
267 } 544 c1 = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
268 545 c2 = disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
269 /** 546 }
270 * Return the CLabel's image or <code>null</code>. 547 if ((style & DWT.SHADOW_OUT) !is 0) {
271 * 548 c1 = disp.getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW);
272 * @return the image of the label or null 549 c2 = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
273 */ 550 }
274 public Image getImage () 551
275 { 552 if (c1 !is null && c2 !is null) {
276 //checkWidget(); 553 gc.setLineWidth(1);
277 return image; 554 drawBevelRect(gc, r.x, r.y, r.width-1, r.height-1, c1, c2);
278 } 555 }
279 556 }
280 /** 557 /**
281 * Compute the minimum size. 558 * Set the alignment of the CLabel.
282 */ 559 * Use the values LEFT, CENTER and RIGHT to align image and text within the available space.
283 private Point getTotalSize (Image image, String text) 560 *
284 { 561 * @param align the alignment style of LEFT, RIGHT or CENTER
285 Point size = new Point(0, 0); 562 *
286 563 * @exception DWTException <ul>
287 if (image !is null) 564 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
288 { 565 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
289 Rectangle r = image.getBounds(); 566 * <li>ERROR_INVALID_ARGUMENT - if the value of align is not one of DWT.LEFT, DWT.RIGHT or DWT.CENTER</li>
290 size.x += r.width; 567 * </ul>
291 size.y += r.height; 568 */
292 } 569 public void setAlignment(int align_) {
293 570 checkWidget();
294 GC gc = new GC(this); 571 if (align_ !is DWT.LEFT && align_ !is DWT.RIGHT && align_ !is DWT.CENTER) {
295 if (text !is null && text.length() > 0) 572 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
296 { 573 }
297 Point e = gc.textExtent(text, DRAW_FLAGS); 574 if (this.align_ !is align_) {
298 size.x += e.x; 575 this.align_ = align_;
299 size.y = Math.max(size.y, e.y); 576 redraw();
300 if (image !is null) 577 }
301 size.x += GAP; 578 }
302 } 579
303 else 580 public override void setBackground (Color color) {
304 { 581 super.setBackground (color);
305 size.y = Math.max(size.y, gc.getFontMetrics().getHeight()); 582 // Are these settings the same as before?
306 } 583 if (backgroundImage is null &&
307 gc.dispose(); 584 gradientColors is null &&
308 585 gradientPercents is null) {
309 return size; 586 if (color is null) {
310 } 587 if (background is null) return;
311 588 } else {
312 public int getStyle () 589 if (color ==/*eq*/ background) return;
313 { 590 }
314 int style = super.getStyle(); 591 }
315 switch (alignn) 592 background = color;
316 { 593 backgroundImage = null;
317 case DWT.RIGHT: 594 gradientColors = null;
318 style |= DWT.RIGHT; 595 gradientPercents = null;
319 break; 596 redraw ();
320 case DWT.CENTER: 597 }
321 style |= DWT.CENTER; 598
322 break; 599 /**
323 case DWT.LEFT: 600 * Specify a gradient of colours to be drawn in the background of the CLabel.
324 style |= DWT.LEFT; 601 * <p>For example, to draw a gradient that varies from dark blue to blue and then to
325 break; 602 * white and stays white for the right half of the label, use the following call
326 } 603 * to setBackground:</p>
327 return style; 604 * <pre>
328 } 605 * clabel.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
329 606 * display.getSystemColor(DWT.COLOR_BLUE),
330 /** 607 * display.getSystemColor(DWT.COLOR_WHITE),
331 * Return the Label's text. 608 * display.getSystemColor(DWT.COLOR_WHITE)},
332 * 609 * new int[] {25, 50, 100});
333 * @return the text of the label or null 610 * </pre>
334 */ 611 *
335 public String getText () 612 * @param colors an array of Color that specifies the colors to appear in the gradient
336 { 613 * in order of appearance from left to right; The value <code>null</code>
337 //checkWidget(); 614 * clears the background gradient; the value <code>null</code> can be used
338 return text; 615 * inside the array of Color to specify the background color.
339 } 616 * @param percents an array of integers between 0 and 100 specifying the percent of the width
340 617 * of the widget at which the color should change; the size of the percents
341 public String getToolTipText () 618 * array must be one less than the size of the colors array.
342 { 619 *
343 checkWidget(); 620 * @exception DWTException <ul>
344 return appToolTipText; 621 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
345 } 622 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
346 623 * <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li>
347 private void initAccessible () 624 * </ul>
348 { 625 */
349 Accessible accessible = getAccessible(); 626 public void setBackground(Color[] colors, int[] percents) {
350 accessible.addAccessibleListener(new class AccessibleAdapter 627 setBackground(colors, percents, false);
351 { 628 }
352 public void getName (AccessibleEvent e) 629 /**
353 { 630 * Specify a gradient of colours to be drawn in the background of the CLabel.
354 e.result = getText(); 631 * <p>For example, to draw a gradient that varies from dark blue to white in the vertical,
355 } 632 * direction use the following call
356 633 * to setBackground:</p>
357 public void getHelp (AccessibleEvent e) 634 * <pre>
358 { 635 * clabel.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
359 e.result = getToolTipText(); 636 * display.getSystemColor(DWT.COLOR_WHITE)},
360 } 637 * new int[] {100}, true);
361 638 * </pre>
362 public void getKeyboardShortcut (AccessibleEvent e) 639 *
363 { 640 * @param colors an array of Color that specifies the colors to appear in the gradient
364 char mnemonic = _findMnemonic(this.text); 641 * in order of appearance from left/top to right/bottom; The value <code>null</code>
365 if (mnemonic !is '\0') 642 * clears the background gradient; the value <code>null</code> can be used
366 { 643 * inside the array of Color to specify the background color.
367 e.result = "Alt+" + mnemonic; //$NON-NLS-1$ 644 * @param percents an array of integers between 0 and 100 specifying the percent of the width/height
368 } 645 * of the widget at which the color should change; the size of the percents
369 } 646 * array must be one less than the size of the colors array.
370 } ); 647 * @param vertical indicate the direction of the gradient. True is vertical and false is horizontal.
371 648 *
372 accessible.addAccessibleControlListener(new class 649 * @exception DWTException <ul>
373 AccessibleControlAdapter 650 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
374 { 651 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
375 public void getChildAtPoint (AccessibleControlEvent e) 652 * <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li>
376 { 653 * </ul>
377 e.childID = ACC.CHILDID_SELF; 654 *
378 } 655 * @since 3.0
379 656 */
380 public void getLocation (AccessibleControlEvent e) 657 public void setBackground(Color[] colors, int[] percents, bool vertical) {
381 { 658 checkWidget();
382 Rectangle rect = getDisplay().map(getParent(), null, 659 if (colors !is null) {
383 getBounds()); 660 if (percents is null || percents.length !is colors.length - 1) {
384 e.x = rect.x; 661 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
385 e.y = rect.y; 662 }
386 e.width = rect.width; 663 if (getDisplay().getDepth() < 15) {
387 e.height = rect.height; 664 // Don't use gradients on low color displays
388 } 665 colors = [colors[colors.length - 1]];
389 666 percents = null;
390 public void getChildCount (AccessibleControlEvent e) 667 }
391 { 668 for (int i = 0; i < percents.length; i++) {
392 e.detail = 0; 669 if (percents[i] < 0 || percents[i] > 100) {
393 } 670 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
394 671 }
395 public void getRole (AccessibleControlEvent e) 672 if (i > 0 && percents[i] < percents[i-1]) {
396 { 673 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
397 e.detail = ACC.ROLE_LABEL; 674 }
398 } 675 }
399 676 }
400 public void getState (AccessibleControlEvent e) 677
401 { 678 // Are these settings the same as before?
402 e.detail = ACC.STATE_READONLY; 679 final Color background = getBackground();
403 } 680 if (backgroundImage is null) {
404 }); 681 if ((gradientColors !is null) && (colors !is null) &&
405 } 682 (gradientColors.length is colors.length)) {
406 683 bool same = false;
407 void onDispose (DisposeEvent event) 684 for (int i = 0; i < gradientColors.length; i++) {
408 { 685 same = (gradientColors[i] is colors[i]) ||
686 ((gradientColors[i] is null) && (colors[i] is background)) ||
687 ((gradientColors[i] is background) && (colors[i] is null));
688 if (!same) break;
689 }
690 if (same) {
691 for (int i = 0; i < gradientPercents.length; i++) {
692 same = gradientPercents[i] is percents[i];
693 if (!same) break;
694 }
695 }
696 if (same && this.gradientVertical is vertical) return;
697 }
698 } else {
699 backgroundImage = null;
700 }
701 // Store the new settings
702 if (colors is null) {
409 gradientColors = null; 703 gradientColors = null;
410 gradientPercents = null; 704 gradientPercents = null;
411 backgroundImage = null; 705 gradientVertical = false;
412 text = null; 706 } else {
413 image = null; 707 gradientColors = new Color[colors.length];
414 appToolTipText = null; 708 for (int i = 0; i < colors.length; ++i)
415 } 709 gradientColors[i] = (colors[i] !is null) ? colors[i] : background;
416 710 gradientPercents = new int[percents.length];
417 void onMnemonic (TraverseEvent event) 711 for (int i = 0; i < percents.length; ++i)
418 { 712 gradientPercents[i] = percents[i];
419 char mnemonic = _findMnemonic(text); 713 gradientVertical = vertical;
420 if (mnemonic is '\0') 714 }
421 return; 715 // Refresh with the new settings
422 if (CharacterToLower(event.character) !is mnemonic) 716 redraw();
423 return; 717 }
424 Composite control = this.getParent(); 718 /**
425 while (control !is null) 719 * Set the image to be drawn in the background of the label.
426 { 720 *
427 Control[] children = control.getChildren(); 721 * @param image the image to be drawn in the background
428 int index = 0; 722 *
429 while (index < children.length) 723 * @exception DWTException <ul>
430 { 724 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
431 if (children[index] is this) 725 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
432 break; 726 * </ul>
433 index++; 727 */
434 } 728 public void setBackground(Image image) {
435 index++; 729 checkWidget();
436 if (index < children.length) 730 if (image is backgroundImage) return;
437 { 731 if (image !is null) {
438 if (children[index].setFocus())
439 {
440 event.doit = true;
441 event.detail = DWT.TRAVERSE_NONE;
442 }
443 }
444 control = control.getParent();
445 }
446 }
447
448 void onPaint (PaintEvent event)
449 {
450 Rectangle rect = getClientArea();
451 if (rect.width is 0 || rect.height is 0)
452 return;
453
454 bool shortenText = false;
455 String t = text;
456 Image img = image;
457 int availableWidth = Math.max(0, rect.width - 2 * hIndent);
458 Point extent = getTotalSize(img, t);
459 if (extent.x > availableWidth)
460 {
461 img = null;
462 extent = getTotalSize(img, t);
463 if (extent.x > availableWidth)
464 {
465 shortenText = true;
466 }
467 }
468
469 GC gc = event.gc;
470 String[] lines = text is null ? null : splitString(text);
471
472 // shorten the text
473 if (shortenText)
474 {
475 extent.x = 0;
476 for (int i = 0; i < lines.length; i++)
477 {
478 Point e = gc.textExtent(lines[i], DRAW_FLAGS);
479 if (e.x > availableWidth)
480 {
481 lines[i] = shortenText(gc, lines[i], availableWidth);
482 extent.x = Math.max(extent.x,
483 getTotalSize(null, lines[i]).x);
484 }
485 else
486 {
487 extent.x = Math.max(extent.x, e.x);
488 }
489 }
490 if (appToolTipText is null)
491 {
492 super.setToolTipText(text);
493 }
494 }
495 else
496 {
497 super.setToolTipText(appToolTipText);
498 }
499
500 // determine horizontal position
501 int x = rect.x + hIndent;
502 if (alignn is DWT.CENTER)
503 {
504 x = (rect.width - extent.x) / 2;
505 }
506 if (alignn is DWT.RIGHT)
507 {
508 x = rect.width - hIndent - extent.x;
509 }
510
511 // draw a background image behind the text
512 try
513 {
514 if (backgroundImage !is null)
515 {
516 // draw a background image behind the text
517 Rectangle imageRect = backgroundImage.getBounds();
518 // tile image to fill space
519 gc.setBackground(getBackground());
520 gc.fillRectangle(rect);
521 int xPos = 0;
522 while (xPos < rect.width)
523 {
524 int yPos = 0;
525 while (yPos < rect.height)
526 {
527 gc.drawImage(backgroundImage, xPos, yPos);
528 yPos += imageRect.height;
529 }
530 xPos += imageRect.width;
531 }
532 }
533 else if (gradientColors !is null)
534 {
535 // draw a gradient behind the text
536 const Color oldBackground = gc.getBackground();
537 if (gradientColors.length is 1)
538 {
539 if (gradientColors[0] !is null)
540 gc.setBackground(gradientColors[0]);
541 gc.fillRectangle(0, 0, rect.width, rect.height);
542 }
543 else
544 {
545 const Color oldForeground = gc.getForeground();
546 Color lastColor = gradientColors[0];
547 if (lastColor is null)
548 lastColor = oldBackground;
549 int pos = 0;
550 for (int i = 0; i < gradientPercents.length; ++i)
551 {
552 gc.setForeground(lastColor);
553 lastColor = gradientColors[i + 1];
554 if (lastColor is null)
555 lastColor = oldBackground;
556 gc.setBackground(lastColor);
557 if (gradientVertical)
558 {
559 const int
560 gradientHeight = (gradientPercents[i] * rect.height / 100) - pos;
561 gc.fillGradientRectangle(0, pos, rect.width,
562 gradientHeight, true);
563 pos += gradientHeight;
564 }
565 else
566 {
567 const int
568 gradientWidth = (gradientPercents[i] * rect.width / 100) - pos;
569 gc.fillGradientRectangle(pos, 0, gradientWidth,
570 rect.height, false);
571 pos += gradientWidth;
572 }
573 }
574 if (gradientVertical && pos < rect.height)
575 {
576 gc.setBackground(getBackground());
577 gc.fillRectangle(0, pos, rect.width, rect.height - pos);
578 }
579 if (!gradientVertical && pos < rect.width)
580 {
581 gc.setBackground(getBackground());
582 gc.fillRectangle(pos, 0, rect.width - pos, rect.height);
583 }
584 gc.setForeground(oldForeground);
585 }
586 gc.setBackground(oldBackground);
587 }
588 else
589 {
590 if (background !is null || (getStyle() & DWT.DOUBLE_BUFFERED) is 0)
591 {
592 gc.setBackground(getBackground());
593 gc.fillRectangle(rect);
594 }
595 }
596 }
597 catch (DWTException e)
598 {
599 if ((getStyle() & DWT.DOUBLE_BUFFERED) is 0)
600 {
601 gc.setBackground(getBackground());
602 gc.fillRectangle(rect);
603 }
604 }
605
606 // draw border
607 int style = getStyle();
608 if ((style & DWT.SHADOW_IN) !is 0 || (style & DWT.SHADOW_OUT) !is 0)
609 {
610 paintBorder(gc, rect);
611 }
612
613 // draw the image
614 if (img !is null)
615 {
616 Rectangle imageRect = img.getBounds();
617 gc.drawImage(img, 0, 0, imageRect.width, imageRect.height, x,
618 (rect.height - imageRect.height) / 2, imageRect.width,
619 imageRect.height);
620 x += imageRect.width + GAP;
621 extent.x -= imageRect.width + GAP;
622 }
623 // draw the text
624 if (lines !is null)
625 {
626 int lineHeight = gc.getFontMetrics().getHeight();
627 int textHeight = lines.length * lineHeight;
628 int lineY = Math.max(vIndent,
629 rect.y + (rect.height - textHeight) / 2);
630 gc.setForeground(getForeground());
631 for (int i = 0; i < lines.length; i++)
632 {
633 int lineX = x;
634 if (lines.length > 1)
635 {
636 if (alignn is DWT.CENTER)
637 {
638 int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
639 lineX = x + Math.max(0, (extent.x - lineWidth) / 2);
640 }
641 if (alignn is DWT.RIGHT)
642 {
643 int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
644 lineX = Math.max(x,
645 rect.x + rect.width - hIndent - lineWidth);
646 }
647 }
648 gc.drawText(lines[i], lineX, lineY, DRAW_FLAGS);
649 lineY += lineHeight;
650 }
651 }
652 }
653
654 /**
655 * Paint the Label's border.
656 */
657 private void paintBorder (GC gc, Rectangle r)
658 {
659 Display disp = getDisplay();
660
661 Color c1 = null;
662 Color c2 = null;
663
664 int style = getStyle();
665 if ((style & DWT.SHADOW_IN) !is 0)
666 {
667 c1 = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
668 c2 = disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
669 }
670 if ((style & DWT.SHADOW_OUT) !is 0)
671 {
672 c1 = disp.getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW);
673 c2 = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
674 }
675
676 if (c1 !is null && c2 !is null)
677 {
678 gc.setLineWidth(1);
679 drawBevelRect(gc, r.x, r.y, r.width - 1, r.height - 1, c1, c2);
680 }
681 }
682
683 /**
684 * Set the alignnment of the CLabel.
685 * Use the values LEFT, CENTER and RIGHT to alignn image and text within the available space.
686 *
687 * @param alignn the alignnment style of LEFT, RIGHT or CENTER
688 *
689 * @exception DWTException <ul>
690 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
691 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
692 * <li>ERROR_INVALID_ARGUMENT - if the value of alignn is not one of DWT.LEFT, DWT.RIGHT or DWT.CENTER</li>
693 * </ul>
694 */
695 public void setAlignment (int alignn)
696 {
697 checkWidget();
698 if (alignn !is DWT.LEFT && alignn !is DWT.RIGHT && alignn !is DWT.CENTER)
699 {
700 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
701 }
702 if (this.alignn !is alignn)
703 {
704 this.alignn = alignn;
705 redraw();
706 }
707 }
708
709 public void setBackground (Color color)
710 {
711 super.setBackground(color);
712 // Are these settings the same as before?
713 if (backgroundImage is null && gradientColors is null && gradientPercents is null)
714 {
715 if (color is null)
716 {
717 if (background is null)
718 return;
719 }
720 else
721 {
722 if (color.opEquals(background))
723 return;
724 }
725 }
726 background = color;
727 backgroundImage = null;
728 gradientColors = null; 732 gradientColors = null;
729 gradientPercents = null; 733 gradientPercents = null;
734 }
735 backgroundImage = image;
736 redraw();
737
738 }
739 public override void setFont(Font font) {
740 super.setFont(font);
741 redraw();
742 }
743 /**
744 * Set the label's Image.
745 * The value <code>null</code> clears it.
746 *
747 * @param image the image to be displayed in the label or null
748 *
749 * @exception DWTException <ul>
750 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
751 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
752 * </ul>
753 */
754 public void setImage(Image image) {
755 checkWidget();
756 if (image !is this.image) {
757 this.image = image;
730 redraw(); 758 redraw();
731 } 759 }
732 760 }
733 /** 761 /**
734 * Specify a gradient of colours to be drawn in the background of the CLabel. 762 * Set the label's text.
735 * <p>For example, to draw a gradient that varies from dark blue to blue and then to 763 * The value <code>null</code> clears it.
736 * white and stays white for the right half of the label, use the following call 764 *
737 * to setBackground:</p> 765 * @param text the text to be displayed in the label or null
738 * <pre> 766 *
739 * clabel.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE), 767 * @exception DWTException <ul>
740 * display.getSystemColor(DWT.COLOR_BLUE), 768 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
741 * display.getSystemColor(DWT.COLOR_WHITE), 769 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
742 * display.getSystemColor(DWT.COLOR_WHITE)}, 770 * </ul>
743 * new int[] {25, 50, 100}); 771 */
744 * </pre> 772 public void setText(String text) {
745 * 773 checkWidget();
746 * @param colors an array of Color that specifies the colors to appear in the gradient 774 if (text is null) text = ""; //$NON-NLS-1$
747 * in order of appearance from left to right; The value <code>null</code> 775 if ( text !=/*eq*/ this.text) {
748 * clears the background gradient; the value <code>null</code> can be used 776 this.text = text;
749 * inside the array of Color to specify the background color.
750 * @param percents an array of integers between 0 and 100 specifying the percent of the width
751 * of the widget at which the color should change; the size of the percents
752 * array must be one less than the size of the colors array.
753 *
754 * @exception DWTException <ul>
755 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
756 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
757 * <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li>
758 * </ul>
759 */
760 public void setBackground (Color[] colors, int[] percents)
761 {
762 setBackground(colors, percents, false);
763 }
764
765 /**
766 * Specify a gradient of colours to be drawn in the background of the CLabel.
767 * <p>For example, to draw a gradient that varies from dark blue to white in the vertical,
768 * direction use the following call
769 * to setBackground:</p>
770 * <pre>
771 * clabel.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
772 * display.getSystemColor(DWT.COLOR_WHITE)},
773 * new int[] {100}, true);
774 * </pre>
775 *
776 * @param colors an array of Color that specifies the colors to appear in the gradient
777 * in order of appearance from left/top to right/bottom; The value <code>null</code>
778 * clears the background gradient; the value <code>null</code> can be used
779 * inside the array of Color to specify the background color.
780 * @param percents an array of integers between 0 and 100 specifying the percent of the width/height
781 * of the widget at which the color should change; the size of the percents
782 * array must be one less than the size of the colors array.
783 * @param vertical indicate the direction of the gradient. True is vertical and false is horizontal.
784 *
785 * @exception DWTException <ul>
786 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
787 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
788 * <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li>
789 * </ul>
790 *
791 * @since 3.0
792 */
793 public void setBackground (Color[] colors, int[] percents, bool vertical)
794 {
795 checkWidget();
796 if (colors !is null)
797 {
798 if (percents is null || percents.length !is colors.length - 1)
799 {
800 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
801 }
802 if (getDisplay().getDepth() < 15)
803 {
804 // Don't use gradients on low color displays
805 colors = new Color[][colors[colors.length - 1]];
806 percents = new int[][];
807 }
808 for (int i = 0; i < percents.length; i++)
809 {
810 if (percents[i] < 0 || percents[i] > 100)
811 {
812 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
813 }
814 if (i > 0 && percents[i] < percents[i - 1])
815 {
816 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
817 }
818 }
819 }
820
821 // Are these settings the same as before?
822 const Color background = getBackground();
823 if (backgroundImage is null)
824 {
825 if ((gradientColors !is null) && (colors !is null) && (gradientColors.length is colors.length))
826 {
827 bool same = false;
828 for (int i = 0; i < gradientColors.length; i++)
829 {
830 same = (gradientColors[i] is colors[i]) || ((gradientColors[i] is null) && (colors[i] is background)) || ((gradientColors[i] is background) && (colors[i] is null));
831 if (!same)
832 break;
833 }
834 if (same)
835 {
836 for (int i = 0; i < gradientPercents.length; i++)
837 {
838 same = gradientPercents[i] is percents[i];
839 if (!same)
840 break;
841 }
842 }
843 if (same && this.gradientVertical is vertical)
844 return;
845 }
846 }
847 else
848 {
849 backgroundImage = null;
850 }
851 // Store the new settings
852 if (colors is null)
853 {
854 gradientColors = null;
855 gradientPercents = null;
856 gradientVertical = false;
857 }
858 else
859 {
860 gradientColors = new Color[colors.length];
861 for (int i = 0; i < colors.length; ++i)
862 gradientColors[i] = (colors[i] !is null) ? colors[i] : background;
863 gradientPercents = new int[percents.length];
864 for (int i = 0; i < percents.length; ++i)
865 gradientPercents[i] = percents[i];
866 gradientVertical = vertical;
867 }
868 // Refresh with the new settings
869 redraw(); 777 redraw();
870 } 778 }
871 779 }
872 /** 780 public override void setToolTipText (String string) {
873 * Set the image to be drawn in the background of the label. 781 super.setToolTipText (string);
874 * 782 appToolTipText = super.getToolTipText();
875 * @param image the image to be drawn in the background 783 }
876 * 784 /**
877 * @exception DWTException <ul> 785 * Shorten the given text <code>t</code> so that its length doesn't exceed
878 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 786 * the given width. The default implementation replaces characters in the
879 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 787 * center of the original string with an ellipsis ("...").
880 * </ul> 788 * Override if you need a different strategy.
881 */ 789 *
882 public void setBackground (Image image) 790 * @param gc the gc to use for text measurement
883 { 791 * @param t the text to shorten
884 checkWidget(); 792 * @param width the width to shorten the text to, in pixels
885 if (image is backgroundImage) 793 * @return the shortened text
886 return; 794 */
887 if (image !is null) 795 protected String shortenText(GC gc, String t, int width) {
888 { 796 if (t is null) return null;
889 gradientColors = null; 797 int w = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x;
890 gradientPercents = null; 798 if (width<=w) return t;
891 } 799 int l = t.length;
892 backgroundImage = image; 800 int max = l/2;
893 redraw(); 801 int min = 0;
894 802 int mid = (max+min)/2 - 1;
895 } 803 if (mid <= 0) return t;
896 804 TextLayout layout = new TextLayout (getDisplay());
897 public void setFont (Font font) 805 layout.setText(t);
898 { 806 mid = validateOffset(layout, mid);
899 super.setFont(font); 807 while (min < mid && mid < max) {
900 redraw(); 808 String s1 = t[0 .. mid].dup;
901 } 809 String s2 = t.substring(validateOffset(layout, l-mid), l);
902 810 int l1 = gc.textExtent(s1, DRAW_FLAGS).x;
903 /** 811 int l2 = gc.textExtent(s2, DRAW_FLAGS).x;
904 * Set the label's Image. 812 if (l1+w+l2 > width) {
905 * The value <code>null</code> clears it. 813 max = mid;
906 * 814 mid = validateOffset(layout, (max+min)/2);
907 * @param image the image to be displayed in the label or null 815 } else if (l1+w+l2 < width) {
908 * 816 min = mid;
909 * @exception DWTException <ul> 817 mid = validateOffset(layout, (max+min)/2);
910 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 818 } else {
911 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 819 min = max;
912 * </ul> 820 }
913 */ 821 }
914 public void setImage (Image image) 822 String result = mid is 0 ? t : t.substring(0, mid) ~ ELLIPSIS ~ t.substring(validateOffset(layout, l-mid), l);
915 { 823 layout.dispose();
916 checkWidget(); 824 return result;
917 if (image !is this.image) 825 }
918 { 826 int validateOffset(TextLayout layout, int offset) {
919 this.image = image; 827 int nextOffset = layout.getNextOffset(offset, DWT.MOVEMENT_CLUSTER);
920 redraw(); 828 if (nextOffset !is offset) return layout.getPreviousOffset(nextOffset, DWT.MOVEMENT_CLUSTER);
921 } 829 return offset;
922 } 830 }
923 831 private String[] splitString(String text) {
924 /** 832 String[] lines = new String[1];
925 * Set the label's text. 833 int start = 0, pos;
926 * The value <code>null</code> clears it. 834 do {
927 * 835 pos = tango.text.Util.locate( text, '\n', start);
928 * @param text the text to be displayed in the label or null 836 if (pos is text.length ) {
929 * 837 lines[lines.length - 1] = text[start .. $ ];
930 * @exception DWTException <ul> 838 } else {
931 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 839 bool crlf = (pos > 0) && (text[ pos - 1 ] is '\r');
932 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 840 lines[lines.length - 1] = text[ start .. pos - (crlf ? 1 : 0)];
933 * </ul> 841 start = pos + 1;
934 */ 842 String[] newLines = new String[lines.length+1];
935 public void setText (String text) 843 System.arraycopy(lines, 0, newLines, 0, lines.length);
936 { 844 lines = newLines;
937 checkWidget(); 845 }
938 if (text is null) 846 } while (pos !is text.length);
939 text = ""; //$NON-NLS-1$ 847 return lines;
940 if (!text.opEquals(this.text)) 848 }
941 { 849 }
942 this.text = text;
943 redraw();
944 }
945 }
946
947 public void setToolTipText (String String)
948 {
949 super.setToolTipText(String);
950 appToolTipText = super.getToolTipText();
951 }
952
953 /**
954 * Shorten the given text <code>t</code> so that its length doesn't exceed
955 * the given width. The default implementation replaces characters in the
956 * center of the original String with an ellipsis ("...").
957 * Override if you need a different strategy.
958 *
959 * @param gc the gc to use for text measurement
960 * @param t the text to shorten
961 * @param width the width to shorten the text to, in pixels
962 * @return the shortened text
963 */
964 protected String shortenText (GC gc, String t, int width)
965 {
966 if (t is null)
967 return null;
968 int w = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x;
969 if (width <= w)
970 return t;
971 int l = t.length();
972 int max = l / 2;
973 int min = 0;
974 int mid = (max + min) / 2 - 1;
975 if (mid <= 0)
976 return t;
977 TextLayout layout = new TextLayout(getDisplay());
978 layout.setText(t);
979 mid = validateOffset(layout, mid);
980 while (min < mid && mid < max)
981 {
982 String s1 = t.substring(0, mid);
983 String s2 = t.substring(validateOffset(layout, l - mid), l);
984 int l1 = gc.textExtent(s1, DRAW_FLAGS).x;
985 int l2 = gc.textExtent(s2, DRAW_FLAGS).x;
986 if (l1 + w + l2 > width)
987 {
988 max = mid;
989 mid = validateOffset(layout, (max + min) / 2);
990 }
991 else if (l1 + w + l2 < width)
992 {
993 min = mid;
994 mid = validateOffset(layout, (max + min) / 2);
995 }
996 else
997 {
998 min = max;
999 }
1000 }
1001 String
1002 result = mid is 0 ? t : t.substring(0, mid) + ELLIPSIS + t.substring(
1003 validateOffset(layout, l - mid), l);
1004 layout.dispose();
1005 return result;
1006 }
1007
1008 int validateOffset (TextLayout layout, int offset)
1009 {
1010 int nextOffset = layout.getNextOffset(offset, DWT.MOVEMENT_CLUSTER);
1011 if (nextOffset !is offset)
1012 return layout.getPreviousOffset(nextOffset, DWT.MOVEMENT_CLUSTER);
1013 return offset;
1014 }
1015
1016 private String[] splitString (String text)
1017 {
1018 String[] lines = new String[1];
1019 int start = 0, pos;
1020 do
1021 {
1022 pos = text.indexOf('\n', start);
1023 if (pos is -1)
1024 {
1025 lines[lines.length - 1] = text.substring(start);
1026 }
1027 else
1028 {
1029 bool crlf = (pos > 0) && (text.charAt(pos - 1) is '\r');
1030 lines[lines.length - 1] = text.substring(start,
1031 pos - (crlf ? 1 : 0));
1032 start = pos + 1;
1033 String[] newLines = new String[lines.length + 1];
1034 System.arraycopy(lines, 0, newLines, 0, lines.length);
1035 lines = newLines;
1036 }
1037 } while (pos !is -1);
1038 return lines;
1039 }
1040 }