AbstractViewUI.java

package edu.ntnu.idi.idatt.view.components;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.util.Duration;

/**
 * Abstract View UI class.
 *
 * <p>
 * Creates a view layout to simplify further view creation for child classes.
 * </p>
 */
public abstract class AbstractViewUI extends AbstractView<StackPane> {

  private VBox navigation;
  private HBox header;
  private HBox toolbar;
  private VBox menu;
  private SimpleBooleanProperty isMenuVisible = new SimpleBooleanProperty(false);

  /**
   * Constructor for AbstactViewUI.
   * 
   * <p>
   * Binds the abstract classes into
   * the root StackPane.
   * Binds together smaller modules which are persistent across all views.
   * </p>
   */
  public AbstractViewUI() {
    HBox wrapper = new HBox();
    BorderPane layout = new BorderPane();

    createUIComponents();
    navigation.getChildren().add(createNavigation());
    header.getChildren().add(createHeader());
    toolbar.getChildren().add(createToolbar());

    layout.setTop(header);
    layout.setBottom(toolbar);
    layout.setCenter(createContent());

    HBox.setHgrow(layout, Priority.ALWAYS);
    wrapper.getChildren().addAll(navigation, layout);

    this.setInstance(new StackPane());

    menu.getChildren().add(createMenu());
    menu.setVisible(false);

    Region disableMenu = new Region();
    disableMenu.setVisible(false);

    disableMenu.setOnMouseClicked(e -> {
      animationMenu(false);
      disableMenu.setVisible(false);
    });

    isMenuVisible.addListener((observer, oldVal, newVal) -> {
      animationMenu(true);
      disableMenu.setVisible(true);
    });

    this.getInstance().getChildren().addAll(wrapper, disableMenu, menu);
  }

  /**
   * Method for creating initial view wrappers.
   */
  public void createUIComponents() {
    navigation = new VBox();
    navigation.setMaxHeight(Double.MAX_VALUE);
    navigation.getStyleClass().add("dark");
    navigation.setPrefWidth(300); // ScrollPane's affect this massively
    navigation.setMaxWidth(300);
    navigation.setMinWidth(300);

    header = new HBox();
    header.getStyleClass().add("light");
    header.setMaxHeight(80);

    toolbar = new HBox();
    toolbar.getStyleClass().add("light");
    toolbar.setMaxHeight(80);

    menu = new VBox();
    StackPane.setAlignment(menu, Pos.CENTER_RIGHT);
    menu.getStyleClass().add("dark");
    menu.setMaxWidth(300);
  }

  /**
   * Abstract method for content creation.
   * 
   * @return Root node of content.
   */
  public abstract Parent createContent();

  /**
   * Abstract method for navigation creation.
   * 
   * @return Root node of navigation.
   */
  public abstract Parent createNavigation();

  /**
   * Abstract method for header creation.
   * 
   * @return Root node of header.
   */
  public abstract Parent createHeader();

  /**
   * Abstract method for toolbar creation.
   * 
   * @return Root node of toolbar.
   */
  public abstract Parent createToolbar();

  /**
   * Abstract method for menu creation.
   * 
   * @return Root node of menu.
   */
  public abstract Parent createMenu();

  /**
   * Getter for navigation.
   * 
   * @return VBox;
   */
  public VBox getNavigation() {
    return navigation;
  }

  /**
   * Getter for header.
   * 
   * @return HBox;
   */
  public HBox getHeader() {
    return header;
  }

  /**
   * Getter for toolbar.
   * 
   * @return HBox;
   */
  public HBox getToolbar() {
    return toolbar;
  }

  /**
   * Method for toggling the visibility of the menu.
   */
  public void toggleMenu() {
    isMenuVisible.set(!isMenuVisible.get());
  }

  /**
   * Method for animating the menu.
   * 
   * @param val - in = true, out = false
   */
  private void animationMenu(boolean val) {
    Timeline animation;
    if (val) {
      menu.setVisible(true);
      menu.setTranslateX(menu.getWidth()); // Fix issue from menu initialization
      // (hide before starting to appear no matter what)
      animation = new Timeline(new KeyFrame(Duration.millis(200),
          new KeyValue(menu.translateXProperty(), 0)));
    } else {
      animation = new Timeline(new KeyFrame(Duration.millis(200),
          new KeyValue(menu.translateXProperty(), menu.getWidth())));
      animation.setOnFinished((e) -> menu.setVisible(false));
    }
    animation.play();
  }

}