Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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