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