/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ /* * @(#)BezierControlPointHandle.java 2.0 2008-05-12 * * Copyright (c) 1996-2008 by the original authors of JHotDraw * and all its contributors. * All rights reserved. * * The copyright of this software is owned by the authors and * contributors of the JHotDraw project ("the copyright holders"). * You may not use, copy or modify this software, except in * accordance with the license agreement you entered into with * the copyright holders. For details see accompanying license terms. */ package org.jhotdraw.draw; import org.jhotdraw.util.*; import org.jhotdraw.undo.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.util.*; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import org.jhotdraw.geom.*; import static org.jhotdraw.samples.svg.SVGAttributeKeys.*; /** * BezierControlPointHandle. * * @author Werner Randelshofer * @version 2.0 2008-05-11 Handle attributes are now retrieved from * DrawingEditor. Added keyPressed method. * <br>1.0 23. Januar 2006 Created. */ public class BezierControlPointHandle extends AbstractHandle { protected int index, controlPointIndex; private CompositeEdit edit; private Figure transformOwner; private BezierPath.Node oldNode; /** Creates a new instance. */ public BezierControlPointHandle(BezierFigure owner, int index, int coord) { this(owner, index, coord, owner); } public BezierControlPointHandle(BezierFigure owner, int index, int coord, Figure transformOwner) { super(owner); this.index = index; this.controlPointIndex = coord; this.transformOwner = transformOwner; transformOwner.addFigureListener(this); } public void dispose() { super.dispose(); transformOwner.removeFigureListener(this); transformOwner = null; } protected BezierFigure getBezierFigure() { return (BezierFigure) getOwner(); } protected Figure getTransformOwner() { return transformOwner; } protected Point getLocation() { if (getBezierFigure().getNodeCount() > index) { Point2D.Double p = getBezierFigure().getPoint(index, controlPointIndex); if (TRANSFORM.get(getTransformOwner()) != null) { TRANSFORM.get(getTransformOwner()).transform(p, p); } return view.drawingToView(p); } else { return new Point(10, 10); } } protected BezierPath.Node getBezierNode() { return getBezierFigure().getNodeCount() > index ? getBezierFigure().getNode(index) : null; } /** * Draws this handle. */ public void draw(Graphics2D g) { BezierFigure f = getBezierFigure(); if (f.getNodeCount() > index) { BezierPath.Node v = f.getNode(index); Point2D.Double p0 = new Point2D.Double(v.x[0], v.y[0]); Point2D.Double pc = new Point2D.Double(v.x[controlPointIndex], v.y[controlPointIndex]); if (TRANSFORM.get(getTransformOwner()) != null) { TRANSFORM.get(getTransformOwner()).transform(p0, p0); TRANSFORM.get(getTransformOwner()).transform(pc, pc); } Color handleFillColor; Color handleStrokeColor; Stroke stroke1; Color strokeColor1; Stroke stroke2; Color strokeColor2; if (getEditor().getTool().supportsHandleInteraction()) { handleFillColor = (Color) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_CONTROL_POINT_HANDLE_FILL_COLOR); handleStrokeColor = (Color) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_CONTROL_POINT_HANDLE_STROKE_COLOR); stroke1 = (Stroke) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_TANGENT_STROKE_1); strokeColor1 = (Color) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_TANGENT_COLOR_1); stroke2 = (Stroke) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_TANGENT_STROKE_2); strokeColor2 = (Color) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_TANGENT_COLOR_2); } else { handleFillColor = (Color) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_CONTROL_POINT_HANDLE_FILL_COLOR_DISABLED); handleStrokeColor = (Color) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_CONTROL_POINT_HANDLE_STROKE_COLOR_DISABLED); stroke1 = (Stroke) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_TANGENT_STROKE_1_DISABLED); strokeColor1 = (Color) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_TANGENT_COLOR_1_DISABLED); stroke2 = (Stroke) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_TANGENT_STROKE_2_DISABLED); strokeColor2 = (Color) getEditor().getHandleAttribute(HandleAttributeKeys.BEZIER_TANGENT_COLOR_2_DISABLED); } if (stroke1 != null && strokeColor1 != null) { g.setStroke(stroke1); g.setColor(strokeColor1); g.draw(new Line2D.Double( view.drawingToView(p0), view.drawingToView(pc))); } if (stroke2 != null && strokeColor2 != null) { g.setStroke(stroke2); g.setColor(strokeColor2); g.draw(new Line2D.Double( view.drawingToView(p0), view.drawingToView(pc))); } if (v.keepColinear && v.mask == BezierPath.C1C2_MASK && (index > 0 && index < f.getNodeCount() - 1 || f.isClosed())) { drawCircle(g, handleStrokeColor, handleFillColor); } else { drawCircle(g, handleFillColor, handleStrokeColor); } } } protected Rectangle basicGetBounds() { Rectangle r = new Rectangle(getLocation()); int h = getHandlesize(); r.x -= h / 2; r.y -= h / 2; r.width = r.height = h; return r; } public void trackStart(Point anchor, int modifiersEx) { BezierFigure figure = getOwner(); view.getDrawing().fireUndoableEditHappened(edit = new CompositeEdit("Punkt verschieben")); Point2D.Double location = view.getConstrainer().constrainPoint(view.viewToDrawing(getLocation())); Point2D.Double p = view.getConstrainer().constrainPoint(view.viewToDrawing(anchor)); oldNode = figure.getNode(index); } public void trackStep(Point anchor, Point lead, int modifiersEx) { BezierFigure figure = getBezierFigure(); Point2D.Double p = view.getConstrainer().constrainPoint(view.viewToDrawing(lead)); BezierPath.Node v = figure.getNode(index); fireAreaInvalidated(v); figure.willChange(); if (TRANSFORM.get(getTransformOwner()) != null) { try { TRANSFORM.get(getTransformOwner()).inverseTransform(p, p); } catch (NoninvertibleTransformException ex) { ex.printStackTrace(); } } if (!v.keepColinear) { // move control point independently figure.setPoint(index, controlPointIndex, p); } else { // move control point and opposite control point on same line double a = Math.PI + Math.atan2(p.y - v.y[0], p.x - v.x[0]); int c2 = (controlPointIndex == 1) ? 2 : 1; double r = Math.sqrt((v.x[c2] - v.x[0]) * (v.x[c2] - v.x[0]) + (v.y[c2] - v.y[0]) * (v.y[c2] - v.y[0])); double sina = Math.sin(a); double cosa = Math.cos(a); Point2D.Double p2 = new Point2D.Double( r * cosa + v.x[0], r * sina + v.y[0]); figure.setPoint(index, controlPointIndex, p); figure.setPoint(index, c2, p2); } figure.changed(); fireAreaInvalidated(figure.getNode(index)); } private void fireAreaInvalidated(BezierPath.Node v) { Rectangle2D.Double dr = new Rectangle2D.Double(v.x[0], v.y[0], 0, 0); for (int i = 1; i < 3; i++) { dr.add(v.x[i], v.y[i]); } Rectangle vr = view.drawingToView(dr); vr.grow(getHandlesize(), getHandlesize()); fireAreaInvalidated(vr); } public void trackEnd(Point anchor, Point lead, int modifiersEx) { final BezierFigure figure = getBezierFigure(); BezierPath.Node oldValue = (BezierPath.Node) oldNode.clone(); BezierPath.Node newValue = figure.getNode(index); if ((modifiersEx & (InputEvent.META_DOWN_MASK | InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)) != 0) { figure.willChange(); newValue.keepColinear = !newValue.keepColinear; if (newValue.keepColinear) { // move control point and opposite control point on same line Point2D.Double p = figure.getPoint(index, controlPointIndex); double a = Math.PI + Math.atan2(p.y - newValue.y[0], p.x - newValue.x[0]); int c2 = (controlPointIndex == 1) ? 2 : 1; double r = Math.sqrt((newValue.x[c2] - newValue.x[0]) * (newValue.x[c2] - newValue.x[0]) + (newValue.y[c2] - newValue.y[0]) * (newValue.y[c2] - newValue.y[0])); double sina = Math.sin(a); double cosa = Math.cos(a); Point2D.Double p2 = new Point2D.Double( r * cosa + newValue.x[0], r * sina + newValue.y[0]); newValue.x[c2] = p2.x; newValue.y[c2] = p2.y; } figure.setNode(index, newValue); figure.changed(); } view.getDrawing().fireUndoableEditHappened(new BezierNodeEdit(figure, index, oldValue, newValue) { @Override public void redo() throws CannotRedoException { super.redo(); fireHandleRequestSecondaryHandles(); } @Override public void undo() throws CannotUndoException { super.undo(); fireHandleRequestSecondaryHandles(); } }); view.getDrawing().fireUndoableEditHappened(edit); } @Override public boolean isCombinableWith(Handle h) { if (super.isCombinableWith(h)) { BezierControlPointHandle that = (BezierControlPointHandle) h; return that.index == this.index && that.controlPointIndex == this.controlPointIndex && that.getBezierFigure().getNodeCount() == this.getBezierFigure().getNodeCount(); } return false; } @Override public String getToolTipText(Point p) { ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels"); BezierPath.Node node = getBezierNode(); if (node == null) { return null; } if (node.mask == BezierPath.C1C2_MASK) { return labels.getFormatted("handle.bezierControlPoint.toolTipText", labels.getFormatted( node.keepColinear ? "handle.bezierControlPoint.cubicColinear.value" : "handle.bezierControlPoint.cubicUnconstrained.value")); } else { return labels.getString("handle.bezierControlPoint.quadratic.toolTipText"); } } public BezierFigure getOwner() { return (BezierFigure) super.getOwner(); } public void keyPressed(KeyEvent evt) { final BezierFigure f = getOwner(); BezierPath.Node oldNode = f.getNode(index); switch (evt.getKeyCode()) { case KeyEvent.VK_UP: f.willChange(); f.setPoint(index, controlPointIndex, new Point2D.Double(oldNode.x[controlPointIndex], oldNode.y[controlPointIndex] - 1d)); f.changed(); view.getDrawing().fireUndoableEditHappened(new BezierNodeEdit(f, index, oldNode, f.getNode(index))); evt.consume(); break; case KeyEvent.VK_DOWN: f.willChange(); f.setPoint(index, controlPointIndex, new Point2D.Double(oldNode.x[controlPointIndex], oldNode.y[controlPointIndex] + 1d)); f.changed(); view.getDrawing().fireUndoableEditHappened(new BezierNodeEdit(f, index, oldNode, f.getNode(index))); evt.consume(); break; case KeyEvent.VK_LEFT: f.willChange(); f.setPoint(index, controlPointIndex, new Point2D.Double(oldNode.x[controlPointIndex] - 1d, oldNode.y[controlPointIndex])); f.changed(); view.getDrawing().fireUndoableEditHappened(new BezierNodeEdit(f, index, oldNode, f.getNode(index))); evt.consume(); break; case KeyEvent.VK_RIGHT: f.willChange(); f.setPoint(index, controlPointIndex, new Point2D.Double(oldNode.x[controlPointIndex] + 1d, oldNode.y[controlPointIndex])); f.changed(); view.getDrawing().fireUndoableEditHappened(new BezierNodeEdit(f, index, oldNode, f.getNode(index))); evt.consume(); break; case KeyEvent.VK_DELETE: case KeyEvent.VK_BACK_SPACE: evt.consume(); break; } } }