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

jfxtras.labs.util.event.MouseControlUtil Maven / Gradle / Ivy

There is a newer version: 0.2.5.0
Show newest version
/*
 * Copyright 2012-2016 Michael Hoffer . All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of
 *       conditions and the following disclaimer.
 *
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list
 *       of conditions and the following disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 *
 * Please cite the following publication(s):
 *
 * M. Hoffer, C.Poliwoda, G.Wittum. Visual Reflection Library -
 * A Framework for Declarative GUI Programming on the Java Platform.
 * Computing and Visualization in Science, 2011, in press.
 *
 * THIS SOFTWARE IS PROVIDED BY Michael Hoffer  "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Hoffer  OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of Michael Hoffer .
 */
package jfxtras.labs.util.event;

import java.util.ArrayList;
import java.util.List;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Rectangle;
import jfxtras.scene.control.window.NodeUtil;
import jfxtras.scene.control.window.SelectableNode;
import jfxtras.scene.control.window.WindowUtil;

/**
 * This is a utility class that provides methods for mouse gesture control.
 * Currently, it can be used to make nodes draggable.
 *
 * @author Michael Hoffer <[email protected]>
 */
public class MouseControlUtil {

    // no instanciation allowed
    private MouseControlUtil() {
        throw new AssertionError(); // not in this class either!
    }

