jfxtras.labs.util.event.MouseControlUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jfxtras-labs Show documentation
Show all versions of jfxtras-labs Show documentation
Experimental components for JavaFX 2
/**
* MouseControlUtil.java
*
* Copyright (c) 2011-2014, JFXtras
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the organization nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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.
*/
package jfxtras.labs.util.event;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Rectangle;
import jfxtras.labs.scene.control.window.SelectableNode;
import jfxtras.labs.util.NodeUtil;
import jfxtras.labs.util.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);
}
/**
* 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) {
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);
}
// public static void makeResizable(Node n) {
//
// }
private static void _makeDraggable(
final Node n,
EventHandlerGroup dragHandler,
EventHandlerGroup pressHandler) {
DraggingControllerImpl draggingController =
new DraggingControllerImpl();
draggingController.apply(n, dragHandler, pressHandler);
}
}
class DraggingControllerImpl {
private double nodeX;
private double nodeY;
private double mouseX;
private double mouseY;
private EventHandler mouseDraggedEventHandler;
private EventHandler mousePressedEventHandler;
public DraggingControllerImpl() {
//
}
public void apply(Node n,
EventHandlerGroup draggedEvtHandler,
EventHandlerGroup pressedEvtHandler) {
init(n);
draggedEvtHandler.addHandler(mouseDraggedEventHandler);
pressedEvtHandler.addHandler(mousePressedEventHandler);
}
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 = nodeX * 1 / parentScaleX;
double 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();
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;
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) {
final double parentScaleX = root.
localToSceneTransformProperty().getValue().getMxx();
final double parentScaleY = root.
localToSceneTransformProperty().getValue().getMyy();
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);
rectangle.setY(y / parentScaleY);
rectangle.setWidth(width / parentScaleX);
rectangle.setHeight(height / parentScaleY);
}
public void performDragBegin(
Parent root, MouseEvent event) {
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.setX(firstX);
rectangle.setY(firstY);
rectangle.toFront();
}
public void performDragEnd(
Parent root, MouseEvent event) {
NodeUtil.removeFromParent(rectangle);
for (Node n : root.getChildrenUnmodifiable()) {
if (rectangle.intersects(n.getBoundsInParent()) && n instanceof SelectableNode) {
WindowUtil.getDefaultClipboard().select((SelectableNode) n, true);
}
}
}
}