package com.kreative.paint.tool;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.ListIterator;
import java.util.Map;
import com.kreative.paint.Layer;
import com.kreative.paint.document.draw.DrawObject;
import com.kreative.paint.document.draw.DrawSurface;
import com.kreative.paint.document.undo.Atom;
import com.kreative.paint.util.CursorUtils;
public class TransformTool extends AbstractPaintDrawSelectionTool {
private static final int K = 0xFF000000;
private static final int A = 0xFF808080;
private static final int W = 0xFFFFFFFF;
private static final Image icon = ToolUtilities.makeIcon(
16, 16,
new int[] {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,K,K,K,0,0,0,K,K,K,0,0,0,K,K,K,
0,K,0,K,0,K,0,K,0,K,0,K,0,K,0,K,
0,K,K,K,0,0,0,K,K,K,0,0,0,K,K,K,
0,0,0,0,0,0,K,0,0,0,0,0,0,0,0,0,
0,0,K,0,0,0,K,K,0,0,0,0,0,0,K,0,
0,0,0,0,0,0,K,K,K,0,0,0,0,0,0,0,
0,K,K,K,0,0,K,K,K,K,0,0,0,K,K,K,
0,K,0,K,0,0,K,K,K,K,K,0,0,K,0,K,
0,K,K,K,0,0,K,K,K,K,K,K,0,K,K,K,
0,0,0,0,0,0,K,K,0,0,0,0,0,0,0,0,
0,0,K,0,0,0,K,0,0,0,0,0,0,0,K,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,K,K,K,0,0,0,K,K,K,0,0,0,K,K,K,
0,K,0,K,0,K,0,K,0,K,0,K,0,K,0,K,
0,K,K,K,0,0,0,K,K,K,0,0,0,K,K,K,
}
);
private static final Cursor rotate_cursor = CursorUtils.makeCursor(
17, 15,
new int[] {
0,0,0,0,0,0,0,W,W,W,W,W,0,0,0,0,0,
0,0,0,0,0,W,W,K,K,K,K,K,W,W,0,0,0,
0,0,0,0,W,K,K,W,W,W,W,W,K,K,W,0,0,
0,0,0,W,K,W,W,0,0,0,0,0,W,W,K,W,0,
0,0,0,W,K,W,0,0,0,0,0,0,0,W,K,W,0,
0,W,W,K,W,W,0,0,0,0,0,0,0,0,W,K,W,
W,K,W,K,W,K,W,0,0,0,0,0,0,0,W,K,W,
0,W,K,K,K,W,0,0,0,0,0,0,0,0,W,K,W,
0,W,K,K,K,W,0,0,0,0,0,0,0,0,W,K,W,
0,0,W,K,W,0,0,0,0,0,0,0,0,0,W,K,W,
0,0,W,K,W,0,0,0,0,0,0,0,0,W,K,W,0,
0,0,0,W,0,0,0,0,0,0,0,0,W,W,K,W,0,
0,0,0,0,0,0,0,0,0,W,W,W,K,K,W,0,0,
0,0,0,0,0,0,0,0,0,W,K,K,W,W,0,0,0,
0,0,0,0,0,0,0,0,0,W,W,W,0,0,0,0,0,
},
9, 7,
"Rotate"
);
public static final Cursor half_arrow_gray = CursorUtils.makeCursor(
16, 16,
new int[] {
W,W,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
W,A,W,0,0,0,0,0,0,0,0,0,0,0,0,0,
W,A,A,W,0,0,0,0,0,0,0,0,0,0,0,0,
W,A,A,A,W,0,0,0,0,0,0,0,0,0,0,0,
W,A,A,A,A,W,0,0,0,0,0,0,0,0,0,0,
W,A,A,A,A,A,W,0,0,0,0,0,0,0,0,0,
W,A,A,A,A,A,A,W,0,0,0,0,0,0,0,0,
W,A,A,A,A,A,A,A,W,0,0,0,0,0,0,0,
W,A,A,A,A,A,A,A,A,W,0,0,0,0,0,0,
W,A,A,A,W,W,W,W,W,W,W,0,0,0,0,0,
W,A,A,W,0,0,0,0,0,0,0,0,0,0,0,0,
W,A,W,0,0,0,0,0,0,0,0,0,0,0,0,0,
W,W,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
W,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
},
1, 1,
"HalfArrowGray"
);
protected Image getBWIcon() {
return icon;
}
public boolean toolSelected(ToolEvent e) {
e.beginTransaction(getName());
if (isSelection(e)) pop(e);
else reset(e);
e.commitTransaction();
return true;
}
public boolean toolDeselected(ToolEvent e) {
e.beginTransaction(getName());
reset(e);
e.commitTransaction();
return true;
}
public boolean mouseEntered(ToolEvent e) {
if (!e.isMouseDown()) updateCursor(e);
return false;
}
public boolean mouseMoved(ToolEvent e) {
if (!e.isMouseDown()) updateCursor(e);
return false;
}
public boolean keyPressed(ToolEvent e) {
if (!e.isMouseDown()) updateCursor(e);
return false;
}
public boolean keyReleased(ToolEvent e) {
if (!e.isMouseDown()) updateCursor(e);
return false;
}
public boolean paintIntermediateUsesCanvasCoordinates() {
return true;
}
private int clickedArea = 0;
private boolean altDown = false;
private boolean definingSelection = false;
private boolean draggingSelection = false;
private AffineTransform dragTransform = null;
public boolean mousePressed(ToolEvent e) {
e.beginTransaction(getName());
if (isSelection(e)) update(e);
else reset(e);
updateCursor(e);
clickedArea = getCurrentArea(e);
altDown = e.isAltDown();
if (clickedArea == 0) {
reset(e);
updateCursor(e);
e.getCanvas().pushPaintSelection();
definingSelection = true;
draggingSelection = false;
dragTransform = null;
} else {
definingSelection = false;
draggingSelection = true;
dragTransform = AffineTransform.getTranslateInstance(0, 0);
if (clickedArea == 5 || clickedArea == 10) {
dragTransform.concatenate(translateTransform);
} else if (!altDown) {
dragTransform.concatenate(scaleTransform);
} else if (clickedArea == 2 || clickedArea == 4 || clickedArea == 6 || clickedArea == 8) {
dragTransform.concatenate(shearTransform);
} else {
dragTransform.concatenate(rotateTransform);
}
}
return true;
}
private void doDragTransform(ToolEvent e) {
Point2D vc = getVisibleCenter();
AffineTransform tx = AffineTransform.getTranslateInstance(0, 0);
tx.concatenate(dragTransform);
if (clickedArea == 5 || clickedArea == 10) {
tx.translate(e.getCanvasX()-e.getCanvasPreviousClickedX(), e.getCanvasY()-e.getCanvasPreviousClickedY());
} else if (!altDown) {
if (clickedArea == 2 || clickedArea == 8) {
tx.scale(1.0, Math.abs(e.getCanvasY()-vc.getY())/Math.abs(e.getCanvasPreviousClickedY()-vc.getY()));
} else if (clickedArea == 4 || clickedArea == 6) {
tx.scale(Math.abs(e.getCanvasX()-vc.getX())/Math.abs(e.getCanvasPreviousClickedX()-vc.getX()), 1.0);
} else if (e.isShiftDown()) {
double sx = Math.abs(e.getCanvasX()-vc.getX())/Math.abs(e.getCanvasPreviousClickedX()-vc.getX());
double sy = Math.abs(e.getCanvasY()-vc.getY())/Math.abs(e.getCanvasPreviousClickedY()-vc.getY());
double s = (sx+sy)/2.0;
tx.scale(s, s);
} else {
double sx = Math.abs(e.getCanvasX()-vc.getX())/Math.abs(e.getCanvasPreviousClickedX()-vc.getX());
double sy = Math.abs(e.getCanvasY()-vc.getY())/Math.abs(e.getCanvasPreviousClickedY()-vc.getY());
tx.scale(sx, sy);
}
} else if (clickedArea == 2) {
tx.shear((e.getCanvasPreviousClickedX()-e.getCanvasX())*1.8/baseRect.getWidth(), 0.0);
} else if (clickedArea == 8) {
tx.shear((e.getCanvasX()-e.getCanvasPreviousClickedX())*1.8/baseRect.getWidth(), 0.0);
} else if (clickedArea == 4) {
tx.shear(0.0, (e.getCanvasPreviousClickedY()-e.getCanvasY())*1.8/baseRect.getHeight());
} else if (clickedArea == 6) {
tx.shear(0.0, (e.getCanvasY()-e.getCanvasPreviousClickedY())*1.8/baseRect.getHeight());
} else {
double a = Math.atan2(e.getCanvasPreviousClickedY()-vc.getY(), e.getCanvasPreviousClickedX()-vc.getX());
double b = Math.atan2(e.getCanvasY()-vc.getY(), e.getCanvasX()-vc.getX());
tx.rotate(b-a);
}
if (clickedArea == 5 || clickedArea == 10) {
if (e.getHistory() != null) e.getHistory().add(new TranslateTransformAtom(this, tx));
translateTransform = tx;
} else if (!altDown) {
if (e.getHistory() != null) e.getHistory().add(new ScaleTransformAtom(this, tx));
scaleTransform = tx;
} else if (clickedArea == 2 || clickedArea == 4 || clickedArea == 6 || clickedArea == 8) {
if (e.getHistory() != null) e.getHistory().add(new ShearTransformAtom(this, tx));
shearTransform = tx;
} else {
if (e.getHistory() != null) e.getHistory().add(new RotateTransformAtom(this, tx));
rotateTransform = tx;
}
}
public boolean mouseDragged(ToolEvent e) {
if (draggingSelection) {
doDragTransform(e);
push(e);
return true;
} else {
return false;
}
}
public boolean mouseReleased(ToolEvent e) {
if (definingSelection) {
Shape s = new Rectangle2D.Float(
Math.min(e.getCanvasX(),e.getCanvasPreviousClickedX()),
Math.min(e.getCanvasY(),e.getCanvasPreviousClickedY()),
Math.abs(e.getCanvasX()-e.getCanvasPreviousClickedX()),
Math.abs(e.getCanvasY()-e.getCanvasPreviousClickedY())
);
Rectangle2D r = new Rectangle2D.Float(
Math.min(e.getX(),e.getPreviousClickedX()),
Math.min(e.getY(),e.getPreviousClickedY()),
Math.abs(e.getX()-e.getPreviousClickedX()),
Math.abs(e.getY()-e.getPreviousClickedY())
);
if (e.isCtrlDown() && e.isAltDown()) e.getCanvas().xorPaintSelection(s);
else if (e.isCtrlDown()) e.getCanvas().addPaintSelection(s);
else if (e.isAltDown()) e.getCanvas().subtractPaintSelection(s);
else e.getCanvas().setPaintSelection(s);
e.getCanvas().pushPaintSelection();
DrawSurface d = e.getDrawSurface();
Point2D.Float p = new Point2D.Float(e.getX(), e.getY());
if (r.isEmpty()) {
if (e.isCtrlDown() && e.isAltDown()) {
ListIterator<DrawObject> oi = d.listIterator(d.size());
while (oi.hasPrevious()) {
DrawObject o = oi.previous();
if (o.contains(p)) {
o.setSelected(!o.isSelected());
break;
}
}
} else if (e.isCtrlDown()) {
ListIterator<DrawObject> oi = d.listIterator(d.size());
while (oi.hasPrevious()) {
DrawObject o = oi.previous();
if (o.contains(p)) {
o.setSelected(true);
break;
}
}
} else if (e.isAltDown()) {
ListIterator<DrawObject> oi = d.listIterator(d.size());
while (oi.hasPrevious()) {
DrawObject o = oi.previous();
if (o.contains(p)) {
o.setSelected(false);
break;
}
}
} else {
for (DrawObject o : d) {
o.setSelected(o.contains(p));
}
}
} else {
if (e.isCtrlDown() && e.isAltDown()) {
for (DrawObject o : d) {
if (o.intersects(r)) {
o.setSelected(!o.isSelected());
}
}
} else if (e.isCtrlDown()) {
for (DrawObject o : d) {
if (o.intersects(r)) {
o.setSelected(true);
}
}
} else if (e.isAltDown()) {
for (DrawObject o : d) {
if (o.intersects(r)) {
o.setSelected(false);
}
}
} else {
for (DrawObject o : d) {
o.setSelected(o.intersects(r));
}
}
}
if (isSelection(e)) pop(e);
else reset(e);
} else if (draggingSelection) {
doDragTransform(e);
push(e);
}
dragTransform = null;
definingSelection = false;
draggingSelection = false;
clickedArea = 0;
altDown = false;
updateCursor(e);
e.commitTransaction();
return true;
}
public boolean paintIntermediate(ToolEvent e, Graphics2D g) {
drawTransformRect(g);
if (definingSelection) {
ToolUtilities.fillSelectionShape(e, g, new Rectangle2D.Float(
Math.min(e.getCanvasX(),e.getCanvasPreviousClickedX()),
Math.min(e.getCanvasY(),e.getCanvasPreviousClickedY()),
Math.abs(e.getCanvasX()-e.getCanvasPreviousClickedX()),
Math.abs(e.getCanvasY()-e.getCanvasPreviousClickedY())
));
}
return true;
}
public boolean respondsToCommand(ToolEvent e) {
switch (e.getCommand()) {
case SELECT_ALL:
case DESELECT_ALL:
case INVERT_SELECTION:
return true;
default:
return false;
}
}
public boolean enableCommand(ToolEvent e) {
switch (e.getCommand()) {
case SELECT_ALL:
case DESELECT_ALL:
case INVERT_SELECTION:
return true;
default:
return false;
}
}
public boolean doCommand(ToolEvent e) {
switch (e.getCommand()) {
case SELECT_ALL:
e.beginTransaction(ToolUtilities.messages.getString("marquee.SelectAll"));
reset(e);
e.getCanvas().pushPaintSelection();
e.getCanvas().setPaintSelection(new Rectangle(0, 0, e.getCanvas().getWidth(), e.getCanvas().getHeight()));
e.getCanvas().pushPaintSelection();
for (DrawObject o : e.getDrawSurface()) {
o.setSelected(true);
}
if (isSelection(e)) pop(e);
else reset(e);
e.commitTransaction();
return true;
case DESELECT_ALL:
e.beginTransaction(ToolUtilities.messages.getString("marquee.DeselectAll"));
reset(e);
e.getCanvas().clearPaintSelection();
for (DrawObject o : e.getDrawSurface()) {
o.setSelected(false);
}
if (isSelection(e)) pop(e);
else reset(e);
e.commitTransaction();
return true;
case INVERT_SELECTION:
e.beginTransaction(ToolUtilities.messages.getString("marquee.InvertSelection"));
reset(e);
e.getCanvas().pushPaintSelection();
Area invertSelection = new Area(new Rectangle(0, 0, e.getCanvas().getWidth(), e.getCanvas().getHeight()));
invertSelection.exclusiveOr(new Area(e.getCanvas().getPaintSelection()));
e.getCanvas().setPaintSelection(invertSelection);
e.getCanvas().pushPaintSelection();
for (DrawObject o : e.getDrawSurface()) {
o.setSelected(!o.isSelected());
}
if (isSelection(e)) pop(e);
else reset(e);
e.commitTransaction();
return true;
default:
return false;
}
}
private void updateCursor(ToolEvent e) {
switch (getCurrentArea(e)) {
case 0: setCursor(CursorUtils.CURSOR_SELECT); break;
case 1: setCursor(e.isAltDown() ? rotate_cursor : Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)); break;
case 2: setCursor(e.isAltDown() ? half_arrow_gray : Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); break;
case 3: setCursor(e.isAltDown() ? rotate_cursor : Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)); break;
case 4: setCursor(e.isAltDown() ? half_arrow_gray : Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); break;
case 5: setCursor(CursorUtils.CURSOR_MOVE); break;
case 6: setCursor(e.isAltDown() ? half_arrow_gray : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); break;
case 7: setCursor(e.isAltDown() ? rotate_cursor : Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)); break;
case 8: setCursor(e.isAltDown() ? half_arrow_gray : Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)); break;
case 9: setCursor(e.isAltDown() ? rotate_cursor : Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)); break;
case 10: setCursor(CursorUtils.CURSOR_MOVE); break;
}
}
private Cursor cursor = CursorUtils.CURSOR_SELECT;
private void setCursor(Cursor c) {
if (cursor != c) {
cursor = c;
}
}
public Cursor getCursor(ToolEvent e) {
return cursor;
}
// - - - BEGIN PRIVATE INTERFACE - - - //
private static final Color BOUNDS_COLOR = new Color(0x8000BB00);
private static final Color HANDLE_COLOR = new Color(0xFF00BB00);
private static final BasicStroke BH_STROKE = new BasicStroke(1);
private static final Composite BH_COMPOSITE = AlphaComposite.SrcOver;
private Shape basePaintSelection = null;
private Shape baseClip = null;
private AffineTransform basePoppedImageTransform = null;
private Map<DrawObject,AffineTransform> baseObjectTransform = new HashMap<DrawObject,AffineTransform>();
private Rectangle2D baseRect = null;
private AffineTransform baseRectTransform = null;
private AffineTransform scaleTransform = null;
private AffineTransform shearTransform = null;
private AffineTransform rotateTransform = null;
private AffineTransform translateTransform = null;
private boolean isSelection(ToolEvent e) {
if (e.getCanvas().getPaintSelection() != null) return true;
for (DrawObject o : e.getDrawSurface()) {
if (o.isSelected() && !o.isLocked()) {
return true;
}
}
return false;
}
private void reset(ToolEvent e) {
basePaintSelection = null;
baseClip = null;
basePoppedImageTransform = null;
baseObjectTransform.clear();
if (e != null && e.getHistory() != null) e.getHistory().add(new BaseRectAtom(this, null, null));
baseRect = null;
baseRectTransform = null;
if (e != null && e.getHistory() != null) e.getHistory().add(new NullTransformAtom(this));
scaleTransform = null;
shearTransform = null;
rotateTransform = null;
translateTransform = null;
}
private void update(ToolEvent e) {
if (e.getCanvas().getPaintSelection() != null && !e.getCanvas().isPaintSelectionPopped()) {
pop(e);
}
}
private void pop(ToolEvent e) {
if (e.getCanvas().getPaintSelection() != null && !e.getCanvas().isPaintSelectionPopped()) {
e.getCanvas().popPaintSelection(false, false);
}
basePaintSelection = e.getCanvas().getPaintSelection();
baseClip = e.getLayer().getClip();
basePoppedImageTransform = e.getLayer().getPoppedImageTransform();
baseObjectTransform.clear();
for (DrawObject o : e.getDrawSurface()) {
if (o.isSelected() && !o.isLocked()) {
baseObjectTransform.put(o, o.getTransform());
}
}
if (basePaintSelection != null) {
if (basePoppedImageTransform != null) {
Rectangle2D br = new Rectangle(0, 0, e.getLayer().getPoppedImage().getWidth(), e.getLayer().getPoppedImage().getHeight());
AffineTransform brt = AffineTransform.getTranslateInstance(0, 0);
brt.translate(e.getLayer().getX(), e.getLayer().getY());
brt.concatenate(basePoppedImageTransform);
if (e.getHistory() != null) e.getHistory().add(new BaseRectAtom(this, br, brt));
baseRect = br;
baseRectTransform = brt;
} else {
Rectangle2D br = basePaintSelection.getBounds2D();
AffineTransform brt = AffineTransform.getTranslateInstance(0, 0);
if (e.getHistory() != null) e.getHistory().add(new BaseRectAtom(this, br, brt));
baseRect = br;
baseRectTransform = brt;
}
} else {
if (baseObjectTransform.size() == 1) {
DrawObject o = baseObjectTransform.keySet().iterator().next();
AffineTransform otx = o.getTransform();
o.setTransform(AffineTransform.getTranslateInstance(0, 0));
Rectangle2D br = o.getBounds2D();
o.setTransform(otx);
AffineTransform brt = AffineTransform.getTranslateInstance(0, 0);
brt.translate(e.getLayer().getX(), e.getLayer().getY());
if (otx != null) brt.concatenate(otx);
if (e.getHistory() != null) e.getHistory().add(new BaseRectAtom(this, br, brt));
baseRect = br;
baseRectTransform = brt;
} else {
float minX = Float.POSITIVE_INFINITY;
float minY = Float.POSITIVE_INFINITY;
float maxX = Float.NEGATIVE_INFINITY;
float maxY = Float.NEGATIVE_INFINITY;
for (DrawObject o : baseObjectTransform.keySet()) {
Rectangle2D ob = o.getBounds2D();
if (ob.getMinX() < minX) minX = (float)ob.getMinX();
if (ob.getMinY() < minY) minY = (float)ob.getMinY();
if (ob.getMaxX() > maxX) maxX = (float)ob.getMaxX();
if (ob.getMaxY() > maxY) maxY = (float)ob.getMaxY();
}
if (Float.isInfinite(minX) || Float.isInfinite(maxX) || Float.isInfinite(minY) || Float.isInfinite(maxY)) {
if (e.getHistory() != null) e.getHistory().add(new BaseRectAtom(this, null, null));
baseRect = null;
baseRectTransform = null;
} else {
Rectangle2D br = new Rectangle2D.Float(minX, minY, maxX-minX, maxY-minY);
AffineTransform brt = AffineTransform.getTranslateInstance(0, 0);
brt.translate(e.getLayer().getX(), e.getLayer().getY());
if (e.getHistory() != null) e.getHistory().add(new BaseRectAtom(this, br, brt));
baseRect = br;
baseRectTransform = brt;
}
}
}
if (e.getHistory() != null) e.getHistory().add(new BaseTransformAtom(this));
scaleTransform = AffineTransform.getTranslateInstance(0, 0);
shearTransform = AffineTransform.getTranslateInstance(0, 0);
rotateTransform = AffineTransform.getTranslateInstance(0, 0);
translateTransform = AffineTransform.getTranslateInstance(0, 0);
}
private AffineTransform accumulateTransform(Layer l, AffineTransform base) {
AffineTransform btx = AffineTransform.getTranslateInstance(0, 0);
/* - - - - PART I - UN-LAYER - - - - */
if (l != null) btx.translate(-l.getX(), -l.getY());
/* - - - - PART II - UN-BASERECT - - - - */
btx.concatenate(baseRectTransform);
btx.translate(baseRect.getCenterX(), baseRect.getCenterY());
/* - - - - PART III - DRAG TRANSFORM - - - - */
if (translateTransform != null) btx.concatenate(translateTransform);
if (rotateTransform != null) btx.concatenate(rotateTransform);
if (scaleTransform != null) btx.concatenate(scaleTransform);
if (shearTransform != null) btx.concatenate(shearTransform);
/* - - - - PART VI - BASERECT - - - - */
btx.translate(-baseRect.getCenterX(), -baseRect.getCenterY());
try {
btx.concatenate(baseRectTransform.createInverse());
} catch (NoninvertibleTransformException e) {
Rectangle2D brx = baseRectTransform.createTransformedShape(baseRect).getBounds2D();
btx.translate(-brx.getCenterX(), -brx.getCenterY());
}
/* - - - - PART V - LAYER - - - - */
if (l != null) btx.translate(l.getX(), l.getY());
/* - - - - PART VI - BASE - - - - */
if (base != null) btx.concatenate(base);
return btx;
}
private void push(ToolEvent e) {
if (basePaintSelection != null) {
e.getCanvas().setPaintSelection(accumulateTransform(null, null).createTransformedShape(basePaintSelection));
}
if (baseClip != null) {
e.getLayer().setClip(accumulateTransform(e.getLayer(), null).createTransformedShape(baseClip));
}
if (basePoppedImageTransform != null) {
e.getLayer().setPoppedImage(e.getLayer().getPoppedImage(), accumulateTransform(e.getLayer(), basePoppedImageTransform));
}
for (Map.Entry<DrawObject,AffineTransform> entry : baseObjectTransform.entrySet()) {
entry.getKey().setTransform(accumulateTransform(e.getLayer(), entry.getValue()));
}
}
private int getCurrentArea(ToolEvent e) {
if (baseRect != null && baseRectTransform != null) {
AffineTransform btx = accumulateTransform(null, baseRectTransform);
Shape s;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMinX()-5.0, baseRect.getMinY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 1;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getCenterX()-5.0, baseRect.getMinY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 2;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMaxX()-5.0, baseRect.getMinY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 3;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMinX()-5.0, baseRect.getCenterY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 4;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getCenterX()-5.0, baseRect.getCenterY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 5;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMaxX()-5.0, baseRect.getCenterY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 6;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMinX()-5.0, baseRect.getMaxY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 7;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getCenterX()-5.0, baseRect.getMaxY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 8;
s = (btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMaxX()-5.0, baseRect.getMaxY()-5.0, 10.0, 10.0)));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 9;
s = (btx.createTransformedShape(baseRect));
if (s.contains(e.getCanvasX(), e.getCanvasY())) return 10;
return 0;
} else {
return 0;
}
}
private void drawTransformRect(Graphics2D g) {
if (baseRect != null && baseRectTransform != null) {
AffineTransform btx = accumulateTransform(null, baseRectTransform);
g.setStroke(BH_STROKE);
g.setComposite(BH_COMPOSITE);
g.setPaint(BOUNDS_COLOR);
g.draw(btx.createTransformedShape(baseRect));
g.setPaint(HANDLE_COLOR);
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMinX()-3.0, baseRect.getMinY()-3.0, 6.0, 6.0)));
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getCenterX()-3.0, baseRect.getMinY()-3.0, 6.0, 6.0)));
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMaxX()-3.0, baseRect.getMinY()-3.0, 6.0, 6.0)));
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMinX()-3.0, baseRect.getCenterY()-3.0, 6.0, 6.0)));
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getCenterX()-3.0, baseRect.getCenterY()-3.0, 6.0, 6.0)));
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMaxX()-3.0, baseRect.getCenterY()-3.0, 6.0, 6.0)));
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMinX()-3.0, baseRect.getMaxY()-3.0, 6.0, 6.0)));
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getCenterX()-3.0, baseRect.getMaxY()-3.0, 6.0, 6.0)));
g.draw(btx.createTransformedShape(new Rectangle2D.Double(baseRect.getMaxX()-3.0, baseRect.getMaxY()-3.0, 6.0, 6.0)));
}
}
private Point2D getVisibleCenter() {
Point2D p = new Point2D.Double(baseRect.getCenterX(), baseRect.getCenterY());
baseRectTransform.transform(p, p);
translateTransform.transform(p, p);
return p;
}
private static class BaseRectAtom implements Atom {
private TransformTool tt;
private Rectangle2D oldBR;
private AffineTransform oldBRT;
private Rectangle2D newBR;
private AffineTransform newBRT;
public BaseRectAtom(TransformTool tt, Rectangle2D newBR, AffineTransform newBRT) {
this.tt = tt;
this.oldBR = tt.baseRect;
this.oldBRT = tt.baseRectTransform;
this.newBR = newBR;
this.newBRT = newBRT;
}
public Atom buildUpon(Atom previousAtom) {
this.oldBR = ((BaseRectAtom)previousAtom).oldBR;
this.oldBRT = ((BaseRectAtom)previousAtom).oldBRT;
return this;
}
public boolean canBuildUpon(Atom previousAtom) {
return (previousAtom instanceof BaseRectAtom) && (((BaseRectAtom)previousAtom).tt == this.tt);
}
public void redo() {
tt.baseRect = newBR;
tt.baseRectTransform = newBRT;
}
public void undo() {
tt.baseRect = oldBR;
tt.baseRectTransform = newBRT;
}
}
private static class NullTransformAtom implements Atom {
private TransformTool tt;
private AffineTransform oldScale;
private AffineTransform oldShear;
private AffineTransform oldRotate;
private AffineTransform oldTrans;
public NullTransformAtom(TransformTool tt) {
this.tt = tt;
this.oldScale = tt.scaleTransform;
this.oldShear = tt.shearTransform;
this.oldRotate = tt.rotateTransform;
this.oldTrans = tt.translateTransform;
}
public Atom buildUpon(Atom previousAtom) {
this.oldScale = ((NullTransformAtom)previousAtom).oldScale;
this.oldShear = ((NullTransformAtom)previousAtom).oldShear;
this.oldRotate = ((NullTransformAtom)previousAtom).oldRotate;
this.oldTrans = ((NullTransformAtom)previousAtom).oldTrans;
return this;
}
public boolean canBuildUpon(Atom previousAtom) {
return (previousAtom instanceof NullTransformAtom) && (((NullTransformAtom)previousAtom).tt == this.tt);
}
public void redo() {
tt.scaleTransform = null;
tt.shearTransform = null;
tt.rotateTransform = null;
tt.translateTransform = null;
}
public void undo() {
tt.scaleTransform = oldScale;
tt.shearTransform = oldShear;
tt.rotateTransform = oldRotate;
tt.translateTransform = oldTrans;
}
}
private static class BaseTransformAtom implements Atom {
private TransformTool tt;
private AffineTransform oldScale;
private AffineTransform oldShear;
private AffineTransform oldRotate;
private AffineTransform oldTrans;
public BaseTransformAtom(TransformTool tt) {
this.tt = tt;
this.oldScale = tt.scaleTransform;
this.oldShear = tt.shearTransform;
this.oldRotate = tt.rotateTransform;
this.oldTrans = tt.translateTransform;
}
public Atom buildUpon(Atom previousAtom) {
this.oldScale = ((BaseTransformAtom)previousAtom).oldScale;
this.oldShear = ((BaseTransformAtom)previousAtom).oldShear;
this.oldRotate = ((BaseTransformAtom)previousAtom).oldRotate;
this.oldTrans = ((BaseTransformAtom)previousAtom).oldTrans;
return this;
}
public boolean canBuildUpon(Atom previousAtom) {
return (previousAtom instanceof BaseTransformAtom) && (((BaseTransformAtom)previousAtom).tt == this.tt);
}
public void redo() {
tt.scaleTransform = AffineTransform.getTranslateInstance(0, 0);
tt.shearTransform = AffineTransform.getTranslateInstance(0, 0);
tt.rotateTransform = AffineTransform.getTranslateInstance(0, 0);
tt.translateTransform = AffineTransform.getTranslateInstance(0, 0);
}
public void undo() {
tt.scaleTransform = oldScale;
tt.shearTransform = oldShear;
tt.rotateTransform = oldRotate;
tt.translateTransform = oldTrans;
}
}
private static class ScaleTransformAtom implements Atom {
private TransformTool tt;
private AffineTransform oldtx;
private AffineTransform newtx;
public ScaleTransformAtom(TransformTool tt, AffineTransform newtx) {
this.tt = tt;
this.oldtx = tt.scaleTransform;
this.newtx = newtx;
}
public Atom buildUpon(Atom previousAtom) {
this.oldtx = ((ScaleTransformAtom)previousAtom).oldtx;
return this;
}
public boolean canBuildUpon(Atom previousAtom) {
return (previousAtom instanceof ScaleTransformAtom) && (((ScaleTransformAtom)previousAtom).tt == this.tt);
}
public void redo() {
tt.scaleTransform = newtx;
}
public void undo() {
tt.scaleTransform = oldtx;
}
}
private static class ShearTransformAtom implements Atom {
private TransformTool tt;
private AffineTransform oldtx;
private AffineTransform newtx;
public ShearTransformAtom(TransformTool tt, AffineTransform newtx) {
this.tt = tt;
this.oldtx = tt.shearTransform;
this.newtx = newtx;
}
public Atom buildUpon(Atom previousAtom) {
this.oldtx = ((ShearTransformAtom)previousAtom).oldtx;
return this;
}
public boolean canBuildUpon(Atom previousAtom) {
return (previousAtom instanceof ShearTransformAtom) && (((ShearTransformAtom)previousAtom).tt == this.tt);
}
public void redo() {
tt.shearTransform = newtx;
}
public void undo() {
tt.shearTransform = oldtx;
}
}
private static class RotateTransformAtom implements Atom {
private TransformTool tt;
private AffineTransform oldtx;
private AffineTransform newtx;
public RotateTransformAtom(TransformTool tt, AffineTransform newtx) {
this.tt = tt;
this.oldtx = tt.rotateTransform;
this.newtx = newtx;
}
public Atom buildUpon(Atom previousAtom) {
this.oldtx = ((RotateTransformAtom)previousAtom).oldtx;
return this;
}
public boolean canBuildUpon(Atom previousAtom) {
return (previousAtom instanceof RotateTransformAtom) && (((RotateTransformAtom)previousAtom).tt == this.tt);
}
public void redo() {
tt.rotateTransform = newtx;
}
public void undo() {
tt.rotateTransform = oldtx;
}
}
private static class TranslateTransformAtom implements Atom {
private TransformTool tt;
private AffineTransform oldtx;
private AffineTransform newtx;
public TranslateTransformAtom(TransformTool tt, AffineTransform newtx) {
this.tt = tt;
this.oldtx = tt.translateTransform;
this.newtx = newtx;
}
public Atom buildUpon(Atom previousAtom) {
this.oldtx = ((TranslateTransformAtom)previousAtom).oldtx;
return this;
}
public boolean canBuildUpon(Atom previousAtom) {
return (previousAtom instanceof TranslateTransformAtom) && (((TranslateTransformAtom)previousAtom).tt == this.tt);
}
public void redo() {
tt.translateTransform = newtx;
}
public void undo() {
tt.translateTransform = oldtx;
}
}
}