44import edu .wpi .grip .core .Step ;
55import edu .wpi .grip .core .sockets .InputSocket ;
66import edu .wpi .grip .core .sockets .OutputSocket ;
7+ import edu .wpi .grip .core .sockets .SocketHint ;
78import edu .wpi .grip .ui .Controller ;
89import edu .wpi .grip .ui .annotations .ParametrizedController ;
910import edu .wpi .grip .ui .components .ExceptionWitnessResponderButton ;
1617import com .google .inject .assistedinject .Assisted ;
1718
1819import java .io .InputStream ;
20+ import java .util .ArrayList ;
1921import java .util .Collection ;
22+ import java .util .List ;
2023
24+ import javafx .animation .KeyFrame ;
25+ import javafx .animation .KeyValue ;
26+ import javafx .animation .Timeline ;
27+ import javafx .animation .TimelineBuilder ;
28+ import javafx .beans .property .DoubleProperty ;
29+ import javafx .event .ActionEvent ;
30+ import javafx .event .EventHandler ;
2131import javafx .fxml .FXML ;
2232import javafx .scene .Node ;
33+ import javafx .scene .control .Button ;
2334import javafx .scene .control .Labeled ;
2435import javafx .scene .image .Image ;
2536import javafx .scene .image .ImageView ;
2637import javafx .scene .layout .HBox ;
2738import javafx .scene .layout .VBox ;
28-
39+ import javafx . util . Duration ;
2940import javax .inject .Inject ;
3041
3142/**
@@ -41,6 +52,8 @@ public class StepController implements Controller {
4152 private final ExceptionWitnessResponderButton .Factory exceptionWitnessResponderButtonFactory ;
4253 private final StepDragService stepDragService ;
4354 private final Step step ;
55+ private final List <InputSocketController > inputSockets ;
56+ private boolean expanded = true ;
4457 @ FXML
4558 private VBox root ;
4659 @ FXML
@@ -53,6 +66,10 @@ public class StepController implements Controller {
5366 private VBox inputs ;
5467 @ FXML
5568 private VBox outputs ;
69+ @ FXML
70+ private ImageView expandIcon ;
71+ @ FXML
72+ private Button expand ;
5673 private ControllerMap <InputSocketController , Node > inputSocketMapManager ;
5774 private ControllerMap <OutputSocketController , Node > outputSocketMapManager ;
5875
@@ -69,6 +86,7 @@ public class StepController implements Controller {
6986 this .exceptionWitnessResponderButtonFactory = exceptionWitnessResponderButtonFactory ;
7087 this .stepDragService = stepDragService ;
7188 this .step = step ;
89+ inputSockets = new ArrayList <>();
7290 }
7391
7492 @ FXML
@@ -82,9 +100,21 @@ private void initialize() {
82100 new Image (InputStream .class .cast (icon ))));
83101 buttons .getChildren ().add (0 , exceptionWitnessResponderButtonFactory .create (step , "Step Error" ));
84102
103+ if (step .getInputSockets ().stream ()
104+ .allMatch (inputSocket -> inputSocket .getSocketHint ().getView ()
105+ .equals (SocketHint .View .NONE ))) {
106+ expand .setManaged (false );
107+ } else {
108+ expandIcon .setImage (new Image ("/edu/wpi/grip/ui/icons/up.png" ));
109+ }
110+
85111 // Add a SocketControlView for each input socket and output socket
86112 for (InputSocket <?> inputSocket : step .getInputSockets ()) {
87- inputSocketMapManager .add (inputSocketControllerFactory .create (inputSocket ));
113+ InputSocketController tempSocket = inputSocketControllerFactory .create (inputSocket );
114+ inputSocketMapManager .add (tempSocket );
115+ if (!inputSocket .getSocketHint ().getView ().equals (SocketHint .View .NONE )) {
116+ inputSockets .add (tempSocket );
117+ }
88118 }
89119
90120 for (OutputSocket <?> outputSocket : step .getOutputSockets ()) {
@@ -142,6 +172,91 @@ private void moveStepRight() {
142172 pipeline .moveStep (step , +1 );
143173 }
144174
175+ @ FXML
176+ private void expand () {
177+ if (expanded ) {
178+ for (InputSocketController input : inputSockets ) {
179+ inputs .setMaxHeight (inputs .getHeight ());
180+ inputs .setPrefHeight (inputs .getHeight ());
181+ if (input .getSocket ().getConnections ().isEmpty ()) {
182+ fadeOut (input );
183+ }
184+ }
185+ closeUp ();
186+ expandIcon .setImage (new Image ("/edu/wpi/grip/ui/icons/down.png" ));
187+ expanded = false ;
188+ } else {
189+ for (InputSocketController input : inputSockets ) {
190+ fadeIn (input );
191+ }
192+ reopen ();
193+ expandIcon .setImage (new Image ("/edu/wpi/grip/ui/icons/up.png" ));
194+ expanded = true ;
195+ }
196+
197+ }
198+
199+ /**
200+ * Makes an animation to make an input socket fade out over 0.1 seconds.
201+ *
202+ * @param input the input socket controller that will be faded out.
203+ */
204+ private void fadeOut (InputSocketController input ) {
205+ DoubleProperty opacity = input .getRoot ().opacityProperty ();
206+ Timeline fadeOut = new Timeline (
207+ new KeyFrame (Duration .ZERO , new KeyValue (opacity , 1.0 )),
208+ new KeyFrame (new Duration (100 ), new KeyValue (opacity , 0.0 )));
209+ fadeOut .setOnFinished (new EventHandler <ActionEvent >() {
210+ @ Override
211+ public void handle (ActionEvent event ) {
212+ input .getRoot ().setVisible (false );
213+ input .getRoot ().setManaged (false );
214+ }
215+ });
216+ fadeOut .play ();
217+ }
218+
219+ /**
220+ * Makes an animation to make an input socket fade in over 0.1 seconds.
221+ *
222+ * @param input the input socket controller that will be faded out.
223+ */
224+ private void fadeIn (InputSocketController input ) {
225+ input .getRoot ().setVisible (true );
226+ DoubleProperty opacity = input .getRoot ().opacityProperty ();
227+ Timeline fadeIn = new Timeline (
228+ new KeyFrame (new Duration (100 ), new KeyValue (opacity , 1.0 )));
229+ fadeIn .setOnFinished (new EventHandler <ActionEvent >() {
230+ @ Override
231+ public void handle (ActionEvent event ) {
232+ for (InputSocketController input : inputSockets ) {
233+ input .getRoot ().setManaged (true );
234+ }
235+ }
236+ });
237+ fadeIn .play ();
238+ }
239+
240+ /**
241+ * Makes an animation to make the input vbox slide closed over .25 seconds
242+ */
243+ private void closeUp () {
244+ Timeline animation = TimelineBuilder .create ().cycleCount (1 ).keyFrames (
245+ new KeyFrame (Duration .seconds (0.25 ),
246+ new KeyValue (inputs .prefHeightProperty (), 0 ))).build ();
247+ animation .play ();
248+ }
249+
250+ /**
251+ * Makes an animation to make the input vbox slide open over .1 seconds
252+ */
253+ private void reopen () {
254+ Timeline animation = TimelineBuilder .create ().cycleCount (1 ).keyFrames (
255+ new KeyFrame (Duration .seconds (0.1 ),
256+ new KeyValue (inputs .prefHeightProperty (), inputs .getMaxHeight ()))).build ();
257+ animation .play ();
258+ }
259+
145260 /**
146261 * Used for assisted injects. Guice will automatically create an instance of this interface so we
147262 * can create step controllers. This lets us use injection with StepController even though it
0 commit comments