/*
* RectangleTool.java
*
* Created on April 8, 2005, 2:47 PM
*/
package ika.map.tools;
import ika.geo.RenderParams;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import ika.gui.MapComponent;
import ika.gui.SelectionBox;
/**
* RectangleTool - an abstract tool that draws a rectangle when dragging the mouse.
* @author Bernhard Jenny, Institute of Cartography, ETH Zurich.
*/
public abstract class RectangleTool extends DoubleBufferedTool {
/**
* The start position of the drag.
*/
protected Point2D.Double dragStartPos;
/**
* The current position of the drag.
*/
protected Point2D.Double dragCurrentPos;
/**
* The dash length used for drawing the rectangle with dashes.
*/
protected static final int DASH_LENGTH = 3;
/**
* MIN_RECT_DIM_PX is used by isRectangleLargeEnough to test whether
* the currently drawn rectangle is considered to be large enough.
* E.g. with the magnifier tool, if the user only draws a rectangle of
* 1x1 pixel, the view will not zoom to such a small area, which would
* be confusing.
* Unit: screen pixel
*/
protected static final int MIN_RECT_DIM_PX = 3;
/**
* Create a new instance.
* @param mapComponent The MapComponent for which this MapTool provides its services.
*/
protected RectangleTool(MapComponent mapComponent) {
super(mapComponent);
}
/**
* The mouse starts a drag, while this MapTool was the active one.
* @param point The location of the mouse in world coordinates.
* @param evt The original event.
*/
public void startDrag(Point2D.Double point, MouseEvent evt) {
dragStartPos = (Point2D.Double)point.clone();
}
/**
* The mouse location changed during a drag, while this MapTool was the active one.
* @param point The location of the mouse in world coordinates.
* @param evt The original event.
*/
@Override
public void updateDrag(Point2D.Double point, MouseEvent evt) {
// just in case we didn't get a mousePressed-Event
if (dragStartPos == null) {
dragStartPos = (Point2D.Double)point.clone();
return;
}
// if this is the first time mouseDragged is called, capture the screen.
if (dragCurrentPos == null) {
captureBackground();
}
dragCurrentPos = (Point2D.Double)point.clone();
mapComponent.repaint();
}
/**
* A drag ends, while this MapTool was the active one.
* @param point The location of the mouse in world coordinates.
* @param evt The original event.
*/
@Override
public void endDrag(Point2D.Double point, MouseEvent evt) {
// release the corner points of the drag rectangle
this.dragStartPos = this.dragCurrentPos = null;
releaseBackground();
mapComponent.repaint();
}
/**
* Returns whether the tool is currently dragging.
*/
@Override
public boolean isDragging() {
return dragStartPos != null;
}
/**
* The mouse was clicked, while this MapTool was the active one.
* @param point The location of the mouse in world coordinates.
* @param evt The original event.
*/
@Override
public void mouseClicked(Point2D.Double point, MouseEvent evt) {
this.dragStartPos = this.dragCurrentPos = null;
releaseBackground();
mapComponent.repaint();
}
/**
* Treat escape key events. Stop drawing the rectangle and revert to the
* previous state, without doing anything.
* The event can be consumed (return true) or be delegated to other
* listeners (return false).
* @param keyEvent The new key event.
* @return True if the key event has been consumed, false otherwise.
*/
@Override
public boolean keyEvent(KeyEvent keyEvent) {
final boolean keyReleased = keyEvent.getID() == KeyEvent.KEY_RELEASED;
final boolean isEscapeKey = keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE;
if (keyReleased && isEscapeKey) {
// release the corner points of the drag rectangle
this.dragStartPos = this.dragCurrentPos = null;
// repaint the map
releaseBackground();
mapComponent.repaint();
}
return false;
}
/**
* Draw the interface elements of this MapTool.
* @param rp The destination to draw to.
*/
@Override
public void draw(RenderParams rp) {
if (dragStartPos == null || dragCurrentPos == null) {
return;
}
SelectionBox.drawRectangle(getRectangle(), rp, false, DASH_LENGTH);
}
/**
* Returns the rectangle formed by the start location and the current drag location.
* @return The rectangle.
*/
protected Rectangle2D.Double getRectangle() {
if (dragStartPos == null || dragCurrentPos == null) {
return null;
}
final double x = Math.min(dragStartPos.getX(), dragCurrentPos.getX());
final double y = Math.min(dragStartPos.getY(), dragCurrentPos.getY());
final double w = Math.abs(dragCurrentPos.getX()-dragStartPos.getX());
final double h = Math.abs(dragCurrentPos.getY()-dragStartPos.getY());
return new Rectangle2D.Double(x, y, w, h);
}
/**
* Returns whether the the currently drawn rectangle is considered to be large enough.
* E.g. with the magnifier tool, if the user only draws a rectangle of
* 1x1 pixel, the view will not zoom to such a small area, which would
* be confusing.
*/
protected boolean isRectangleLargeEnough() {
final Rectangle2D.Double rect = this.getRectangle();
if (rect == null) {
return false;
}
final double minRectDim = MIN_RECT_DIM_PX / this.mapComponent.getScaleFactor();
return (rect.width >= minRectDim && rect.height >= minRectDim);
}
}