All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jhotdraw8.draw.tool.SimpleDragTracker Maven / Gradle / Ivy

The newest version!
/*
 * @(#)SimpleDragTracker.java
 * Copyright © 2023 The authors and contributors of JHotDraw. MIT License.
 */
package org.jhotdraw8.draw.tool;

import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import org.jspecify.annotations.Nullable;
import org.jhotdraw8.base.util.MathUtil;
import org.jhotdraw8.draw.DrawingView;
import org.jhotdraw8.draw.css.value.CssPoint2D;
import org.jhotdraw8.draw.figure.AnchorableFigure;
import org.jhotdraw8.draw.figure.Figure;
import org.jhotdraw8.draw.model.DrawingModel;
import org.jhotdraw8.fxbase.undo.CompositeEdit;
import org.jhotdraw8.graph.iterator.BfsDfsVertexSpliterator;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.StreamSupport;

import static org.jhotdraw8.draw.handle.MoveHandle.translateFigure;

/**
 * |@code SimpleDragTracker} implements interactions with the content area of a
 * {@code Figure}.
 * 

* The {@code DefaultDragTracker} handles one of the three states of the * {@code SelectionTool}. It comes into action, when the user presses the mouse * button over the content area of a {@code Figure}. *

* Design pattern:
* Name: Chain of Responsibility.
* Role: Handler.
* Partners: {@link SelectionTool} as Handler, {@link SelectAreaTracker} as * Handler, {@link HandleTracker} as Handler. *

* Design pattern:
* Name: State.
* Role: State.
* Partners: {@link SelectAreaTracker} as State, {@link SelectionTool} as * Context, {@link HandleTracker} as State. * * @author Werner Randelshofer * @see SelectionTool */ public class SimpleDragTracker extends AbstractTracker implements DragTracker { private @Nullable Set

groupReshapeableFigures; private @Nullable Figure anchorFigure; private @Nullable CssPoint2D oldPoint; private @Nullable CssPoint2D anchor; private @Nullable CompositeEdit undoableEdit; public SimpleDragTracker() { } // --- // Behaviors // --- @Override public void setDraggedFigure(Figure anchor, DrawingView view) { this.anchorFigure = anchor; // Determine which figures can be reshaped together as a group. Set
selectedFigures = view.getSelectedFigures(); groupReshapeableFigures = new HashSet<>(); for (Figure f : selectedFigures) { if (f.isGroupReshapeableWith(selectedFigures)) { groupReshapeableFigures.add(f); } } } private boolean dependsOn(final Figure f, final Set
others) { return StreamSupport.stream(new BfsDfsVertexSpliterator<>(Figure::getLayoutSubjects, f, false), false) .anyMatch(fg -> (fg != f) && others.contains(fg) || (fg.getParent() != null && containsAny(others, fg.getParent().getPath()))); } private boolean containsAny(Collection subject, Collection c) { for (E e : c) { if (subject.contains(e)) { return true; } } return false; } @Override public void trackMousePressed(MouseEvent event, DrawingView view) { stopCompositeEdit(view); oldPoint = anchor = view.getConstrainer().constrainPoint(anchorFigure, new CssPoint2D(view.viewToWorld(new Point2D(event.getX(), event.getY())))); } @Override public void trackMouseReleased(MouseEvent event, DrawingView dv) { dv.recreateHandles(); stopCompositeEdit(dv); } @Override public void trackMouseClicked(MouseEvent event, DrawingView dv) { stopCompositeEdit(dv); } @Override public void trackMouseDragged(MouseEvent event, DrawingView view) { startCompositeEdit(view); CssPoint2D newPoint = new CssPoint2D(view.viewToWorld(new Point2D(event.getX(), event.getY()))); if (!event.isAltDown() && !event.isControlDown()) { // alt or control turns the constrainer off newPoint = view.getConstrainer().constrainPoint(anchorFigure, newPoint); } if (event.isMetaDown()) { // meta snaps the top left corner of the anchor figure to the grid // or whatever corner is specified in the anchor Bounds bounds = anchorFigure.getLayoutBounds(); double anchorX = MathUtil.clamp(anchorFigure.getNonNull(AnchorableFigure.ANCHOR_X), 0, 1); double anchorY = MathUtil.clamp(anchorFigure.getNonNull(AnchorableFigure.ANCHOR_Y), 0, 1); Point2D loc = new Point2D(bounds.getMinX() + anchorX * bounds.getWidth(), bounds.getMinY() + anchorY * bounds.getHeight()); oldPoint = new CssPoint2D(anchorFigure.localToWorld(loc)); } if (newPoint.equals(oldPoint)) { return; } DrawingModel model = view.getModel(); if (event.isShiftDown()) { // shift transforms only the anchor figure Figure f = anchorFigure; translateFigure(f, oldPoint, newPoint, model); } else { for (Figure f : groupReshapeableFigures) { translateFigure(f, oldPoint, newPoint, model); } } oldPoint = newPoint; } @Override public void trackKeyPressed(KeyEvent event, DrawingView view) { CssPoint2D translate = null; if (event.getEventType() == KeyEvent.KEY_PRESSED) { translate = switch (event.getCode()) { case UP -> new CssPoint2D(0, -1); case DOWN -> new CssPoint2D(0, 1); case LEFT -> new CssPoint2D(-1, 0); case RIGHT -> new CssPoint2D(1, 0); default -> null; }; } if (translate != null) { event.consume(); DrawingModel model = view.getModel(); for (Figure f : view.getSelectedFigures()) { model.translateInParent(f, translate); } } } @Override public void trackKeyReleased(KeyEvent event, DrawingView view) { } @Override public void trackKeyTyped(KeyEvent event, DrawingView view) { } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy