@Override public void drag(MouseEvent e, Dimension delta) { if (invalidGesture) { return; } if (selectionBounds == null) { return; } Rectangle sel = updateSelectionBounds(e); for (IContentPart<Node, ? extends Node> targetPart : targetParts) { // compute initial and new bounds for this target Bounds initialBounds = getBounds(selectionBounds, targetPart); Bounds newBounds = getBounds(sel, targetPart); // compute translation in scene coordinates double dx = newBounds.getMinX() - initialBounds.getMinX(); double dy = newBounds.getMinY() - initialBounds.getMinY(); // transform translation to parent coordinates Node visual = targetPart.getVisual(); Point2D originInParent = visual.getParent().sceneToLocal(0, 0); Point2D deltaInParent = visual.getParent().sceneToLocal(dx, dy); dx = deltaInParent.getX() - originInParent.getX(); dy = deltaInParent.getY() - originInParent.getY(); // apply translation getTransformPolicy(targetPart).setPostTranslate(translateIndices.get(targetPart), dx, dy); // check if we can resize the part AffineTransform affineTransform = getTransformPolicy(targetPart).getCurrentNodeTransform(); if (affineTransform.getRotation().equals(Angle.fromDeg(0))) { // no rotation => resize possible // TODO: special case 90 degree rotations double dw = newBounds.getWidth() - initialBounds.getWidth(); double dh = newBounds.getHeight() - initialBounds.getHeight(); Point2D originInLocal = visual.sceneToLocal(newBounds.getMinX(), newBounds.getMinY()); Point2D dstInLocal = visual.sceneToLocal(newBounds.getMinX() + dw, newBounds.getMinY() + dh); dw = dstInLocal.getX() - originInLocal.getX(); dh = dstInLocal.getY() - originInLocal.getY(); getResizePolicy(targetPart).resize(dw, dh); } else { // compute scaling based on bounds change double sx = newBounds.getWidth() / initialBounds.getWidth(); double sy = newBounds.getHeight() / initialBounds.getHeight(); // apply scaling getTransformPolicy(targetPart).setPostScale(scaleIndices.get(targetPart), sx, sy); } } }
@Override public IUndoableOperation commit() { final IUndoableOperation updateVisualOperation = super.commit(); if (updateVisualOperation == null) { return null; } // commit changes to model final FXGeometricShapePart host = getHost(); final FXGeometricShape hostContent = host.getContent(); // determine transformation @SuppressWarnings("serial") Provider<Affine> affineProvider = host.getAdapter( AdapterKey.<Provider<? extends Affine>>get( new TypeToken<Provider<? extends Affine>>() {}, FXTransformPolicy.TRANSFORMATION_PROVIDER_ROLE)); AffineTransform tx = JavaFX2Geometry.toAffineTransform(affineProvider.get()); final AffineTransform oldTransform = hostContent.getTransform(); final AffineTransform newTransform = new AffineTransform( tx.getM00(), tx.getM10(), tx.getM01(), tx.getM11(), tx.getTranslateX(), tx.getTranslateY()); // create operation to write the changes to the model final IUndoableOperation updateModelOperation = new AbstractOperation("Update Model") { @Override public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { hostContent.setTransform(newTransform); return Status.OK_STATUS; } @Override public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { return execute(monitor, info); } @Override public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { hostContent.setTransform(oldTransform); return Status.OK_STATUS; } }; // compose operations IUndoableOperation compositeOperation = new ForwardUndoCompositeOperation(updateVisualOperation.getLabel()) { { add(updateVisualOperation); add(updateModelOperation); } }; return compositeOperation; }