| /******************************************************************************* |
| * Copyright (c) 2000, 2012 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.custom; |
| |
| import org.eclipse.swt.*; |
| import org.eclipse.swt.widgets.*; |
| import org.eclipse.swt.graphics.*; |
| import org.eclipse.swt.events.*; |
| import org.eclipse.swt.accessibility.*; |
| |
| /** |
| * A Label which supports aligned text and/or an image and different border styles. |
| * <p> |
| * If there is not enough space a CLabel uses the following strategy to fit the |
| * information into the available space: |
| * <pre> |
| * ignores the indent in left align mode |
| * ignores the image and the gap |
| * shortens the text by replacing the center portion of the label with an ellipsis |
| * shortens the text by removing the center portion of the label |
| * </pre> |
| * <p> |
| * <dl> |
| * <dt><b>Styles:</b> |
| * <dd>LEFT, RIGHT, CENTER, SHADOW_IN, SHADOW_OUT, SHADOW_NONE</dd> |
| * <dt><b>Events:</b> |
| * <dd></dd> |
| * </dl> |
| * |
| * </p><p> |
| * This class may be subclassed for the purpose of overriding the default string |
| * shortening algorithm that is implemented in method <code>shortenText()</code>. |
| * </p> |
| * |
| * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: CustomControlExample</a> |
| * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> |
| * @see CLabel#shortenText(GC, String, int) |
| */ |
| public class CLabel extends Canvas { |
| |
| /** Gap between icon and text */ |
| private static final int GAP = 5; |
| /** Left and right margins */ |
| private static final int DEFAULT_MARGIN = 3; |
| /** a string inserted in the middle of text that has been shortened */ |
| private static final String ELLIPSIS = "..."; //$NON-NLS-1$ // could use the ellipsis glyph on some platforms "\u2026" |
| /** the alignment. Either CENTER, RIGHT, LEFT. Default is LEFT*/ |
| private int align = SWT.LEFT; |
| private int leftMargin = DEFAULT_MARGIN; |
| private int topMargin = DEFAULT_MARGIN; |
| private int rightMargin = DEFAULT_MARGIN; |
| private int bottomMargin = DEFAULT_MARGIN; |
| /** the current text */ |
| private String text; |
| /** the current icon */ |
| private Image image; |
| // The tooltip is used for two purposes - the application can set |
| // a tooltip or the tooltip can be used to display the full text when the |
| // the text has been truncated due to the label being too short. |
| // The appToolTip stores the tooltip set by the application. Control.tooltiptext |
| // contains whatever tooltip is currently being displayed. |
| private String appToolTipText; |
| private boolean ignoreDispose; |
| |
| private Image backgroundImage; |
| private Color[] gradientColors; |
| private int[] gradientPercents; |
| private boolean gradientVertical; |
| private Color background; |
| |
| private static int DRAW_FLAGS = SWT.DRAW_MNEMONIC | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT | SWT.DRAW_DELIMITER; |
| |
| /** |
| * Constructs a new instance of this class given its parent |
| * and a style value describing its behavior and appearance. |
| * <p> |
| * The style value is either one of the style constants defined in |
| * class <code>SWT</code> which is applicable to instances of this |
| * class, or must be built by <em>bitwise OR</em>'ing together |
| * (that is, using the <code>int</code> "|" operator) two or more |
| * of those <code>SWT</code> style constants. The class description |
| * lists the style constants that are applicable to the class. |
| * Style bits are also inherited from superclasses. |
| * </p> |
| * |
| * @param parent a widget which will be the parent of the new instance (cannot be null) |
| * @param style the style of widget to construct |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> |
| * </ul> |
| * |
| * @see SWT#LEFT |
| * @see SWT#RIGHT |
| * @see SWT#CENTER |
| * @see SWT#SHADOW_IN |
| * @see SWT#SHADOW_OUT |
| * @see SWT#SHADOW_NONE |
| * @see #getStyle() |
| */ |
| public CLabel(Composite parent, int style) { |
| super(parent, checkStyle(style)); |
| if ((style & (SWT.CENTER | SWT.RIGHT)) == 0) style |= SWT.LEFT; |
| if ((style & SWT.CENTER) != 0) align = SWT.CENTER; |
| if ((style & SWT.RIGHT) != 0) align = SWT.RIGHT; |
| if ((style & SWT.LEFT) != 0) align = SWT.LEFT; |
| |
| addPaintListener(new PaintListener() { |
| public void paintControl(PaintEvent event) { |
| onPaint(event); |
| } |
| }); |
| |
| addTraverseListener(new TraverseListener() { |
| public void keyTraversed(TraverseEvent event) { |
| if (event.detail == SWT.TRAVERSE_MNEMONIC) { |
| onMnemonic(event); |
| } |
| } |
| }); |
| |
| addListener(SWT.Dispose, new Listener() { |
| public void handleEvent(Event event) { |
| onDispose(event); |
| } |
| }); |
| |
| initAccessible(); |
| |
| } |
| /** |
| * Check the style bits to ensure that no invalid styles are applied. |
| */ |
| private static int checkStyle (int style) { |
| if ((style & SWT.BORDER) != 0) style |= SWT.SHADOW_IN; |
| int mask = SWT.SHADOW_IN | SWT.SHADOW_OUT | SWT.SHADOW_NONE | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; |
| style = style & mask; |
| return style |= SWT.NO_FOCUS | SWT.DOUBLE_BUFFERED; |
| } |
| |
| @Override |
| public Point computeSize(int wHint, int hHint, boolean changed) { |
| checkWidget(); |
| Point e = getTotalSize(image, text); |
| if (wHint == SWT.DEFAULT){ |
| e.x += leftMargin + rightMargin; |
| } else { |
| e.x = wHint; |
| } |
| if (hHint == SWT.DEFAULT) { |
| e.y += topMargin + bottomMargin; |
| } else { |
| e.y = hHint; |
| } |
| return e; |
| } |
| /** |
| * Draw a rectangle in the given colors. |
| */ |
| private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topleft, Color bottomright) { |
| gc.setForeground(bottomright); |
| gc.drawLine(x+w, y, x+w, y+h); |
| gc.drawLine(x, y+h, x+w, y+h); |
| |
| gc.setForeground(topleft); |
| gc.drawLine(x, y, x+w-1, y); |
| gc.drawLine(x, y, x, y+h-1); |
| } |
| /* |
| * Return the lowercase of the first non-'&' character following |
| * an '&' character in the given string. If there are no '&' |
| * characters in the given string, return '\0'. |
| */ |
| char _findMnemonic (String string) { |
| if (string == null) return '\0'; |
| int index = 0; |
| int length = string.length (); |
| do { |
| while (index < length && string.charAt (index) != '&') index++; |
| if (++index >= length) return '\0'; |
| if (string.charAt (index) != '&') return Character.toLowerCase (string.charAt (index)); |
| index++; |
| } while (index < length); |
| return '\0'; |
| } |
| /** |
| * Returns the horizontal alignment. |
| * The alignment style (LEFT, CENTER or RIGHT) is returned. |
| * |
| * @return SWT.LEFT, SWT.RIGHT or SWT.CENTER |
| */ |
| public int getAlignment() { |
| //checkWidget(); |
| return align; |
| } |
| /** |
| * Return the CLabel's bottom margin. |
| * |
| * @return the bottom margin of the label |
| * |
| * @since 3.6 |
| */ |
| public int getBottomMargin() { |
| //checkWidget(); |
| return bottomMargin; |
| } |
| /** |
| * Return the CLabel's image or <code>null</code>. |
| * |
| * @return the image of the label or null |
| */ |
| public Image getImage() { |
| //checkWidget(); |
| return image; |
| } |
| /** |
| * Return the CLabel's left margin. |
| * |
| * @return the left margin of the label |
| * |
| * @since 3.6 |
| */ |
| public int getLeftMargin() { |
| //checkWidget(); |
| return leftMargin; |
| } |
| /** |
| * Return the CLabel's right margin. |
| * |
| * @return the right margin of the label |
| * |
| * @since 3.6 |
| */ |
| public int getRightMargin() { |
| //checkWidget(); |
| return rightMargin; |
| } |
| /** |
| * Compute the minimum size. |
| */ |
| private Point getTotalSize(Image image, String text) { |
| Point size = new Point(0, 0); |
| |
| if (image != null) { |
| Rectangle r = image.getBounds(); |
| size.x += r.width; |
| size.y += r.height; |
| } |
| |
| GC gc = new GC(this); |
| if (text != null && text.length() > 0) { |
| Point e = gc.textExtent(text, DRAW_FLAGS); |
| size.x += e.x; |
| size.y = Math.max(size.y, e.y); |
| if (image != null) size.x += GAP; |
| } else { |
| size.y = Math.max(size.y, gc.getFontMetrics().getHeight()); |
| } |
| gc.dispose(); |
| |
| return size; |
| } |
| @Override |
| public int getStyle () { |
| int style = super.getStyle(); |
| switch (align) { |
| case SWT.RIGHT: style |= SWT.RIGHT; break; |
| case SWT.CENTER: style |= SWT.CENTER; break; |
| case SWT.LEFT: style |= SWT.LEFT; break; |
| } |
| return style; |
| } |
| |
| /** |
| * Return the Label's text. |
| * |
| * @return the text of the label or null |
| */ |
| public String getText() { |
| //checkWidget(); |
| return text; |
| } |
| @Override |
| public String getToolTipText () { |
| checkWidget(); |
| return appToolTipText; |
| } |
| /** |
| * Return the CLabel's top margin. |
| * |
| * @return the top margin of the label |
| * |
| * @since 3.6 |
| */ |
| public int getTopMargin() { |
| //checkWidget(); |
| return topMargin; |
| } |
| private void initAccessible() { |
| Accessible accessible = getAccessible(); |
| accessible.addAccessibleListener(new AccessibleAdapter() { |
| @Override |
| public void getName(AccessibleEvent e) { |
| e.result = getText(); |
| } |
| |
| @Override |
| public void getHelp(AccessibleEvent e) { |
| e.result = getToolTipText(); |
| } |
| |
| @Override |
| public void getKeyboardShortcut(AccessibleEvent e) { |
| char mnemonic = _findMnemonic(CLabel.this.text); |
| if (mnemonic != '\0') { |
| e.result = "Alt+"+mnemonic; //$NON-NLS-1$ |
| } |
| } |
| }); |
| |
| accessible.addAccessibleControlListener(new AccessibleControlAdapter() { |
| @Override |
| public void getChildAtPoint(AccessibleControlEvent e) { |
| e.childID = ACC.CHILDID_SELF; |
| } |
| |
| @Override |
| public void getLocation(AccessibleControlEvent e) { |
| Rectangle rect = getDisplay().map(getParent(), null, getBounds()); |
| e.x = rect.x; |
| e.y = rect.y; |
| e.width = rect.width; |
| e.height = rect.height; |
| } |
| |
| @Override |
| public void getChildCount(AccessibleControlEvent e) { |
| e.detail = 0; |
| } |
| |
| @Override |
| public void getRole(AccessibleControlEvent e) { |
| e.detail = ACC.ROLE_LABEL; |
| } |
| |
| @Override |
| public void getState(AccessibleControlEvent e) { |
| e.detail = ACC.STATE_READONLY; |
| } |
| }); |
| } |
| void onDispose(Event event) { |
| /* make this handler run after other dispose listeners */ |
| if (ignoreDispose) { |
| ignoreDispose = false; |
| return; |
| } |
| ignoreDispose = true; |
| notifyListeners (event.type, event); |
| event.type = SWT.NONE; |
| |
| gradientColors = null; |
| gradientPercents = null; |
| backgroundImage = null; |
| text = null; |
| image = null; |
| appToolTipText = null; |
| } |
| void onMnemonic(TraverseEvent event) { |
| char mnemonic = _findMnemonic(text); |
| if (mnemonic == '\0') return; |
| if (Character.toLowerCase(event.character) != mnemonic) return; |
| Composite control = this.getParent(); |
| while (control != null) { |
| Control [] children = control.getChildren(); |
| int index = 0; |
| while (index < children.length) { |
| if (children [index] == this) break; |
| index++; |
| } |
| index++; |
| if (index < children.length) { |
| if (children [index].setFocus ()) { |
| event.doit = true; |
| event.detail = SWT.TRAVERSE_NONE; |
| } |
| } |
| control = control.getParent(); |
| } |
| } |
| |
| void onPaint(PaintEvent event) { |
| Rectangle rect = getClientArea(); |
| if (rect.width == 0 || rect.height == 0) return; |
| |
| boolean shortenText = false; |
| String t = text; |
| Image img = image; |
| int availableWidth = Math.max(0, rect.width - (leftMargin + rightMargin)); |
| Point extent = getTotalSize(img, t); |
| if (extent.x > availableWidth) { |
| img = null; |
| extent = getTotalSize(img, t); |
| if (extent.x > availableWidth) { |
| shortenText = true; |
| } |
| } |
| |
| GC gc = event.gc; |
| String[] lines = text == null ? null : splitString(text); |
| |
| // shorten the text |
| if (shortenText) { |
| extent.x = 0; |
| for(int i = 0; i < lines.length; i++) { |
| Point e = gc.textExtent(lines[i], DRAW_FLAGS); |
| if (e.x > availableWidth) { |
| lines[i] = shortenText(gc, lines[i], availableWidth); |
| extent.x = Math.max(extent.x, getTotalSize(null, lines[i]).x); |
| } else { |
| extent.x = Math.max(extent.x, e.x); |
| } |
| } |
| if (appToolTipText == null) { |
| super.setToolTipText(text); |
| } |
| } else { |
| super.setToolTipText(appToolTipText); |
| } |
| |
| // determine horizontal position |
| int x = rect.x + leftMargin; |
| if (align == SWT.CENTER) { |
| x = (rect.width - extent.x)/2; |
| } |
| if (align == SWT.RIGHT) { |
| x = rect.width - rightMargin - extent.x; |
| } |
| |
| // draw a background image behind the text |
| try { |
| if (backgroundImage != null) { |
| // draw a background image behind the text |
| Rectangle imageRect = backgroundImage.getBounds(); |
| // tile image to fill space |
| gc.setBackground(getBackground()); |
| gc.fillRectangle(rect); |
| int xPos = 0; |
| while (xPos < rect.width) { |
| int yPos = 0; |
| while (yPos < rect.height) { |
| gc.drawImage(backgroundImage, xPos, yPos); |
| yPos += imageRect.height; |
| } |
| xPos += imageRect.width; |
| } |
| } else if (gradientColors != null) { |
| // draw a gradient behind the text |
| final Color oldBackground = gc.getBackground(); |
| if (gradientColors.length == 1) { |
| if (gradientColors[0] != null) gc.setBackground(gradientColors[0]); |
| gc.fillRectangle(0, 0, rect.width, rect.height); |
| } else { |
| final Color oldForeground = gc.getForeground(); |
| Color lastColor = gradientColors[0]; |
| if (lastColor == null) lastColor = oldBackground; |
| int pos = 0; |
| for (int i = 0; i < gradientPercents.length; ++i) { |
| gc.setForeground(lastColor); |
| lastColor = gradientColors[i + 1]; |
| if (lastColor == null) lastColor = oldBackground; |
| gc.setBackground(lastColor); |
| if (gradientVertical) { |
| final int gradientHeight = (gradientPercents[i] * rect.height / 100) - pos; |
| gc.fillGradientRectangle(0, pos, rect.width, gradientHeight, true); |
| pos += gradientHeight; |
| } else { |
| final int gradientWidth = (gradientPercents[i] * rect.width / 100) - pos; |
| gc.fillGradientRectangle(pos, 0, gradientWidth, rect.height, false); |
| pos += gradientWidth; |
| } |
| } |
| if (gradientVertical && pos < rect.height) { |
| gc.setBackground(getBackground()); |
| gc.fillRectangle(0, pos, rect.width, rect.height - pos); |
| } |
| if (!gradientVertical && pos < rect.width) { |
| gc.setBackground(getBackground()); |
| gc.fillRectangle(pos, 0, rect.width - pos, rect.height); |
| } |
| gc.setForeground(oldForeground); |
| } |
| gc.setBackground(oldBackground); |
| } else { |
| if (background != null || (getStyle() & SWT.DOUBLE_BUFFERED) == 0) { |
| gc.setBackground(getBackground()); |
| gc.fillRectangle(rect); |
| } |
| } |
| } catch (SWTException e) { |
| if ((getStyle() & SWT.DOUBLE_BUFFERED) == 0) { |
| gc.setBackground(getBackground()); |
| gc.fillRectangle(rect); |
| } |
| } |
| |
| // draw border |
| int style = getStyle(); |
| if ((style & SWT.SHADOW_IN) != 0 || (style & SWT.SHADOW_OUT) != 0) { |
| paintBorder(gc, rect); |
| } |
| |
| /* |
| * Compute text height and image height. If image height is more than |
| * the text height, draw image starting from top margin. Else draw text |
| * starting from top margin. |
| */ |
| Rectangle imageRect = null; |
| int lineHeight = 0, textHeight = 0, imageHeight = 0; |
| |
| if (img != null) { |
| imageRect = img.getBounds(); |
| imageHeight = imageRect.height; |
| } |
| if (lines != null) { |
| lineHeight = gc.getFontMetrics().getHeight(); |
| textHeight = lines.length * lineHeight; |
| } |
| |
| int imageY = 0, midPoint = 0, lineY = 0; |
| if (imageHeight > textHeight ) { |
| if (topMargin == DEFAULT_MARGIN && bottomMargin == DEFAULT_MARGIN) imageY = rect.y + (rect.height - imageHeight) / 2; |
| else imageY = topMargin; |
| midPoint = imageY + imageHeight/2; |
| lineY = midPoint - textHeight / 2; |
| } |
| else { |
| if (topMargin == DEFAULT_MARGIN && bottomMargin == DEFAULT_MARGIN) lineY = rect.y + (rect.height - textHeight) / 2; |
| else lineY = topMargin; |
| midPoint = lineY + textHeight/2; |
| imageY = midPoint - imageHeight / 2; |
| } |
| |
| // draw the image |
| if (img != null) { |
| gc.drawImage(img, 0, 0, imageRect.width, imageHeight, |
| x, imageY, imageRect.width, imageHeight); |
| x += imageRect.width + GAP; |
| extent.x -= imageRect.width + GAP; |
| } |
| |
| // draw the text |
| if (lines != null) { |
| gc.setForeground(getForeground()); |
| for (int i = 0; i < lines.length; i++) { |
| int lineX = x; |
| if (lines.length > 1) { |
| if (align == SWT.CENTER) { |
| int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x; |
| lineX = x + Math.max(0, (extent.x - lineWidth) / 2); |
| } |
| if (align == SWT.RIGHT) { |
| int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x; |
| lineX = Math.max(x, rect.x + rect.width - rightMargin - lineWidth); |
| } |
| } |
| gc.drawText(lines[i], lineX, lineY, DRAW_FLAGS); |
| lineY += lineHeight; |
| } |
| } |
| } |
| /** |
| * Paint the Label's border. |
| */ |
| private void paintBorder(GC gc, Rectangle r) { |
| Display disp= getDisplay(); |
| |
| Color c1 = null; |
| Color c2 = null; |
| |
| int style = getStyle(); |
| if ((style & SWT.SHADOW_IN) != 0) { |
| c1 = disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); |
| c2 = disp.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); |
| } |
| if ((style & SWT.SHADOW_OUT) != 0) { |
| c1 = disp.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW); |
| c2 = disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); |
| } |
| |
| if (c1 != null && c2 != null) { |
| gc.setLineWidth(1); |
| drawBevelRect(gc, r.x, r.y, r.width-1, r.height-1, c1, c2); |
| } |
| } |
| /** |
| * Set the horizontal alignment of the CLabel. |
| * Use the values LEFT, CENTER and RIGHT to align image and text within the available space. |
| * |
| * @param align the alignment style of LEFT, RIGHT or CENTER |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * <li>ERROR_INVALID_ARGUMENT - if the value of align is not one of SWT.LEFT, SWT.RIGHT or SWT.CENTER</li> |
| * </ul> |
| */ |
| public void setAlignment(int align) { |
| checkWidget(); |
| if (align != SWT.LEFT && align != SWT.RIGHT && align != SWT.CENTER) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| if (this.align != align) { |
| this.align = align; |
| redraw(); |
| } |
| } |
| |
| @Override |
| public void setBackground (Color color) { |
| super.setBackground (color); |
| // Are these settings the same as before? |
| if (backgroundImage == null && |
| gradientColors == null && |
| gradientPercents == null) { |
| if (color == null) { |
| if (background == null) return; |
| } else { |
| if (color.equals(background)) return; |
| } |
| } |
| background = color; |
| backgroundImage = null; |
| gradientColors = null; |
| gradientPercents = null; |
| redraw (); |
| } |
| |
| /** |
| * Specify a gradient of colours to be drawn in the background of the CLabel. |
| * <p>For example, to draw a gradient that varies from dark blue to blue and then to |
| * white and stays white for the right half of the label, use the following call |
| * to setBackground:</p> |
| * <pre> |
| * clabel.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), |
| * display.getSystemColor(SWT.COLOR_BLUE), |
| * display.getSystemColor(SWT.COLOR_WHITE), |
| * display.getSystemColor(SWT.COLOR_WHITE)}, |
| * new int[] {25, 50, 100}); |
| * </pre> |
| * |
| * @param colors an array of Color that specifies the colors to appear in the gradient |
| * in order of appearance from left to right; The value <code>null</code> |
| * clears the background gradient; the value <code>null</code> can be used |
| * inside the array of Color to specify the background color. |
| * @param percents an array of integers between 0 and 100 specifying the percent of the width |
| * of the widget at which the color should change; the size of the percents |
| * array must be one less than the size of the colors array. |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li> |
| * </ul> |
| */ |
| public void setBackground(Color[] colors, int[] percents) { |
| setBackground(colors, percents, false); |
| } |
| /** |
| * Specify a gradient of colours to be drawn in the background of the CLabel. |
| * <p>For example, to draw a gradient that varies from dark blue to white in the vertical, |
| * direction use the following call |
| * to setBackground:</p> |
| * <pre> |
| * clabel.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE), |
| * display.getSystemColor(SWT.COLOR_WHITE)}, |
| * new int[] {100}, true); |
| * </pre> |
| * |
| * @param colors an array of Color that specifies the colors to appear in the gradient |
| * in order of appearance from left/top to right/bottom; The value <code>null</code> |
| * clears the background gradient; the value <code>null</code> can be used |
| * inside the array of Color to specify the background color. |
| * @param percents an array of integers between 0 and 100 specifying the percent of the width/height |
| * of the widget at which the color should change; the size of the percents |
| * array must be one less than the size of the colors array. |
| * @param vertical indicate the direction of the gradient. True is vertical and false is horizontal. |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li> |
| * </ul> |
| * |
| * @since 3.0 |
| */ |
| public void setBackground(Color[] colors, int[] percents, boolean vertical) { |
| checkWidget(); |
| if (colors != null) { |
| if (percents == null || percents.length != colors.length - 1) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| if (getDisplay().getDepth() < 15) { |
| // Don't use gradients on low color displays |
| colors = new Color[] {colors[colors.length - 1]}; |
| percents = new int[] { }; |
| } |
| for (int i = 0; i < percents.length; i++) { |
| if (percents[i] < 0 || percents[i] > 100) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| if (i > 0 && percents[i] < percents[i-1]) { |
| SWT.error(SWT.ERROR_INVALID_ARGUMENT); |
| } |
| } |
| } |
| |
| // Are these settings the same as before? |
| final Color background = getBackground(); |
| if (backgroundImage == null) { |
| if ((gradientColors != null) && (colors != null) && |
| (gradientColors.length == colors.length)) { |
| boolean same = false; |
| for (int i = 0; i < gradientColors.length; i++) { |
| same = (gradientColors[i] == colors[i]) || |
| ((gradientColors[i] == null) && (colors[i] == background)) || |
| ((gradientColors[i] == background) && (colors[i] == null)); |
| if (!same) break; |
| } |
| if (same) { |
| for (int i = 0; i < gradientPercents.length; i++) { |
| same = gradientPercents[i] == percents[i]; |
| if (!same) break; |
| } |
| } |
| if (same && this.gradientVertical == vertical) return; |
| } |
| } else { |
| backgroundImage = null; |
| } |
| // Store the new settings |
| if (colors == null) { |
| gradientColors = null; |
| gradientPercents = null; |
| gradientVertical = false; |
| } else { |
| gradientColors = new Color[colors.length]; |
| for (int i = 0; i < colors.length; ++i) |
| gradientColors[i] = (colors[i] != null) ? colors[i] : background; |
| gradientPercents = new int[percents.length]; |
| for (int i = 0; i < percents.length; ++i) |
| gradientPercents[i] = percents[i]; |
| gradientVertical = vertical; |
| } |
| // Refresh with the new settings |
| redraw(); |
| } |
| /** |
| * Set the image to be drawn in the background of the label. |
| * |
| * @param image the image to be drawn in the background |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setBackground(Image image) { |
| checkWidget(); |
| if (image == backgroundImage) return; |
| if (image != null) { |
| gradientColors = null; |
| gradientPercents = null; |
| } |
| backgroundImage = image; |
| redraw(); |
| |
| } |
| /** |
| * Set the label's bottom margin, in pixels. |
| * |
| * @param bottomMargin the bottom margin of the label, which must be equal to or greater than zero |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| * |
| * @since 3.6 |
| */ |
| public void setBottomMargin(int bottomMargin) { |
| checkWidget(); |
| if (this.bottomMargin == bottomMargin || bottomMargin < 0) return; |
| this.bottomMargin = bottomMargin; |
| redraw(); |
| } |
| @Override |
| public void setFont(Font font) { |
| super.setFont(font); |
| redraw(); |
| } |
| /** |
| * Set the label's Image. |
| * The value <code>null</code> clears it. |
| * |
| * @param image the image to be displayed in the label or null |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setImage(Image image) { |
| checkWidget(); |
| if (image != this.image) { |
| this.image = image; |
| redraw(); |
| } |
| } |
| /** |
| * Set the label's horizontal left margin, in pixels. |
| * |
| * @param leftMargin the left margin of the label, which must be equal to or greater than zero |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| * |
| * @since 3.6 |
| */ |
| public void setLeftMargin(int leftMargin) { |
| checkWidget(); |
| if (this.leftMargin == leftMargin || leftMargin < 0) return; |
| this.leftMargin = leftMargin; |
| redraw(); |
| } |
| /** |
| * Set the label's margins, in pixels. |
| * |
| * @param leftMargin the left margin. |
| * @param topMargin the top margin. |
| * @param rightMargin the right margin. |
| * @param bottomMargin the bottom margin. |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| * |
| * @since 3.6 |
| */ |
| public void setMargins (int leftMargin, int topMargin, int rightMargin, int bottomMargin) { |
| checkWidget(); |
| this.leftMargin = Math.max(0, leftMargin); |
| this.topMargin = Math.max(0, topMargin); |
| this.rightMargin = Math.max(0, rightMargin); |
| this.bottomMargin = Math.max(0, bottomMargin); |
| redraw(); |
| } |
| /** |
| * Set the label's right margin, in pixels. |
| * |
| * @param rightMargin the right margin of the label, which must be equal to or greater than zero |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| * |
| * @since 3.6 |
| */ |
| public void setRightMargin(int rightMargin) { |
| checkWidget(); |
| if (this.rightMargin == rightMargin || rightMargin < 0) return; |
| this.rightMargin = rightMargin; |
| redraw(); |
| } |
| /** |
| * Set the label's text. |
| * The value <code>null</code> clears it. |
| * <p> |
| * Mnemonics are indicated by an '&' that causes the next |
| * character to be the mnemonic. When the user presses a |
| * key sequence that matches the mnemonic, focus is assigned |
| * to the control that follows the label. On most platforms, |
| * the mnemonic appears underlined but may be emphasised in a |
| * platform specific manner. The mnemonic indicator character |
| * '&' can be escaped by doubling it in the string, causing |
| * a single '&' to be displayed. |
| * </p> |
| * |
| * @param text the text to be displayed in the label or null |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setText(String text) { |
| checkWidget(); |
| if (text == null) text = ""; //$NON-NLS-1$ |
| if (! text.equals(this.text)) { |
| this.text = text; |
| redraw(); |
| } |
| } |
| @Override |
| public void setToolTipText (String string) { |
| super.setToolTipText (string); |
| appToolTipText = super.getToolTipText(); |
| } |
| /** |
| * Set the label's top margin, in pixels. |
| * |
| * @param topMargin the top margin of the label, which must be equal to or greater than zero |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> |
| * </ul> |
| * |
| * @since 3.6 |
| */ |
| public void setTopMargin(int topMargin) { |
| checkWidget(); |
| if (this.topMargin == topMargin || topMargin < 0) return; |
| this.topMargin = topMargin; |
| redraw(); |
| } |
| /** |
| * Shorten the given text <code>t</code> so that its length doesn't exceed |
| * the given width. The default implementation replaces characters in the |
| * center of the original string with an ellipsis ("..."). |
| * Override if you need a different strategy. |
| * |
| * @param gc the gc to use for text measurement |
| * @param t the text to shorten |
| * @param width the width to shorten the text to, in pixels |
| * @return the shortened text |
| */ |
| protected String shortenText(GC gc, String t, int width) { |
| if (t == null) return null; |
| int w = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x; |
| if (width<=w) return t; |
| int l = t.length(); |
| int max = l/2; |
| int min = 0; |
| int mid = (max+min)/2 - 1; |
| if (mid <= 0) return t; |
| TextLayout layout = new TextLayout (getDisplay()); |
| layout.setText(t); |
| mid = validateOffset(layout, mid); |
| while (min < mid && mid < max) { |
| String s1 = t.substring(0, mid); |
| String s2 = t.substring(validateOffset(layout, l-mid), l); |
| int l1 = gc.textExtent(s1, DRAW_FLAGS).x; |
| int l2 = gc.textExtent(s2, DRAW_FLAGS).x; |
| if (l1+w+l2 > width) { |
| max = mid; |
| mid = validateOffset(layout, (max+min)/2); |
| } else if (l1+w+l2 < width) { |
| min = mid; |
| mid = validateOffset(layout, (max+min)/2); |
| } else { |
| min = max; |
| } |
| } |
| String result = mid == 0 ? t : t.substring(0, mid) + ELLIPSIS + t.substring(validateOffset(layout, l-mid), l); |
| layout.dispose(); |
| return result; |
| } |
| int validateOffset(TextLayout layout, int offset) { |
| int nextOffset = layout.getNextOffset(offset, SWT.MOVEMENT_CLUSTER); |
| if (nextOffset != offset) return layout.getPreviousOffset(nextOffset, SWT.MOVEMENT_CLUSTER); |
| return offset; |
| } |
| private String[] splitString(String text) { |
| String[] lines = new String[1]; |
| int start = 0, pos; |
| do { |
| pos = text.indexOf('\n', start); |
| if (pos == -1) { |
| lines[lines.length - 1] = text.substring(start); |
| } else { |
| boolean crlf = (pos > 0) && (text.charAt(pos - 1) == '\r'); |
| lines[lines.length - 1] = text.substring(start, pos - (crlf ? 1 : 0)); |
| start = pos + 1; |
| String[] newLines = new String[lines.length+1]; |
| System.arraycopy(lines, 0, newLines, 0, lines.length); |
| lines = newLines; |
| } |
| } while (pos != -1); |
| return lines; |
| } |
| } |