Mercurial > projects > dwt-mac
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 } |