    /**
     * Makes a node draggable via mouse gesture.
     *
     * 

* Note: Existing handlers will be replaced!

* * @param n the node that shall be made draggable */ public static void makeDraggable(final Node n) { makeDraggable(n, null, null, false); } /** * Makes a node draggable via mouse gesture. * *

* Note: Existing handlers will be replaced!

* * @param n the node that shall be made draggable */ public static void makeDraggable(final Node n, boolean centerNode) { makeDraggable(n, null, null); } /** * Adds a selection rectangle gesture to the specified parent node. * * A rectangle node must be specified that is used to indicate the selection * area. * *

* Note:

* * To support selection a node must implement the * {@link jfxtras.labs.scene.control.window.SelectableNode} interface. * * @param root parent node * @param rect selectionn rectangle * * @see jfxtras.labs.scene.control.window.Clipboard * @see jfxtras.labs.util.WindowUtil#getDefaultClipboard() */ public static void addSelectionRectangleGesture(final Parent root, final Rectangle rect) { addSelectionRectangleGesture(root, rect, null, null, null); } /** * Adds a selection rectangle gesture to the specified parent node. * * A rectangle node must be specified that is used to indicate the selection * area. * *

* Note:

* * To support selection a node must implement the * {@link jfxtras.labs.scene.control.window.SelectableNode} interface. * * @param root parent node * @param rect selectionn rectangle * @param dragHandler additional drag handler (optional, may be * null) * @param pressHandler additional press handler (optional, may be * null) * @param releaseHandler additional release handler (optional, may be * null) * * @see jfxtras.labs.scene.control.window.Clipboard * @see jfxtras.labs.util.WindowUtil#getDefaultClipboard() */ public static void addSelectionRectangleGesture( final Parent root, final Rectangle rect, EventHandler dragHandler, EventHandler pressHandler, EventHandler releaseHandler) { EventHandlerGroup dragHandlerGroup = new EventHandlerGroup<>(); EventHandlerGroup pressHandlerGroup = new EventHandlerGroup<>(); EventHandlerGroup releaseHandlerGroup = new EventHandlerGroup<>(); if (dragHandler != null) { dragHandlerGroup.addHandler(dragHandler); } if (pressHandler != null) { pressHandlerGroup.addHandler(pressHandler); } if (releaseHandler != null) { releaseHandlerGroup.addHandler(releaseHandler); } root.setOnMouseDragged(dragHandlerGroup); root.setOnMousePressed(pressHandlerGroup); root.setOnMouseReleased(releaseHandlerGroup); RectangleSelectionControllerImpl selectionHandler = new RectangleSelectionControllerImpl(); selectionHandler.apply(root, rect, dragHandlerGroup, pressHandlerGroup, releaseHandlerGroup); } /** * Makes a node draggable via mouse gesture. * *

* Note: Existing handlers will be replaced!

* * @param n the node that shall be made draggable * @param dragHandler additional drag handler * @param pressHandler additional press handler */ public static void makeDraggable(final Node n, EventHandler dragHandler, EventHandler pressHandler) { makeDraggable(n, dragHandler, pressHandler, false); } /** * Makes a node draggable via mouse gesture. * *

* Note: Existing handlers will be replaced!

* * @param n the node that shall be made draggable * @param dragHandler additional drag handler * @param pressHandler additional press handler */ public static void makeDraggable(final Node n, EventHandler dragHandler, EventHandler pressHandler, boolean centerNode) { EventHandlerGroup dragHandlerGroup = new EventHandlerGroup<>(); EventHandlerGroup pressHandlerGroup = new EventHandlerGroup<>(); if (dragHandler != null) { dragHandlerGroup.addHandler(dragHandler); } if (pressHandler != null) { pressHandlerGroup.addHandler(pressHandler); } n.setOnMouseDragged(dragHandlerGroup); n.setOnMousePressed(pressHandlerGroup); n.layoutXProperty().unbind(); n.layoutYProperty().unbind(); _makeDraggable(n, dragHandlerGroup, pressHandlerGroup, centerNode); } // public static void makeResizable(Node n) { // // } private static void _makeDraggable( final Node n, EventHandlerGroup dragHandler, EventHandlerGroup pressHandler, boolean centerNode) { DraggingControllerImpl draggingController = new DraggingControllerImpl(); draggingController.apply(n, dragHandler, pressHandler, centerNode); } } class DraggingControllerImpl { private double nodeX; private double nodeY; private double mouseX; private double mouseY; private EventHandler mouseDraggedEventHandler; private EventHandler mousePressedEventHandler; private boolean centerNode = false; public DraggingControllerImpl() { // } public void apply(Node n, EventHandlerGroup draggedEvtHandler, EventHandlerGroup pressedEvtHandler, boolean centerNode) { init(n); draggedEvtHandler.addHandler(mouseDraggedEventHandler); pressedEvtHandler.addHandler(mousePressedEventHandler); this.centerNode = centerNode; } private void init(final Node n) { mouseDraggedEventHandler = new EventHandler() { @Override public void handle(MouseEvent event) { performDrag(n, event); event.consume(); } }; mousePressedEventHandler = new EventHandler() { @Override public void handle(MouseEvent event) { performDragBegin(n, event); event.consume(); } }; } public void performDrag( Node n, MouseEvent event) { final double parentScaleX = n.getParent(). localToSceneTransformProperty().getValue().getMxx(); final double parentScaleY = n.getParent(). localToSceneTransformProperty().getValue().getMyy(); // Get the exact moved X and Y double offsetX = event.getSceneX() - mouseX; double offsetY = event.getSceneY() - mouseY; nodeX += offsetX; nodeY += offsetY; double scaledX; double scaledY; if (centerNode) { Point2D p2d = n.getParent().sceneToLocal(mouseX, mouseY); scaledX = p2d.getX(); scaledY = p2d.getY(); } else { scaledX = nodeX * 1 / (parentScaleX); scaledY = nodeY * 1 / (parentScaleY); } n.setLayoutX(scaledX); n.setLayoutY(scaledY); // again set current Mouse x AND y position mouseX = event.getSceneX(); mouseY = event.getSceneY(); } public void performDragBegin( Node n, MouseEvent event) { final double parentScaleX = n.getParent(). localToSceneTransformProperty().getValue().getMxx(); final double parentScaleY = n.getParent(). localToSceneTransformProperty().getValue().getMyy(); // record the current mouse X and Y position on Node mouseX = event.getSceneX(); mouseY = event.getSceneY(); if (centerNode) { Point2D p2d = n.getParent().sceneToLocal(mouseX, mouseY); nodeX = p2d.getX(); nodeY = p2d.getY(); } else { nodeX = n.getLayoutX() * parentScaleX; nodeY = n.getLayoutY() * parentScaleY; } n.toFront(); } } class RectangleSelectionControllerImpl { private Rectangle rectangle; private Parent root; private double nodeX; private double nodeY; private double firstX; private double firstY; private double secondX; private double secondY; private EventHandler mouseDraggedEventHandler; private EventHandler mousePressedHandler; private EventHandler mouseReleasedHandler; private final List selectedNodes = new ArrayList<>(); public RectangleSelectionControllerImpl() { // } public void apply(Parent root, Rectangle rect, EventHandlerGroup draggedEvtHandler, EventHandlerGroup pressedEvtHandler, EventHandlerGroup releasedEvtHandler) { init(root, rect); draggedEvtHandler.addHandler(mouseDraggedEventHandler); pressedEvtHandler.addHandler(mousePressedHandler); releasedEvtHandler.addHandler(mouseReleasedHandler); } private void init(final Parent root, final Rectangle rect) { this.rectangle = rect; this.root = root; // root.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler() { // @Override // public void handle(MouseEvent t) { // WindowUtil.getDefaultClipboard().unselectAll(); // } // }); mouseDraggedEventHandler = new EventHandler() { @Override public void handle(MouseEvent event) { performDrag(root, event); event.consume(); } }; mousePressedHandler = new EventHandler() { @Override public void handle(MouseEvent event) { performDragBegin(root, event); event.consume(); } }; mouseReleasedHandler = new EventHandler() { @Override public void handle(MouseEvent event) { performDragEnd(root, event); event.consume(); } }; } public void performDrag( Parent root, MouseEvent event) { rectangle.setVisible(true); final double parentScaleX = root. localToSceneTransformProperty().getValue().getMxx(); final double parentScaleY = root. localToSceneTransformProperty().getValue().getMyy(); final double translateX = -root. localToSceneTransformProperty().getValue().getTx(); final double translateY = -root. localToSceneTransformProperty().getValue().getTy(); secondX = event.getSceneX(); secondY = event.getSceneY(); firstX = Math.max(firstX, 0); firstY = Math.max(firstY, 0); secondX = Math.max(secondX, 0); secondY = Math.max(secondY, 0); double x = Math.min(firstX, secondX); double y = Math.min(firstY, secondY); double width = Math.abs(secondX - firstX); double height = Math.abs(secondY - firstY); rectangle.setX(x / parentScaleX + translateX / parentScaleX); rectangle.setY(y / parentScaleY + translateY / parentScaleY); rectangle.setWidth(width / parentScaleX); rectangle.setHeight(height / parentScaleY); selectIntersectingNodes(root, !event.isControlDown()); } private void selectIntersectingNodes(Parent root, boolean deselect) { List selectableNodes = root.getChildrenUnmodifiable(). filtered(n -> n instanceof SelectableNode); boolean rectBigEnough = rectangle.getWidth() > 1 || rectangle.getHeight() > 1; for (Node n : selectableNodes) { boolean selectN = rectangle.intersects( rectangle.parentToLocal( n.localToParent(n.getBoundsInLocal()))); SelectableNode sn = (SelectableNode) n; if ((deselect || potentiallySelected(sn)) || (selectN && rectBigEnough)) { WindowUtil.getDefaultClipboard().select( sn, (selectN && rectBigEnough)); } } } public void performDragBegin( Parent root, MouseEvent event) { selectedNodes.addAll( WindowUtil.getDefaultClipboard().getSelectedItems()); if (rectangle.getParent() != null) { return; } // record the current mouse X and Y position on Node firstX = event.getSceneX(); firstY = event.getSceneY(); NodeUtil.addToParent(root, rectangle); rectangle.setWidth(0); rectangle.setHeight(0); rectangle.toFront(); rectangle.setVisible(false); } public void performDragEnd( Parent root, MouseEvent event) { if (rectangle.getParent() != null) { selectIntersectingNodes(root, !event.isControlDown()); NodeUtil.removeFromParent(rectangle); } selectedNodes.clear(); } private boolean potentiallySelected(SelectableNode sn) { return !selectedNodes.contains(sn) && WindowUtil.getDefaultClipboard(). getSelectedItems().contains(sn); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy