/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package com.bc.ceres.swing.figure;
import com.bc.ceres.grender.Rendering;
import com.bc.ceres.grender.Viewport;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* The base class for all {@link Handle} implementations.
*
* @author Norman Fomferra
* @since Ceres 0.10
*/
public abstract class AbstractHandle extends AbstractFigure implements Handle {
private final Figure figure;
private final FigureChangeListener listener;
private final Point2D.Double location;
private Shape shape;
/**
* Constructor.
*
* @param figure The figure to which this handle belongs.
* @param normalStyle The handle's normal style.
* @param selectedStyle The handle's selected style.
*/
protected AbstractHandle(Figure figure,
FigureStyle normalStyle,
FigureStyle selectedStyle) {
super(normalStyle, selectedStyle);
setSelectable(true);
this.figure = figure;
this.listener = new FigureChangeListener() {
@Override
public void figureChanged(FigureChangeEvent e) {
updateLocation();
}
};
this.figure.addChangeListener(listener);
this.location = new Point2D.Double();
}
public double getX() {
return location.x;
}
public double getY() {
return location.y;
}
@Override
public boolean isCollection() {
return false;
}
@Override
public Point2D getLocation() {
return (Point2D) location.clone();
}
public void setLocation(Point2D location) {
setLocation(location.getX(), location.getY());
}
public void setLocation(double x, double y) {
location.setLocation(x, y);
}
public abstract void updateLocation();
/**
* @return The figure to which this handle belongs.
*/
public Figure getFigure() {
return figure;
}
@Override
public Rank getRank() {
return Rank.AREA;
}
@Override
public Shape getShape() {
return shape;
}
@Override
public void setShape(Shape shape) {
this.shape = shape;
}
@Override
public Rectangle2D getBounds() {
return shape.getBounds2D();
}
/**
* The default implementation returns {@code true}.
*
* @return Always {@code true}.
*/
@Override
public boolean isSelectable() {
return true;
}
@Override
public boolean isCloseTo(Point2D point, AffineTransform m2v) {
Point2D delta = new Point2D.Double(point.getX() - location.getX(),
point.getY() - location.getY());
m2v.deltaTransform(delta, delta);
return getShape().contains(delta);
}
@Override
public void dispose() {
super.dispose();
figure.removeChangeListener(listener);
}
@Override
public Cursor getCursor() {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
}
@Override
public abstract void move(double dx, double dy);
@Override
public final void draw(Rendering rendering) {
final Graphics2D g = rendering.getGraphics();
final Viewport vp = rendering.getViewport();
final AffineTransform oldTransform = g.getTransform();
try {
AffineTransform m2v = vp.getModelToViewTransform();
Point2D transfLocation = m2v.transform(location, null);
AffineTransform newTransform = new AffineTransform(oldTransform);
newTransform.concatenate(
AffineTransform.getTranslateInstance(transfLocation.getX(), transfLocation.getY()));
g.setTransform(newTransform);
drawHandle(g);
} finally {
g.setTransform(oldTransform);
}
}
protected void drawHandle(Graphics2D g) {
FigureStyle handleStyle = getEffectiveStyle();
g.setPaint(handleStyle.getFillPaint());
g.fill(getShape());
g.setPaint(handleStyle.getStrokePaint());
g.setStroke(handleStyle.getStroke());
g.draw(getShape());
}
}