blob: 65a4aa5c67dbf84630384865251e630a5110fb36 [file] [log] [blame]
package net.sf.taverna.t2.workbench.views.graph;
import static java.awt.event.InputEvent.BUTTON1_DOWN_MASK;
import static java.awt.event.InputEvent.BUTTON1_MASK;
import static java.awt.event.MouseEvent.BUTTON1;
import static java.awt.event.MouseEvent.MOUSE_DRAGGED;
import static java.awt.event.MouseEvent.MOUSE_PRESSED;
import static java.lang.System.currentTimeMillis;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.swing.gvt.InteractorAdapter;
import org.apache.batik.swing.gvt.JGVTComponent;
/**
* An interactor that scrolls the canvas view if the mouse is dragged to the
* edge of the canvas.
*
* @author David Withers
*/
public class AutoScrollInteractor extends InteractorAdapter {
/**
* Defines the border around the canvas in which the auto scroll will become
* active.
*/
private static final int BORDER = 25;
/**
* The interval, in milliseconds, between scroll events.
*/
private static final long SCROLL_INTERVAL = 100;
private JSVGCanvas svgCanvas;
private Dimension canvasSize;
private int scrollX;
private int scrollY;
private int mouseX;
private int mouseY;
/**
* Component used to identify mouse events generated by this class
*/
private Component eventIdentifier = new Component() {
private static final long serialVersionUID = -295542754718804222L;
};
private static Timer timer = new Timer("GraphAutoScrollTimer", true);
private TimerTask task;
/**
* Whether the interactor has finished.
*/
protected boolean finished = true;
public AutoScrollInteractor(JSVGCanvas svgCanvas) {
this.svgCanvas = svgCanvas;
}
@Override
public boolean startInteraction(InputEvent ie) {
int mods = ie.getModifiers();
if (ie.getID() == MOUSE_PRESSED && (mods & BUTTON1_MASK) != 0) {
AffineTransform transform = svgCanvas.getRenderingTransform();
// check if we're zoomed in
if (transform.getScaleX() > 1d || transform.getScaleY() > 1d) {
canvasSize = svgCanvas.getSize();
return true;
}
}
return false;
}
@Override
public boolean endInteraction() {
return finished;
}
@Override
public void mousePressed(final MouseEvent e) {
if (startInteraction(e)) {
finished = false;
task = new TimerTask() {
@Override
public void run() {
scrollTimerCallback(e);
}
};
timer.schedule(task, 0, SCROLL_INTERVAL);
}
}
/**
* Dispatches a mouse drag event that updates the mouse location by the
* amount that the canvas has been scrolled.
*
* @param dragX
* @param dragY
*/
private void dispatchDragEvent(double dragX, double dragY) {
int x = (int) (mouseX + dragX);
int y = (int) (mouseY + dragY);
MouseEvent mouseDragEvent = new MouseEvent(eventIdentifier,
MOUSE_DRAGGED, currentTimeMillis(), BUTTON1_DOWN_MASK, x, y, 1,
false, BUTTON1);
svgCanvas.dispatchEvent(mouseDragEvent);
}
@Override
public void mouseReleased(MouseEvent e) {
if (!finished) {
finished = true;
scrollX = 0;
scrollY = 0;
if (task != null)
task.cancel();
}
}
@Override
public void mouseDragged(MouseEvent e) {
// ignore events generated by this class
if (!finished && e.getSource() != eventIdentifier) {
mouseX = e.getX();
mouseY = e.getY();
int minX = BORDER;
int maxX = canvasSize.width - BORDER;
int minY = BORDER;
int maxY = canvasSize.height - BORDER;
scrollX = (mouseX < minX) ? (minX - mouseX)
: (mouseX > maxX) ? (maxX - mouseX) : 0;
scrollY = (mouseY < minY) ? (minY - mouseY)
: (mouseY > maxY) ? (maxY - mouseY) : 0;
}
}
private void scrollTimerCallback(MouseEvent e) {
double x = scrollX;
double y = scrollY;
if (x == 0 && y == 0)
return;
JGVTComponent c = (JGVTComponent) e.getSource();
AffineTransform rt = (AffineTransform) c.getRenderingTransform()
.clone();
double currentTranslateX = rt.getTranslateX();
double currentTranslateY = rt.getTranslateY();
// the tranlation that will show the east edge
double maxTranslateX = -((canvasSize.width * rt.getScaleX()) - canvasSize.width);
// the translation that will show the south
double maxTranslateY = -((canvasSize.height * rt.getScaleY()) - canvasSize.height);
if (x > 0 && currentTranslateX + x > 0)
// scroll left && not at west edge
x = -currentTranslateX;
else if (x < 0 && currentTranslateX + x < maxTranslateX)
// scroll right && not at east edge
x = maxTranslateX - currentTranslateX;
if (y > 0 && currentTranslateY + y > 0)
// scroll up && not at north edge
y = -currentTranslateY;
else if (y < 0 && currentTranslateY + y < maxTranslateY)
// scroll down && not at south edge
y = maxTranslateY - currentTranslateY;
if (x != 0d || y != 0d) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
rt.preConcatenate(at);
c.setRenderingTransform(rt);
dispatchDragEvent(x, y);
}
}
}