diff dwtx/draw2d/Label.d @ 98:95307ad235d9

Added Draw2d code, still work in progress
author Frank Benoit <benoit@tionex.de>
date Sun, 03 Aug 2008 00:52:14 +0200
parents
children c3583c6ec027
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/draw2d/Label.d	Sun Aug 03 00:52:14 2008 +0200
@@ -0,0 +1,706 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.draw2d.Label;
+
+import dwt.dwthelper.utils;
+
+
+
+import dwt.graphics.Font;
+import dwt.graphics.Image;
+import dwtx.draw2d.geometry.Dimension;
+import dwtx.draw2d.geometry.Insets;
+import dwtx.draw2d.geometry.Point;
+import dwtx.draw2d.geometry.Rectangle;
+import dwtx.draw2d.Figure;
+import dwtx.draw2d.PositionConstants;
+import dwtx.draw2d.IFigure;
+import dwtx.draw2d.Graphics;
+import dwtx.draw2d.TextUtilities;
+import dwtx.draw2d.ColorConstants;
+
+/**
+ * A figure that can display text and/or an image.
+ */
+public class Label
+    : Figure
+    , PositionConstants
+{
+alias Figure.getPreferredSize getPreferredSize;
+
+private static String ELLIPSIS = "..."; //$NON-NLS-1$
+
+
+private Image icon;
+private String text = "";//$NON-NLS-1$
+private String subStringText;
+private Dimension textSize;
+private Dimension subStringTextSize;
+private Dimension iconSize;
+private Point iconLocation;
+private Point textLocation;
+private int textAlignment = CENTER;
+private int iconAlignment = CENTER;
+private int labelAlignment = CENTER;
+private int textPlacement = EAST;
+private int iconTextGap = 3;
+
+/**
+ * Construct an empty Label.
+ *
+ * @since 2.0
+ */
+public this() {
+    iconSize = new Dimension(0, 0);
+}
+
+/**
+ * Construct a Label with passed String as its text.
+ *
+ * @param s the label text
+ * @since 2.0
+ */
+public this(String s) {
+    this();
+    setText(s);
+}
+
+/**
+ * Construct a Label with passed Image as its icon.
+ *
+ * @param i the label image
+ * @since 2.0
+ */
+public this(Image i) {
+    this();
+    setIcon(i);
+}
+
+/**
+ * Construct a Label with passed String as text and passed Image as its icon.
+ *
+ * @param s the label text
+ * @param i the label image
+ * @since 2.0
+ */
+public this(String s, Image i) {
+    this();
+    setText(s);
+    setIcon(i);
+}
+
+private void alignOnHeight(Point loc, Dimension size, int alignment) {
+    Insets insets = getInsets();
+    switch(alignment) {
+        case TOP:
+            loc.y = insets.top;
+            break;
+        case BOTTOM:
+            loc.y = bounds.height - size.height - insets.bottom;
+            break;
+        default:
+            loc.y = (bounds.height - size.height) / 2;
+    }
+}
+
+private void alignOnWidth(Point loc, Dimension size, int alignment) {
+    Insets insets = getInsets();
+    switch(alignment) {
+        case LEFT:
+            loc.x = insets.left;
+            break;
+        case RIGHT:
+            loc.x = bounds.width - size.width - insets.right;
+            break;
+        default:
+            loc.x = (bounds.width - size.width) / 2;
+    }
+}
+
+private void calculateAlignment() {
+    switch(textPlacement) {
+        case EAST:
+        case WEST:
+            alignOnHeight(textLocation, getTextSize(), textAlignment);
+            alignOnHeight(iconLocation, getIconSize(), iconAlignment);
+            break;
+        case NORTH:
+        case SOUTH:
+            alignOnWidth(textLocation, getSubStringTextSize(), textAlignment);
+            alignOnWidth(iconLocation, getIconSize(), iconAlignment);
+            break;
+    }
+}
+
+/**
+ * Calculates the size of the Label using the passed Dimension as the size of the Label's
+ * text.
+ *
+ * @param txtSize the precalculated size of the label's text
+ * @return the label's size
+ * @since 2.0
+ */
+protected Dimension calculateLabelSize(Dimension txtSize) {
+    int gap = getIconTextGap();
+    if (getIcon() is null || getText().equals("")) //$NON-NLS-1$
+        gap = 0;
+    Dimension d = new Dimension(0, 0);
+    if (textPlacement is WEST || textPlacement is EAST) {
+        d.width = getIconSize().width + gap + txtSize.width;
+        d.height = Math.max(getIconSize().height, txtSize.height);
+    } else {
+        d.width = Math.max(getIconSize().width, txtSize.width);
+        d.height = getIconSize().height + gap + txtSize.height;
+    }
+    return d;
+}
+
+private void calculateLocations() {
+    textLocation = new Point();
+    iconLocation = new Point();
+
+    calculatePlacement();
+    calculateAlignment();
+    Dimension offset = getSize().getDifference(getPreferredSize());
+    offset.width += getTextSize().width - getSubStringTextSize().width;
+    switch (labelAlignment) {
+        case CENTER:
+            offset.scale(0.5f);
+            break;
+        case LEFT:
+            offset.scale(0.0f);
+            break;
+        case RIGHT:
+            offset.scale(1.0f);
+            break;
+        case TOP:
+            offset.height = 0;
+            offset.scale(0.5f);
+            break;
+        case BOTTOM:
+            offset.height = offset.height * 2;
+            offset.scale(0.5f);
+            break;
+        default:
+            offset.scale(0.5f);
+            break;
+    }
+
+    switch (textPlacement) {
+        case EAST:
+        case WEST:
+            offset.height = 0;
+            break;
+        case NORTH:
+        case SOUTH:
+            offset.width = 0;
+            break;
+    }
+
+    textLocation.translate(offset);
+    iconLocation.translate(offset);
+}
+
+private void calculatePlacement() {
+    int gap = getIconTextGap();
+    if (icon is null || text.equals("")) //$NON-NLS-1$
+        gap = 0;
+    Insets insets = getInsets();
+
+    switch(textPlacement) {
+    case EAST:
+        iconLocation.x = insets.left;
+        textLocation.x = getIconSize().width + gap + insets.left;
+        break;
+    case WEST:
+        textLocation.x = insets.left;
+        iconLocation.x = getSubStringTextSize().width + gap + insets.left;
+        break;
+    case NORTH:
+        textLocation.y = insets.top;
+        iconLocation.y = getTextSize().height + gap + insets.top;
+        break;
+    case SOUTH:
+        textLocation.y = getIconSize().height + gap + insets.top;
+        iconLocation.y = insets.top;
+    }
+}
+
+/**
+ * Calculates the size of the Label's text size. The text size calculated takes into
+ * consideration if the Label's text is currently truncated. If text size without
+ * considering current truncation is desired, use {@link #calculateTextSize()}.
+ *
+ * @return the size of the label's text, taking into account truncation
+ * @since 2.0
+ */
+protected Dimension calculateSubStringTextSize() {
+    return getTextUtilities().getTextExtents(getSubStringText(), getFont());
+}
+
+/**
+ * Calculates and returns the size of the Label's text. Note that this Dimension is
+ * calculated using the Label's full text, regardless of whether or not its text is
+ * currently truncated. If text size considering current truncation is desired, use
+ * {@link #calculateSubStringTextSize()}.
+ *
+ * @return the size of the label's text, ignoring truncation
+ * @since 2.0
+ */
+protected Dimension calculateTextSize() {
+    return getTextUtilities().getTextExtents(getText(), getFont());
+}
+
+private void clearLocations() {
+    iconLocation = textLocation = null;
+}
+
+/**
+ * Returns the Label's icon.
+ *
+ * @return the label icon
+ * @since 2.0
+ */
+public Image getIcon() {
+    return icon;
+}
+
+/**
+ * Returns the current alignment of the Label's icon. The default is
+ * {@link PositionConstants#CENTER}.
+ *
+ * @return the icon alignment
+ * @since 2.0
+ */
+public int getIconAlignment() {
+    return iconAlignment;
+}
+
+/**
+ * Returns the bounds of the Label's icon.
+ *
+ * @return the icon's bounds
+ * @since 2.0
+ */
+public Rectangle getIconBounds() {
+    Rectangle bounds = getBounds();
+    return new Rectangle(bounds.getLocation().translate(getIconLocation()), getIconSize());
+}
+
+/**
+ * Returns the location of the Label's icon relative to the Label.
+ *
+ * @return the icon's location
+ * @since 2.0
+ */
+protected Point getIconLocation() {
+    if (iconLocation is null)
+        calculateLocations();
+    return iconLocation;
+}
+
+/**
+ * Returns the gap in pixels between the Label's icon and its text.
+ *
+ * @return the gap
+ * @since 2.0
+ */
+public int getIconTextGap() {
+    return iconTextGap;
+}
+
+/**
+ * @see IFigure#getMinimumSize(int, int)
+ */
+public Dimension getMinimumSize(int w, int h) {
+    if (minSize !is null)
+        return minSize;
+    minSize = new Dimension();
+    if (getLayoutManager() !is null)
+        minSize.setSize(getLayoutManager().getMinimumSize(this, w, h));
+
+    Dimension labelSize =
+        calculateLabelSize(getTextUtilities().getTextExtents(getTruncationString(), getFont())
+                .intersect(getTextUtilities().getTextExtents(getText(), getFont())));
+    Insets insets = getInsets();
+    labelSize.expand(insets.getWidth(), insets.getHeight());
+    minSize.union_(labelSize);
+    return minSize;
+}
+
+/**
+ * @see IFigure#getPreferredSize(int, int)
+ */
+public Dimension getPreferredSize(int wHint, int hHint) {
+    if (prefSize is null) {
+        prefSize = calculateLabelSize(getTextSize());
+        Insets insets = getInsets();
+        prefSize.expand(insets.getWidth(), insets.getHeight());
+        if (getLayoutManager() !is null)
+            prefSize.union_(getLayoutManager().getPreferredSize(this, wHint, hHint));
+    }
+    if (wHint >= 0 && wHint < prefSize.width) {
+        Dimension minSize = getMinimumSize(wHint, hHint);
+        Dimension result = prefSize.getCopy();
+        result.width = Math.min(result.width, wHint);
+        result.width = Math.max(minSize.width, result.width);
+        return result;
+    }
+    return prefSize;
+}
+
+/**
+ * Calculates the amount of the Label's current text will fit in the Label, including an
+ * elipsis "..." if truncation is required.
+ *
+ * @return the substring
+ * @since 2.0
+ */
+public String getSubStringText() {
+    if (subStringText !is null)
+        return subStringText;
+
+    subStringText = text;
+    int widthShrink = getPreferredSize().width - getSize().width;
+    if (widthShrink <= 0)
+        return subStringText;
+
+    Dimension effectiveSize = getTextSize().getExpanded(-widthShrink, 0);
+    Font currentFont = getFont();
+    int dotsWidth = getTextUtilities().getTextExtents(getTruncationString(), currentFont).width;
+
+    if (effectiveSize.width < dotsWidth)
+        effectiveSize.width = dotsWidth;
+
+    int subStringLength = getTextUtilities().getLargestSubstringConfinedTo(text,
+                                                  currentFont,
+                                                  effectiveSize.width - dotsWidth);
+    subStringText = (text.substring(0, subStringLength) ~ getTruncationString()).dup;
+    return subStringText;
+}
+
+/**
+ * Returns the size of the Label's current text. If the text is currently truncated, the
+ * truncated text with its ellipsis is used to calculate the size.
+ *
+ * @return the size of this label's text, taking into account truncation
+ * @since 2.0
+ */
+protected Dimension getSubStringTextSize() {
+    if (subStringTextSize is null)
+        subStringTextSize = calculateSubStringTextSize();
+    return subStringTextSize;
+}
+
+/**
+ * Returns the text of the label. Note that this is the complete text of the label,
+ * regardless of whether it is currently being truncated. Call {@link #getSubStringText()}
+ * to return the label's current text contents with truncation considered.
+ *
+ * @return the complete text of this label
+ * @since 2.0
+ */
+public String getText() {
+    return text;
+}
+
+/**
+ * Returns the current alignment of the Label's text. The default text alignment is
+ * {@link PositionConstants#CENTER}.
+ *
+ * @return the text alignment
+ */
+public int getTextAlignment() {
+    return textAlignment;
+}
+
+/**
+ * Returns the bounds of the label's text. Note that the bounds are calculated using the
+ * label's complete text regardless of whether the label's text is currently truncated.
+ *
+ * @return the bounds of this label's complete text
+ * @since 2.0
+ */
+public Rectangle getTextBounds() {
+    Rectangle bounds = getBounds();
+    return new Rectangle(bounds.getLocation().translate(getTextLocation()), textSize);
+}
+
+/**
+ * Returns the location of the label's text relative to the label.
+ *
+ * @return the text location
+ * @since 2.0
+ */
+protected Point getTextLocation() {
+    if (textLocation !is null)
+        return textLocation;
+    calculateLocations();
+    return textLocation;
+}
+
+/**
+ * Returns the current placement of the label's text relative to its icon. The default
+ * text placement is {@link PositionConstants#EAST}.
+ *
+ * @return the text placement
+ * @since 2.0
+ */
+public int getTextPlacement() {
+    return textPlacement;
+}
+
+/**
+ * Returns the size of the label's complete text. Note that the text used to make this
+ * calculation is the label's full text, regardless of whether the label's text is
+ * currently being truncated and is displaying an ellipsis. If the size considering
+ * current truncation is desired, call {@link #getSubStringTextSize()}.
+ *
+ * @return the size of this label's complete text
+ * @since 2.0
+ */
+protected Dimension getTextSize() {
+    if (textSize is null)
+        textSize = calculateTextSize();
+    return textSize;
+}
+
+/**
+ * @see IFigure#invalidate()
+ */
+public void invalidate() {
+    prefSize = null;
+    minSize = null;
+    clearLocations();
+    textSize = null;
+    subStringTextSize = null;
+    subStringText = null;
+    super.invalidate();
+}
+
+/**
+ * Returns <code>true</code> if the label's text is currently truncated and is displaying
+ * an ellipsis, <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if the label's text is truncated
+ * @since 2.0
+ */
+public bool isTextTruncated() {
+    return !getSubStringText().equals(getText());
+}
+
+/**
+ * @see Figure#paintFigure(Graphics)
+ */
+protected void paintFigure(Graphics graphics) {
+    if (isOpaque())
+        super.paintFigure(graphics);
+    Rectangle bounds = getBounds();
+    graphics.translate(bounds.x, bounds.y);
+    if (icon !is null)
+        graphics.drawImage(icon, getIconLocation());
+    if (!isEnabled()) {
+        graphics.translate(1, 1);
+        graphics.setForegroundColor(ColorConstants.buttonLightest);
+        graphics.drawText(getSubStringText(), getTextLocation());
+        graphics.translate(-1, -1);
+        graphics.setForegroundColor(ColorConstants.buttonDarker);
+    }
+    graphics.drawText(getSubStringText(), getTextLocation());
+    graphics.translate(-bounds.x, -bounds.y);
+}
+
+/**
+ * Sets the label's icon to the passed image.
+ *
+ * @param image the new label image
+ * @since 2.0
+ */
+public void setIcon(Image image) {
+    if (icon is image)
+        return;
+    icon = image;
+    //Call repaint, in case the image dimensions are the same.
+    repaint();
+    if (icon is null)
+        setIconDimension(new Dimension());
+    else
+        setIconDimension(new Dimension(image));
+}
+
+/**
+ * This method sets the alignment of the icon within the bounds of the label. If the label
+ * is larger than the icon, then the icon will be aligned according to this alignment.
+ * Valid values are:
+ * <UL>
+ *   <LI><EM>{@link PositionConstants#CENTER}</EM>
+ *   <LI>{@link PositionConstants#TOP}
+ *   <LI>{@link PositionConstants#BOTTOM}
+ *   <LI>{@link PositionConstants#LEFT}
+ *   <LI>{@link PositionConstants#RIGHT}
+ * </UL>
+ * @param align the icon alignment
+ * @since 2.0
+ */
+public void setIconAlignment (int align_) {
+    if (iconAlignment is align_)
+        return;
+    iconAlignment = align_;
+    clearLocations();
+    repaint();
+}
+
+/**
+ * Sets the label's icon size to the passed Dimension.
+ *
+ * @param d the new icon size
+ * @deprecated the icon is automatically displayed at 1:1
+ * @since 2.0
+ */
+public void setIconDimension(Dimension d) {
+    if (d.opEquals(getIconSize()))
+        return;
+    iconSize = d;
+    revalidate();
+}
+
+/**
+ * Sets the gap in pixels between the label's icon and text to the passed value. The
+ * default is 4.
+ *
+ * @param gap the gap
+ * @since 2.0
+ */
+public void setIconTextGap(int gap) {
+    if (iconTextGap is gap)
+        return;
+    iconTextGap = gap;
+    repaint();
+    revalidate();
+}
+
+/**
+ * Sets the alignment of the label (icon and text) within the figure. If this
+ * figure's bounds are larger than the size needed to display the label, the
+ * label will be aligned accordingly. Valid values are:
+ * <UL>
+ *   <LI><EM>{@link PositionConstants#CENTER}</EM>
+ *   <LI>{@link PositionConstants#TOP}
+ *   <LI>{@link PositionConstants#BOTTOM}
+ *   <LI>{@link PositionConstants#LEFT}
+ *   <LI>{@link PositionConstants#RIGHT}
+ * </UL>
+ *
+ * @param align label alignment
+ */
+public void setLabelAlignment(int align_) {
+    if (labelAlignment is align_)
+        return;
+    labelAlignment = align_;
+    clearLocations();
+    repaint();
+}
+
+/**
+ * Sets the label's text.
+ * @param s the new label text
+ * @since 2.0
+ */
+public void setText(String s) {
+    //"text" will never be null.
+    if (s is null)
+        s = "";//$NON-NLS-1$
+    if (text.equals(s))
+        return;
+    text = s;
+    revalidate();
+    repaint();
+}
+
+/**
+ * Sets the alignment of the text relative to the icon within the label. The text
+ * alignment must be orthogonal to the text placement. For example, if the placement
+ * is EAST, then the text can be aligned using TOP, CENTER, or BOTTOM. Valid values are:
+ * <UL>
+ *   <LI><EM>{@link PositionConstants#CENTER}</EM>
+ *   <LI>{@link PositionConstants#TOP}
+ *   <LI>{@link PositionConstants#BOTTOM}
+ *   <LI>{@link PositionConstants#LEFT}
+ *   <LI>{@link PositionConstants#RIGHT}
+ * </UL>
+ * @see #setLabelAlignment(int)
+ * @param align the text alignment
+ * @since 2.0
+ */
+public void setTextAlignment(int align_) {
+    if (textAlignment is align_)
+        return;
+    textAlignment = align_;
+    clearLocations();
+    repaint();
+}
+
+/**
+ * Sets the placement of the text relative to the icon within the label.
+ * Valid values are:
+ * <UL>
+ *   <LI><EM>{@link PositionConstants#EAST}</EM>
+ *   <LI>{@link PositionConstants#NORTH}
+ *   <LI>{@link PositionConstants#SOUTH}
+ *   <LI>{@link PositionConstants#WEST}
+ * </UL>
+ *
+ * @param where the text placement
+ * @since 2.0
+ */
+public void setTextPlacement (int where) {
+    if (textPlacement is where)
+        return;
+    textPlacement = where;
+    revalidate();
+    repaint();
+}
+
+/**
+ * Gets the <code>TextUtilities</code> instance to be used in measurement
+ * calculations.
+ *
+ * @return a <code>TextUtilities</code> instance
+ * @since 3.4
+ */
+public TextUtilities getTextUtilities() {
+    return TextUtilities.INSTANCE;
+}
+
+/**
+ * Gets the string that will be appended to the text when the label is
+ * truncated. By default, this returns an ellipsis.
+ *
+ * @return the string to append to the text when truncated
+ * @since 3.4
+ */
+protected String getTruncationString() {
+    return ELLIPSIS;
+}
+
+/**
+ * Gets the icon size
+ *
+ * @return the icon size
+ * @since 3.4
+ */
+protected Dimension getIconSize() {
+    return iconSize;
+}
+
+}