Skip to content

Commit

Permalink
Adds Dragging and Dropping Steps in the Pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
JLLeitschuh committed May 9, 2016
1 parent 880cc48 commit 087c8c3
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 67 deletions.
37 changes: 30 additions & 7 deletions core/src/main/java/edu/wpi/grip/core/Pipeline.java
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,13 @@ public void onSourceRemoved(SourceRemovedEvent event) {
}

/**
* Adds the step between two other steps.
* @param stepToAdd The step to add to the pipeline
* @param lower The step to be added above
* @param higher The step to be added below
* Finds the index between the two steps
* @param lower The lower step
* @param higher The higher step
* @return The index that is in between the two of these steps
*/
public void addStepBetween(Step stepToAdd, @Nullable Step lower, @Nullable Step higher) {
checkNotNull(stepToAdd, "The step to add cannot be null");
int index = readStepsSafely(steps -> {
private int indexBetween(@Nullable Step lower, @Nullable Step higher) {
return readStepsSafely(steps -> {
// If not in the list these can return -1
int lowerIndex = steps.indexOf(lower);
int upperIndex = steps.indexOf(higher);
Expand All @@ -259,9 +258,33 @@ public void addStepBetween(Step stepToAdd, @Nullable Step lower, @Nullable Step
return steps.size();
}
});
}

/**
* Adds the step between two other steps.
* @param stepToAdd The step to add to the pipeline
* @param lower The step to be added above
* @param higher The step to be added below
*/
public void addStepBetween(Step stepToAdd, @Nullable Step lower, @Nullable Step higher) {
checkNotNull(stepToAdd, "The step to add cannot be null");
final int index = indexBetween(lower, higher);
addStep(index, stepToAdd);
}

/**
*
* @param toMove The step to move
* @param lower The lower step
* @param higher The upper step
*/
public void moveStepBetween(Step toMove, @Nullable Step lower, @Nullable Step higher) {
checkNotNull(toMove, "The step to move cannot be null");
final int index = indexBetween(lower, higher);
final int currentIndex = readStepsSafely(steps -> steps.indexOf(toMove));
moveStep(toMove, index > currentIndex ? index - (currentIndex + 1 ) : index - currentIndex);
}

public void addStep(int index, Step step) {
checkNotNull(step, "The step can not be null");
checkArgument(!step.removed(), "The step must not have been disabled already");
Expand Down
30 changes: 30 additions & 0 deletions core/src/test/java/edu/wpi/grip/core/PipelineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,34 @@ public void testAddBetweenStepsOutOfOrder() {

pipeline.addStepBetween(stepToAdd, upperStep, lowerStep);
}

@Test
public void testMoveStepToLeft() {
final Step
stepToMove = new MockStep(),
lowerStep = new MockStep(),
upperStep = new MockStep();
pipeline.addStep(lowerStep);
pipeline.addStep(upperStep);
pipeline.addStep(stepToMove);
pipeline.moveStepBetween(stepToMove, lowerStep, upperStep);

assertEquals("The step should have been moved within the pipeline",
Arrays.asList(lowerStep, stepToMove, upperStep), pipeline.getSteps());
}

@Test
public void testMoveStepToRight() {
final Step
stepToMove = new MockStep(),
lowerStep = new MockStep(),
upperStep = new MockStep();
pipeline.addStep(stepToMove);
pipeline.addStep(lowerStep);
pipeline.addStep(upperStep);
pipeline.moveStepBetween(stepToMove, lowerStep, upperStep);

assertEquals("The step should have been moved within the pipeline",
Arrays.asList(lowerStep, stepToMove, upperStep), pipeline.getSteps());
}
}
19 changes: 5 additions & 14 deletions ui/src/main/java/edu/wpi/grip/ui/OperationController.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,8 @@
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.GridPane;

import java.util.Collections;

/**
* A JavaFX control that renders information about an {@link Operation}. This is used in the palette view to present
* the user with information on the various operations to choose from.
Expand Down Expand Up @@ -76,19 +71,15 @@ public void initialize() {


root.setOnDragDetected(mouseEvent -> {
// Create a snapshot to use as the cursor
final ImageView preview = new ImageView(root.snapshot(null, null));

final Dragboard db = root.startDragAndDrop(TransferMode.ANY);
db.setContent(Collections.singletonMap(DataFormat.PLAIN_TEXT, operation.getName()));
db.setDragView(preview.getImage());
// Begin the dragging
root.startFullDrag();
// Tell the drag service that this is the operation that will be received
operationDragService.beginDrag(operation);
operationDragService.beginDrag(operation, root, operation.getName());

mouseEvent.consume();
});

root.setOnDragDone(mouseEvent -> {
operationDragService.completeDrag();
});
}

@FXML
Expand Down
21 changes: 19 additions & 2 deletions ui/src/main/java/edu/wpi/grip/ui/dragging/DragService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;

import java.util.Collections;
import java.util.Optional;

/**
Expand Down Expand Up @@ -39,11 +45,22 @@ public Optional<T> getValue() {
}

/**
* Begins the drag action
* Begins the drag action.
* Creates the dragboard on the root node and adds a
* snapshot of the root node as the view.
*
* @param value The value to be transferred during the drag.
* @param root The root node to drag
* @param name The name to set as the content of the dragboard
*/
public void beginDrag(T value) {
public void beginDrag(T value, Node root, String name) {
// Create a snapshot to use as the cursor
final ImageView preview = new ImageView(root.snapshot(null, null));

final Dragboard db = root.startDragAndDrop(TransferMode.ANY);
db.setContent(Collections.singletonMap(DataFormat.PLAIN_TEXT, name));
db.setDragView(preview.getImage());

this.dragProperty.set(value);
}

Expand Down
15 changes: 15 additions & 0 deletions ui/src/main/java/edu/wpi/grip/ui/dragging/StepDragService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package edu.wpi.grip.ui.dragging;

import com.google.inject.Singleton;
import edu.wpi.grip.core.Step;

/**
* Service for dragging and dropping a step
*/
@Singleton
public class StepDragService extends DragService<Step> {

public StepDragService() {
super("step");
}
}
111 changes: 75 additions & 36 deletions ui/src/main/java/edu/wpi/grip/ui/pipeline/PipelineController.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import edu.wpi.grip.core.sockets.OutputSocket;
import edu.wpi.grip.ui.annotations.ParametrizedController;
import edu.wpi.grip.ui.dragging.OperationDragService;
import edu.wpi.grip.ui.dragging.StepDragService;
import edu.wpi.grip.ui.pipeline.input.InputSocketController;
import edu.wpi.grip.ui.pipeline.source.SourceController;
import edu.wpi.grip.ui.pipeline.source.SourceControllerFactory;
Expand All @@ -31,6 +32,7 @@
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.Collection;
import java.util.Map;
Expand Down Expand Up @@ -70,6 +72,8 @@ public final class PipelineController {
private AddSourceView addSourceView;
@Inject
private OperationDragService operationDragService;
@Inject
private StepDragService stepDragService;

private ControllerMap<StepController, Node> stepsMapManager;
private ControllerMap<SourceController, Node> sourceMapManager;
Expand Down Expand Up @@ -98,55 +102,90 @@ public void initialize() throws Exception {
dragEvent.acceptTransferModes(TransferMode.ANY);
});

stepDragService.getValue().ifPresent(step -> {
dragEvent.acceptTransferModes(TransferMode.ANY);
});

});

stepBox.setOnDragDropped(mouseEvent -> {
// If this is an operation being dropped
operationDragService.getValue().ifPresent(operation -> {
// Then we need to figure out where to put it in the pipeline
// First create a map of every node in the steps list to its x position
final Map<Double, Node> positionMapping = stepsMapManager
.entrySet()
.stream()
.collect(
Collectors
.toMap(e -> calculateMiddleXPosOfNodeInParent(e.getValue()),
Map.Entry::getValue));

// A tree map is an easy way to sort the values
final NavigableMap<Double, Node> sortedPositionMapping
= new TreeMap<>(positionMapping);

// Now we find the sockets that are to the immediate left and
// immediate right of the drop point

// These can be null
final Map.Entry<Double, Node>
lowerEntry = sortedPositionMapping.floorEntry(mouseEvent.getX()),
higherEntry = sortedPositionMapping.ceilingEntry(mouseEvent.getX());
// These can be null
final StepController
lowerStepController =
lowerEntry == null ?
null : stepsMapManager.getWithNode(lowerEntry.getValue());
final StepController
higherStepController =
higherEntry == null ?
null : stepsMapManager.getWithNode(higherEntry.getValue());
final Step
lowerStep = lowerStepController == null ? null : lowerStepController.getStep(),
higherStep = higherStepController == null ? null : higherStepController.getStep();


operationDragService.completeDrag();
final StepPair pair = lowerAndHigherStep(mouseEvent.getX());
// Add the new step to the pipeline between these two steps
pipeline.addStepBetween(stepFactory.create(operation), lowerStep, higherStep);
pipeline.addStepBetween(stepFactory.create(operation), pair.lower, pair.higher);
});

// If this is a step being dropped
stepDragService.getValue().ifPresent(step -> {
stepDragService.completeDrag();
final StepPair pair = lowerAndHigherStep(mouseEvent.getX());
// Move the new step to the pipeline between these two steps
pipeline.moveStepBetween(step, pair.lower, pair.higher);
});
});

addSourcePane.getChildren().add(addSourceView);
}

/**
* Simple class for returning two steps
*/
private static final class StepPair {
final Step lower;
final Step higher;

StepPair(@Nullable Step lower, @Nullable Step higher) {
this.lower = lower;
this.higher = higher;
}
}

/**
* Determines the steps (via the {@link StepController} that are above and below the given
* {@code x} value in the list of steps.
*
* @param x The x value to find what steps this is between
* @return The pair of steps that are above and below this x position.
*/
private StepPair lowerAndHigherStep(double x) {
// Then we need to figure out where to put it in the pipeline
// First create a map of every node in the steps list to its x position
final Map<Double, Node> positionMapping = stepsMapManager
.entrySet()
.stream()
.collect(
Collectors
.toMap(e -> calculateMiddleXPosOfNodeInParent(e.getValue()),
Map.Entry::getValue));

// A tree map is an easy way to sort the values
final NavigableMap<Double, Node> sortedPositionMapping
= new TreeMap<>(positionMapping);

// Now we find the sockets that are to the immediate left and
// immediate right of the drop point

// These can be null
final Map.Entry<Double, Node>
lowerEntry = sortedPositionMapping.floorEntry(x),
higherEntry = sortedPositionMapping.ceilingEntry(x);
// These can be null
final StepController
lowerStepController =
lowerEntry == null ?
null : stepsMapManager.getWithNode(lowerEntry.getValue());
final StepController
higherStepController =
higherEntry == null ?
null : stepsMapManager.getWithNode(higherEntry.getValue());
return new StepPair(
lowerStepController == null ? null : lowerStepController.getStep(),
higherStepController == null ? null : higherStepController.getStep()
);
}

private double calculateMiddleXPosOfNodeInParent(Node node) {
return node.getLayoutX() + (node.getBoundsInParent().getWidth() / 2.);
}
Expand Down
10 changes: 2 additions & 8 deletions ui/src/main/java/edu/wpi/grip/ui/pipeline/SocketHandleView.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@
import javafx.css.PseudoClass;
import javafx.scene.control.Button;
import javafx.scene.control.Tooltip;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;

import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -95,12 +92,9 @@ public interface Factory {
// When the user starts dragging a socket handle, starting forming a connection. This involves keeping a
// reference to the SocketView that the drag started at.
this.setOnDragDetected(mouseEvent -> {
Dragboard db = this.startDragAndDrop(TransferMode.ANY);
db.setContent(Collections.singletonMap(DataFormat.PLAIN_TEXT, "socket"));
mouseEvent.consume();

this.connectingProperty.set(true);
socketDragService.beginDrag(this.socket);
socketDragService.beginDrag(this.socket, this, "socket");
mouseEvent.consume();
});

// Remove the "connecting" property (which changes the appearance of the handle) when the user moves the cursor
Expand Down
Loading

0 comments on commit 087c8c3

Please sign in to comment.