diff org.eclipse.draw2d/src/org/eclipse/draw2d/parts/Thumbnail.d @ 12:bc29606a740c

Added dwt-addons in original directory structure of eclipse.org
author Frank Benoit <benoit@tionex.de>
date Sat, 14 Mar 2009 18:23:29 +0100
parents
children dbfb303e8fb0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.draw2d/src/org/eclipse/draw2d/parts/Thumbnail.d	Sat Mar 14 18:23:29 2009 +0100
@@ -0,0 +1,512 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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 org.eclipse.draw2d.parts.Thumbnail;
+
+import java.lang.all;
+import org.eclipse.swt.dwthelper.Runnable;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+static import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.SWTGraphics;
+import org.eclipse.draw2d.ScaledGraphics;
+import org.eclipse.draw2d.UpdateListener;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * A Thumbnail is a Figure that displays an image of its source Figure at a
+ * smaller size. The Thumbnail will maintain the aspect ratio of the source
+ * Figure.
+ *
+ * @author Eric Bordeau
+ */
+public class Thumbnail
+    : Figure
+    , UpdateListener
+{
+alias Figure.getPreferredSize getPreferredSize;
+
+
+/**
+ * This updates the Thumbnail by breaking the thumbnail {@link Image} into
+ * several tiles and updating each tile individually.
+ */
+class ThumbnailUpdater : Runnable {
+    static final int MAX_BUFFER_SIZE = 256;
+    private int currentHTile, currentVTile;
+    private int hTiles, vTiles;
+    private bool isActive_ = true;
+
+    private bool isRunning_ = false;
+    private GC thumbnailGC;
+    private ScaledGraphics thumbnailGraphics;
+    private Dimension tileSize;
+
+    /**
+     * Stops the updater and disposes of any resources.
+     */
+    public void deactivate() {
+        setActive(false);
+        stop();
+        if (thumbnailImage !is null) {
+            thumbnailImage.dispose();
+            thumbnailImage = null;
+            thumbnailImageSize = null;
+        }
+    }
+
+    /**
+     * Returns the current horizontal tile index.
+     * @return current horizontal tile index.
+     */
+    protected int getCurrentHTile() {
+        return currentHTile;
+    }
+
+    /**
+     * Returns the current vertical tile index.
+     * @return current vertical tile index.
+     */
+    protected int getCurrentVTile() {
+        return currentVTile;
+    }
+
+    /**
+     * Returns <code>true</code> if this ThumbnailUpdater is active.  An inactive
+     * updater has disposed of its {@link Image}.  The updater may be active and
+     * not currently running.
+     * @return <code>true</code> if this ThumbnailUpdater is active
+     */
+    public bool isActive() {
+        return isActive_;
+    }
+
+    /**
+     * Returns <code>true</code> if this is currently running and updating at
+     * least one tile on the thumbnail {@link Image}.
+     * @return <code>true</code> if this is currently running
+     */
+    public bool isRunning() {
+        return isRunning_;
+    }
+
+    /**
+     * Resets the number of vertical and horizontal tiles, as well as the tile
+     * size and current tile index.
+     */
+    public void resetTileValues() {
+        hTiles = cast(int)Math.ceil(cast(float)getSourceRectangle().width
+                                    / cast(float)MAX_BUFFER_SIZE);
+        vTiles = cast(int)Math.ceil(cast(float)getSourceRectangle().height
+                                    / cast(float)MAX_BUFFER_SIZE);
+
+        tileSize = new Dimension(cast(int)Math.ceil(cast(float)getSourceRectangle().width
+                                    / cast(float)hTiles),
+                                cast(int)Math.ceil(cast(float)getSourceRectangle().height
+                                    / cast(float)vTiles));
+
+        currentHTile = 0;
+        currentVTile = 0;
+    }
+
+    /**
+     * Restarts the updater.
+     */
+    public void restart() {
+        stop();
+        start();
+    }
+
+    /**
+     * Updates the current tile on the Thumbnail.  An area of the source Figure
+     * is painted to an {@link Image}.  That Image is then drawn on the
+     * Thumbnail.  Scaling of the source Image is done inside
+     * {@link GC#drawImage(Image, int, int, int, int, int, int, int, int)} since
+     * the source and target sizes are different.  The current tile indexes are
+     * incremented and if more updating is necesary, this {@link Runnable} is
+     * called again in a {@link Display#timerExec(int, Runnable)}.  If no more
+     * updating is required, {@link #stop()} is called.
+     */
+    public void run() {
+        if (!isActive() || !isRunning())
+            return;
+        int v = getCurrentVTile();
+        int sy1 = v * tileSize.height;
+        int sy2 = Math.min((v + 1) * tileSize.height, getSourceRectangle().height);
+
+        int h = getCurrentHTile();
+        int sx1 = h * tileSize.width;
+        int sx2 = Math.min((h + 1) * tileSize.width, getSourceRectangle().width);
+        org.eclipse.draw2d.geometry.Point.Point p = getSourceRectangle().getLocation();
+
+        Rectangle rect = new Rectangle(sx1 + p.x, sy1 + p.y, sx2 - sx1, sy2 - sy1);
+        thumbnailGraphics.pushState();
+        thumbnailGraphics.setClip(rect);
+        thumbnailGraphics.fillRectangle(rect);
+        sourceFigure.paint(thumbnailGraphics);
+        thumbnailGraphics.popState();
+
+        if (getCurrentHTile() < (hTiles - 1))
+            setCurrentHTile(getCurrentHTile() + 1);
+        else {
+            setCurrentHTile(0);
+            if (getCurrentVTile() < (vTiles - 1))
+                setCurrentVTile(getCurrentVTile() + 1);
+            else
+                setCurrentVTile(0);
+        }
+
+        if (getCurrentHTile() !is 0 || getCurrentVTile() !is 0)
+            Display.getCurrent().asyncExec(this);
+        else if (isDirty()) {
+            setDirty(false);
+            Display.getCurrent().asyncExec(this);
+            repaint();
+        } else {
+            stop();
+            repaint();
+        }
+    }
+
+    /**
+     * Sets the active flag.
+     * @param value The active value
+     */
+    public void setActive(bool value) {
+        isActive_ = value;
+    }
+
+    /**
+     * Sets the current horizontal tile index.
+     * @param count current horizontal tile index
+     */
+    protected void setCurrentHTile(int count) {
+        currentHTile = count;
+    }
+
+    /**
+     * Sets the current vertical tile index.
+     * @param count current vertical tile index
+     */
+    protected void setCurrentVTile(int count) {
+        currentVTile = count;
+    }
+
+    /**
+     * Starts this updater.  This method initializes all the necessary resources
+     * and puts this {@link Runnable} on the asynch queue.  If this updater is
+     * not active or is already running, this method just returns.
+     */
+    public void start() {
+        if (!isActive() || isRunning())
+            return;
+
+        isRunning_ = true;
+        setDirty(false);
+        resetTileValues();
+
+        if (!targetSize.opEquals(thumbnailImageSize)) {
+            resetThumbnailImage();
+        }
+
+        if (targetSize.isEmpty())
+            return;
+
+        thumbnailGC = new GC(thumbnailImage,
+                sourceFigure.isMirrored() ? SWT.RIGHT_TO_LEFT : SWT.NONE);
+        thumbnailGraphics = new ScaledGraphics(new SWTGraphics(thumbnailGC));
+        thumbnailGraphics.scale(getScaleX());
+        thumbnailGraphics.translate(getSourceRectangle().getLocation().negate());
+
+        Color color = sourceFigure.getForegroundColor();
+        if (color !is null)
+            thumbnailGraphics.setForegroundColor(color);
+        color = sourceFigure.getBackgroundColor();
+        if (color !is null)
+            thumbnailGraphics.setBackgroundColor(color);
+        thumbnailGraphics.setFont(sourceFigure.getFont());
+
+        setScales(targetSize.width / cast(float)getSourceRectangle().width,
+                 targetSize.height / cast(float)getSourceRectangle().height);
+
+        Display.getCurrent().asyncExec(this);
+    }
+
+    /**
+     *
+     * @since 3.2
+     */
+    private void resetThumbnailImage() {
+        if (thumbnailImage !is null)
+            thumbnailImage.dispose();
+
+        if (!targetSize.isEmpty()) {
+            thumbnailImage = new Image(Display.getDefault(),
+                    targetSize.width,
+                    targetSize.height);
+            thumbnailImageSize = new Dimension(targetSize);
+        }
+        else {
+            thumbnailImage = null;
+            thumbnailImageSize = new Dimension(0, 0);
+        }
+    }
+
+    /**
+     * Stops this updater.  Also disposes of resources (except the thumbnail
+     * image which is still needed for painting).
+     */
+    public void stop() {
+        isRunning_ = false;
+        if (thumbnailGC !is null) {
+            thumbnailGC.dispose();
+            thumbnailGC = null;
+        }
+        if (thumbnailGraphics !is null) {
+            thumbnailGraphics.dispose();
+            thumbnailGraphics = null;
+        }
+        // Don't dispose of the thumbnail image since it is needed to paint the
+        // figure when the source is not dirty (i.e. showing/hiding the dock).
+    }
+}
+private bool isDirty_;
+private float scaleX;
+private float scaleY;
+
+private IFigure sourceFigure;
+Dimension targetSize;
+private Image thumbnailImage;
+private Dimension thumbnailImageSize;
+private ThumbnailUpdater updater;
+
+/**
+ * Creates a new Thumbnail.  The source Figure must be set separately if you
+ * use this constructor.
+ */
+public this() {
+    super();
+    targetSize = new Dimension(0, 0);
+    updater = new ThumbnailUpdater();
+}
+
+/**
+ * Creates a new Thumbnail with the given IFigure as its source figure.
+ * @param fig The source figure
+ */
+public this(IFigure fig) {
+    this();
+    setSource(fig);
+}
+
+private Dimension adjustToAspectRatio(Dimension size, bool adjustToMaxDimension) {
+    Dimension sourceSize = getSourceRectangle().getSize();
+    Dimension borderSize = new Dimension(getInsets().getWidth(), getInsets().getHeight());
+    size.expand(borderSize.getNegated());
+    int width, height;
+    if (adjustToMaxDimension) {
+        width  = Math.max(size.width, cast(int)(size.height * sourceSize.width
+                                            / cast(float)sourceSize.height + 0.5));
+        height = Math.max(size.height, cast(int)(size.width * sourceSize.height
+                                            / cast(float)sourceSize.width + 0.5));
+    } else {
+        width  = Math.min(size.width,  cast(int)(size.height * sourceSize.width
+                                            / cast(float)sourceSize.height + 0.5));
+        height = Math.min(size.height, cast(int)(size.width * sourceSize.height
+                                            / cast(float)sourceSize.width + 0.5));
+    }
+    size.width  = width;
+    size.height = height;
+    return size.expand(borderSize);
+}
+
+/**
+ * Deactivates this Thumbnail.
+ */
+public void deactivate() {
+    sourceFigure.getUpdateManager().removeUpdateListener(this);
+    updater.deactivate();
+}
+
+/**
+ * Returns the preferred size of this Thumbnail.  The preferred size will be
+ * calculated in a way that maintains the source Figure's aspect ratio.
+ *
+ * @param wHint The width hint
+ * @param hHint The height hint
+ * @return The preferred size
+ */
+public Dimension getPreferredSize(int wHint, int hHint) {
+    if (prefSize is null)
+        return adjustToAspectRatio(getBounds().getSize(), false);
+
+    Dimension preferredSize = adjustToAspectRatio(prefSize.getCopy(), true);
+
+    if (maxSize is null)
+        return preferredSize;
+
+    Dimension maximumSize = adjustToAspectRatio(maxSize.getCopy(), true);
+    if (preferredSize.contains(maximumSize))
+        return maximumSize;
+    else
+        return preferredSize;
+}
+
+/**
+ * Returns the scale factor on the X-axis.
+ * @return X scale
+ */
+protected float getScaleX() {
+    return scaleX;
+}
+
+/**
+ * Returns the scale factor on the Y-axis.
+ * @return Y scale
+ */
+protected float getScaleY() {
+    return scaleY;
+}
+
+/**
+ * Returns the source figure being used to generate a thumbnail.
+ * @return the source figure
+ */
+protected IFigure getSource() {
+    return sourceFigure;
+}
+
+/**
+ * Returns the rectangular region relative to the source figure which will be the basis of
+ * the thumbnail.  The value may be returned by reference and should not be modified by
+ * the caller.
+ * @since 3.1
+ * @return the region of the source figure being used for the thumbnail
+ */
+protected Rectangle getSourceRectangle() {
+    return sourceFigure.getBounds();
+}
+
+/**
+ * Returns the scaled Image of the source Figure.  If the Image needs to be
+ * updated, the ThumbnailUpdater will notified.
+ *
+ * @return The thumbnail image
+ */
+protected Image getThumbnailImage() {
+    Dimension oldSize = targetSize;
+    targetSize = getPreferredSize();
+    targetSize.expand((new Dimension(getInsets().getWidth(),
+                                    getInsets().getHeight())).negate());
+    setScales(targetSize.width / cast(float)getSourceRectangle().width,
+             targetSize.height / cast(float)getSourceRectangle().height);
+    if ((isDirty()) && !updater.isRunning())
+        updater.start();
+    else if (oldSize !is null && !targetSize.opEquals(oldSize)) {
+        revalidate();
+        updater.restart();
+    }
+
+    return thumbnailImage;
+}
+
+/**
+ * Returns <code>true</code> if the source figure has changed.
+ * @return <code>true</code> if the source figure has changed
+ */
+protected bool isDirty() {
+    return isDirty_;
+}
+
+/**
+ * @see org.eclipse.draw2d.UpdateListener#notifyPainting(Rectangle, Map)
+ */
+public void notifyPainting(Rectangle damage, Map dirtyRegions) {
+    Iterator dirtyFigures = dirtyRegions.keySet().iterator();
+    while (dirtyFigures.hasNext()) {
+        IFigure current = cast(IFigure)dirtyFigures.next();
+        while (current !is null) {
+            if (current is getSource()) {
+                setDirty(true);
+                repaint();
+                return;
+            }
+            current = current.getParent();
+        }
+    }
+}
+
+/**
+ * @see org.eclipse.draw2d.UpdateListener#notifyValidating()
+ */
+public void notifyValidating() {
+//  setDirty(true);
+//  revalidate();
+}
+
+/**
+ * @see org.eclipse.draw2d.Figure#paintFigure(Graphics)
+ */
+protected void paintFigure(Graphics graphics) {
+    Image thumbnail = getThumbnailImage();
+    if (thumbnail is null)
+        return;
+    graphics.drawImage(thumbnail, getClientArea().getLocation());
+}
+
+/**
+ * Sets the dirty flag.
+ * @param value The dirty value
+ */
+public void setDirty(bool value) {
+    isDirty_ = value;
+}
+
+/**
+ * Sets the X and Y scales for the Thumbnail.  These scales represent the ratio
+ * between the source figure and the Thumbnail.
+ * @param x The X scale
+ * @param y The Y scale
+ */
+protected void setScales(float x, float y) {
+    scaleX = x;
+    scaleY = y;
+}
+
+/**
+ * Sets the source Figure.  Also sets the scales and creates the necessary
+ * update manager.
+ * @param fig The source figure
+ */
+public void setSource(IFigure fig) {
+    if (sourceFigure is fig)
+        return;
+    if (sourceFigure !is null)
+        sourceFigure.getUpdateManager().removeUpdateListener(this);
+    sourceFigure = fig;
+    if (sourceFigure !is null) {
+        setScales(cast(float)getSize().width / cast(float)getSourceRectangle().width,
+                cast(float)getSize().height / cast(float)getSourceRectangle().height);
+        sourceFigure.getUpdateManager().addUpdateListener(this);
+        repaint();
+    }
+}
+
+}