| /******************************************************************************* |
| * Copyright (c) 2008 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.gmf.runtime.draw2d.ui.internal.parts; |
| |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.graphics.PaletteData; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.swt.widgets.Display; |
| |
| import org.eclipse.draw2d.ColorConstants; |
| import org.eclipse.draw2d.Figure; |
| import org.eclipse.draw2d.FigureListener; |
| import org.eclipse.draw2d.Graphics; |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.KeyEvent; |
| import org.eclipse.draw2d.KeyListener; |
| import org.eclipse.draw2d.MouseEvent; |
| import org.eclipse.draw2d.MouseListener; |
| import org.eclipse.draw2d.MouseMotionListener; |
| import org.eclipse.draw2d.Viewport; |
| import org.eclipse.draw2d.geometry.Dimension; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.geometry.Rectangle; |
| |
| /** |
| * A scaled image representation of a Figure. If the source Figure is not completely |
| * visible, a SelectorFigure is placed over the thumbnail representing the viewable area |
| * and can be dragged around to scroll the source figure. |
| * Code modified to resolve {@link https://bugs.eclipse.org/bugs/show_bug.cgi?id=230056} |
| */ |
| public final class ScrollableThumbnailEx |
| extends ThumbnailEx |
| { |
| |
| private class ClickScrollerAndDragTransferrer |
| extends MouseMotionListener.Stub |
| implements MouseListener |
| { |
| private boolean dragTransfer; |
| public void mouseDoubleClicked(MouseEvent me) { } |
| public void mouseDragged(MouseEvent me) { |
| if (dragTransfer) |
| syncher.mouseDragged(me); |
| } |
| public void mousePressed(MouseEvent me) { |
| if (!(ScrollableThumbnailEx.this.getClientArea().contains(me.getLocation()))) |
| return; |
| Dimension selectorCenter = selector.getBounds().getSize().scale(0.5f); |
| Point scrollPoint = me.getLocation() |
| .getTranslated(getLocation().getNegated()) |
| .translate(selectorCenter.negate()) |
| .scale(1.0f / getViewportScaleX(), 1.0f / getViewportScaleY()) |
| .translate( |
| viewport.getHorizontalRangeModel().getMinimum(), |
| viewport.getVerticalRangeModel().getMinimum()); |
| viewport.setViewLocation(scrollPoint); |
| syncher.mousePressed(me); |
| dragTransfer = true; |
| } |
| public void mouseReleased(MouseEvent me) { |
| syncher.mouseReleased(me); |
| dragTransfer = false; |
| } |
| } |
| |
| private class ScrollSynchronizer |
| extends MouseMotionListener.Stub |
| implements MouseListener |
| { |
| private Point startLocation; |
| private Point viewLocation; |
| |
| public void mouseDoubleClicked(MouseEvent me) { } |
| |
| public void mouseDragged(MouseEvent me) { |
| Dimension d = me.getLocation().getDifference(startLocation); |
| d.scale(1.0f / getViewportScaleX(), 1.0f / getViewportScaleY()); |
| viewport.setViewLocation(viewLocation.getTranslated(d)); |
| me.consume(); |
| } |
| |
| public void mousePressed(MouseEvent me) { |
| startLocation = me.getLocation(); |
| viewLocation = viewport.getViewLocation(); |
| me.consume(); |
| } |
| |
| public void mouseReleased(MouseEvent me) { } |
| } |
| |
| private class SelectorFigure |
| extends Figure |
| { |
| { |
| Display display = Display.getCurrent(); |
| PaletteData pData = new PaletteData(0xFF, 0xFF00, 0xFF0000); |
| RGB rgb = ColorConstants.menuBackgroundSelected.getRGB(); |
| int fillColor = pData.getPixel(rgb); |
| ImageData iData = new ImageData(1, 1, 24, pData); |
| iData.setPixel(0, 0, fillColor); |
| iData.setAlpha(0, 0, 55); |
| image = new Image(display, iData); |
| } |
| private Rectangle iBounds = new Rectangle(0, 0, 1, 1); |
| |
| private Image image; |
| |
| protected void dispose() { |
| image.dispose(); |
| } |
| |
| public void paintFigure(Graphics g) { |
| Rectangle bounds = getBounds().getCopy(); |
| |
| // Avoid drawing images that are 0 in dimension |
| if (bounds.width < 5 || bounds.height < 5) |
| return; |
| |
| // Don't paint the selector figure if the entire source is visible. |
| Dimension thumbnailSize = new Dimension(getThumbnailImage()); |
| // expand to compensate for rounding errors in calculating bounds |
| Dimension size = getSize().getExpanded(1, 1); |
| if (size.contains(thumbnailSize)) |
| return; |
| |
| bounds.height--; |
| bounds.width--; |
| g.drawImage(image, iBounds, bounds); |
| |
| g.setForegroundColor(ColorConstants.menuBackgroundSelected); |
| g.drawRectangle(bounds); |
| } |
| |
| } |
| private FigureListener figureListener = new FigureListener() { |
| public void figureMoved(IFigure source) { |
| reconfigureSelectorBounds(); |
| } |
| }; |
| private KeyListener keyListener = new KeyListener.Stub() { |
| public void keyPressed(KeyEvent ke) { |
| int moveX = viewport.getClientArea().width / 4; |
| int moveY = viewport.getClientArea().height / 4; |
| if (ke.keycode == SWT.HOME || (isMirrored() ? ke.keycode == SWT.ARROW_RIGHT |
| : ke.keycode == SWT.ARROW_LEFT)) |
| viewport.setViewLocation(viewport.getViewLocation().translate(-moveX, 0)); |
| else if (ke.keycode == SWT.END || (isMirrored() ? ke.keycode == SWT.ARROW_LEFT |
| : ke.keycode == SWT.ARROW_RIGHT)) |
| viewport.setViewLocation(viewport.getViewLocation().translate(moveX, 0)); |
| else if (ke.keycode == SWT.ARROW_UP || ke.keycode == SWT.PAGE_UP) |
| viewport.setViewLocation(viewport.getViewLocation().translate(0, -moveY)); |
| else if (ke.keycode == SWT.ARROW_DOWN || ke.keycode == SWT.PAGE_DOWN) |
| viewport.setViewLocation(viewport.getViewLocation().translate(0, moveY)); |
| } |
| }; |
| |
| private PropertyChangeListener propListener = new PropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent evt) { |
| reconfigureSelectorBounds(); |
| } |
| }; |
| |
| private SelectorFigure selector; |
| |
| private ScrollSynchronizer syncher; |
| private Viewport viewport; |
| |
| /** |
| * Creates a new ScrollableThumbnailEx. |
| */ |
| public ScrollableThumbnailEx() { |
| super(); |
| initialize(); |
| } |
| |
| /** |
| * Creates a new ScrollableThumbnailEx that synchs with the given Viewport. |
| * @param port The Viewport |
| */ |
| public ScrollableThumbnailEx(Viewport port) { |
| super(); |
| setViewport(port); |
| initialize(); |
| } |
| |
| /** |
| * @see ThumbnailEx#deactivate() |
| */ |
| public void deactivate() { |
| viewport.removePropertyChangeListener(Viewport.PROPERTY_VIEW_LOCATION, propListener); |
| viewport.removeFigureListener(figureListener); |
| remove(selector); |
| selector.dispose(); |
| super.deactivate(); |
| } |
| |
| private double getViewportScaleX() { |
| return (double)targetSize.width / viewport.getContents().getBounds().width; |
| } |
| |
| private double getViewportScaleY() { |
| return (double)targetSize.height / viewport.getContents().getBounds().height; |
| } |
| |
| private void initialize() { |
| selector = new SelectorFigure(); |
| selector.addMouseListener(syncher = new ScrollSynchronizer()); |
| selector.addMouseMotionListener(syncher); |
| selector.setFocusTraversable(true); |
| selector.addKeyListener(keyListener); |
| add(selector); |
| ClickScrollerAndDragTransferrer transferrer = |
| new ClickScrollerAndDragTransferrer(); |
| addMouseListener(transferrer); |
| addMouseMotionListener(transferrer); |
| } |
| |
| private void reconfigureSelectorBounds() { |
| Rectangle rect = new Rectangle(); |
| Point offset = viewport.getViewLocation(); |
| offset.x -= viewport.getHorizontalRangeModel().getMinimum(); |
| offset.y -= viewport.getVerticalRangeModel().getMinimum(); |
| rect.setLocation(offset); |
| rect.setSize(viewport.getClientArea().getSize()); |
| rect.scale(getViewportScaleX(), getViewportScaleY()); |
| rect.translate(getClientArea().getLocation()); |
| selector.setBounds(rect); |
| } |
| |
| /** |
| * Reconfigures the SelectorFigure's bounds if the scales have changed. |
| * @param scaleX The X scale |
| * @param scaleY The Y scale |
| * @see org.eclipse.draw2d.parts.Thumbnail#setScales(float, float) |
| */ |
| protected void setScales(float scaleX, float scaleY) { |
| if (scaleX == getScaleX() && scaleY == getScaleY()) |
| return; |
| |
| super.setScales(scaleX, scaleY); |
| reconfigureSelectorBounds(); |
| } |
| |
| /** |
| * Sets the Viewport that this ScrollableThumbnailEx will synch with. |
| * @param port The Viewport |
| */ |
| public void setViewport(Viewport port) { |
| port.addPropertyChangeListener(Viewport.PROPERTY_VIEW_LOCATION, propListener); |
| port.addFigureListener(figureListener); |
| viewport = port; |
| } |
| |
| } |