package org.dockfx;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class MouseDraggedTest extends Application implements EventHandler<MouseEvent> {
	private Stage mainStage;
	private StackPane root = new StackPane();
	private Button btn;
	
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
    	this.mainStage = primaryStage;
        primaryStage.setTitle("Hello World!");
        btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.addEventFilter(MouseEvent.ANY, this);
        
        root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    Stage floatingStage;
    Point2D dragLast;
    
	@Override
	public void handle(MouseEvent event) {
		if (event.getEventType() == MouseEvent.MOUSE_PRESSED) {
			dragLast = new Point2D(event.getScreenX(), event.getScreenY());
		} else if (event.getEventType() == MouseEvent.DRAG_DETECTED) {
			// ok let's remove the button and drag it out of the stage
			// into a new stage, after removing it from the root
			// of the old scene it stops receiving Event.ANY, ANY event
			// at all until the mouse is released
			root.getChildren().remove(btn);
			
			// this is the work around that uses the main stage
			// as a temporary listener but this is not ideal
			// uncomment to make the node perfectly draggable out
			// of the scene and thereafter
			//mainStage.addEventFilter(MouseEvent.ANY, this);
			
			// this seems quite evidently undesirable behavior as the node that
			// starts a drag event should continue to receive it until the end
			// or have a way of at least knowing that it was cancelled
			
			if (floatingStage != null) {
				return;
			}
			
			floatingStage = new Stage();
			floatingStage.initOwner(mainStage);
			
			floatingStage.setX(event.getScreenX());
			floatingStage.setY(event.getScreenY());
			
			StackPane stack = new StackPane();
			stack.getChildren().add(btn);
			
			floatingStage.setScene(new Scene(stack));
			
			floatingStage.show();
		} else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) {
			if (floatingStage == null) return;
			
			// this is not reached unless we *temporarily* use the
			// old stage as a listener because the button
			// will not receive MOUSE_DRAGGED again until it's old
			// stage/scene receive a MOUSE_RELEASED

			floatingStage.setX(floatingStage.getX() + (event.getScreenX() - dragLast.getX()));
			floatingStage.setY(floatingStage.getY() + (event.getScreenY() - dragLast.getY()));
			
			dragLast = new Point2D(event.getScreenX(), event.getScreenY());
		}
	}
}
