/*
* 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.support;
import com.bc.ceres.swing.figure.AbstractHandle;
import com.bc.ceres.swing.figure.Figure;
import com.bc.ceres.swing.figure.FigureStyle;
import java.awt.Cursor;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* A {@link com.bc.ceres.swing.figure.Handle Handle} that can be used to scale figures.
*
* @author Norman Fomferra
* @since Ceres 0.10
*/
public class ScaleHandle extends AbstractHandle {
public final static int E = 0;
public final static int NE = 1;
public final static int N = 2;
public final static int NW = 3;
public final static int W = 4;
public final static int SW = 5;
public final static int S = 6;
public final static int SE = 7;
private final static int[] OPPONENT_INDEX = {
W, // opponent of E
SW, // opponent of NE
S, // opponent of N
SE, // opponent of NW
E, // opponent of W
NE, // opponent of SW
N, // opponent of S
NW, // opponent of SE
};
private final static int[] CURSOR_TYPES = {
Cursor.E_RESIZE_CURSOR,
Cursor.NE_RESIZE_CURSOR,
Cursor.N_RESIZE_CURSOR,
Cursor.NW_RESIZE_CURSOR,
Cursor.W_RESIZE_CURSOR,
Cursor.SW_RESIZE_CURSOR,
Cursor.S_RESIZE_CURSOR,
Cursor.SE_RESIZE_CURSOR,
};
private final static Point2D[] DIRECTIONS = {
new Point2D.Double(+1.0, 0.0),
new Point2D.Double(+1.0, +1.0),
new Point2D.Double(0.0, +1.0),
new Point2D.Double(-1.0, +1.0),
new Point2D.Double(-1.0, 0.0),
new Point2D.Double(-1.0, -1.0),
new Point2D.Double(0.0, -1.0),
new Point2D.Double(+1.0, -1.0),
};
private final static Point2D[] POSITIONS = {
new Point2D.Double(1.0, 0.5),
new Point2D.Double(1.0, 0.0),
new Point2D.Double(0.5, 0.0),
new Point2D.Double(0.0, 0.0),
new Point2D.Double(0.0, 0.5),
new Point2D.Double(0.0, 1.0),
new Point2D.Double(0.5, 1.0),
new Point2D.Double(1.0, 1.0),
};
private final int type;
public ScaleHandle(Figure figure,
int type, double dx, double dy,
FigureStyle style) {
super(figure, style, style);
this.type = type;
setShape(createHandleShape(dx, dy));
updateLocation();
}
@Override
public void updateLocation() {
Point2D.Double point = getRefPoint(type);
setLocation(point.getX(), point.getY());
}
@Override
public void move(double dx, double dy) {
setLocation(getX() + dx, getY() + dy);
dx *= DIRECTIONS[type].getX();
dy *= -DIRECTIONS[type].getY();
Rectangle2D bounds = getFigure().getBounds();
double w = bounds.getWidth();
double h = bounds.getHeight();
double sx = (w + dx) / w;
double sy = (h + dy) / h;
getFigure().scale(getRefPoint(OPPONENT_INDEX[type]), sx, sy);
}
@Override
public Cursor getCursor() {
double rotation = 0.0; // todo - derive rotation angle
if (rotation == 0.0) {
return Cursor.getPredefinedCursor(CURSOR_TYPES[type]);
} else {
final Point2D direction = DIRECTIONS[type];
// todo - rotate "direction" by "rotation"
double a = Math.atan2(direction.getY(), direction.getX());
if (a < 0.0) {
a = 2.0 * Math.PI - a;
}
final double b = 0.5 * a / Math.PI;
final double n = CURSOR_TYPES.length;
final double c = n * b + 0.5 * (1.0 / n);
int index = (int) c;
if (index >= CURSOR_TYPES.length) {
index = CURSOR_TYPES.length - 1;
}
return Cursor.getPredefinedCursor(CURSOR_TYPES[index]);
}
}
private Point2D.Double getRefPoint() {
return getRefPoint(type);
}
private Point2D.Double getRefPoint(int type) {
final Rectangle2D bounds = getFigure().getBounds();
final double x = bounds.getX();
final double y = bounds.getY();
final double w = bounds.getWidth();
final double h = bounds.getHeight();
return new Point2D.Double(x + POSITIONS[type].getX() * w,
y + POSITIONS[type].getY() * h);
}
private static Shape createHandleShape(double dx, double dy) {
return new Rectangle2D.Double(dx - 0.5 * StyleDefaults.SCALE_HANDLE_SIZE,
dy - 0.5 * StyleDefaults.SCALE_HANDLE_SIZE,
StyleDefaults.SCALE_HANDLE_SIZE,
StyleDefaults.SCALE_HANDLE_SIZE);
}
}