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