Skip to content
Snippets Groups Projects
ChaosGameGui.java 14.2 KiB
Newer Older
Magnus Eik's avatar
Magnus Eik committed
package edu.ntnu.stud.chaosgame.view;

import edu.ntnu.stud.chaosgame.controller.game.ChaosCanvas;
import edu.ntnu.stud.chaosgame.controller.game.ChaosGame;
import edu.ntnu.stud.chaosgame.controller.game.ChaosGameDescription;
import edu.ntnu.stud.chaosgame.controller.game.GuiButtonController;
import edu.ntnu.stud.chaosgame.controller.utility.Formatter;
import edu.ntnu.stud.chaosgame.model.data.Vector2D;
Magnus Eik's avatar
Magnus Eik committed
import edu.ntnu.stud.chaosgame.model.generators.ChaosGameDescriptionFactory;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Platform;
import javafx.geometry.Insets;
Magnus Eik's avatar
Magnus Eik committed
import javafx.scene.Scene;
import javafx.scene.control.*;
Magnus Eik's avatar
Magnus Eik committed
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
Magnus Eik's avatar
Magnus Eik committed
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
Magnus Eik's avatar
Magnus Eik committed

import java.io.IOException;

public class ChaosGameGui implements ChaosGameObserver {
Håvard Daleng's avatar
Håvard Daleng committed
  private int currentLine = 0;

Håvard Daleng's avatar
Håvard Daleng committed
  /**
   * The ChaosCanvas for this GUI.
   */
Håvard Daleng's avatar
Håvard Daleng committed

  /**
   * The ChaosGameDescription.
   */
  private ChaosGameDescription description;

  /**
   * The ChaosGameDescriptionFactory.
   */
  private ChaosGameDescriptionFactory factory;

  /**
   * The ImageView for the GUI..
   */
  private ChaosGameImageView imageView;
Håvard Daleng's avatar
Håvard Daleng committed

  /**
   * The Scene for the GUI..
   */
  private Scene scene;

  /**
   * The width and height of the GUI.
   */
  private int width;
  private int height;

  /**
   * The ChaosGame for this GUI.
   */
  private ChaosGame game;

  /**
   * The Timeline for the GUI.
   */
  private Timeline timeline;

  /**
   * The BorderPane for the GUI.
   */
  private BorderPane borderPane;

  /**
   * The side menu for the GUI.
   */
  private VBox sideMenu;

  /**
   * The start, stop, new, clear, quit and show sidebar buttons for the GUI.
Håvard Daleng's avatar
Håvard Daleng committed
   */
  private Button startButton;
  private Button stopButton;
  private Button newButton;
  private Button clearButton;
  private Button quitButton;
Håvard Daleng's avatar
Håvard Daleng committed

  /**
   * The load fractal from file and write fractal to file buttons for the GUI.
   */
  private Button loadFractalFromFileButton;
  private Button writeFractalToFileButton;

  /**
   * The radio buttons for the fractal type for the GUI.
   */
  private RadioButton sierpinskiRadioButton;
  private RadioButton barnsleyRadioButton;
  private RadioButton juliaRadioButton;
  private RadioButton improvedBarnsleyButton;

  private TextField stepCountTextField;

  private CheckBox colorCheckBox;

  private GuiButtonController controller;
public ChaosGameGui(Stage primaryStage) throws IOException {

  this.initializeComponents();
  this.initializeGameComponents();
  this.controller = new GuiButtonController(game, this); // Initialize controller here

Håvard Daleng's avatar
Håvard Daleng committed

    primaryStage.setTitle("Fractal Chaos Game");
    primaryStage.setScene(scene);
    primaryStage.setOnShown(event -> this.imageView.requestFocus());
    primaryStage.show();
Håvard Daleng's avatar
Håvard Daleng committed
  /**
   * Initialize the components of the GUI.
   */
  private void initializeComponents() {

    // Timeline
    //this.timeline = new Timeline(new KeyFrame(Duration.seconds(0.05), event -> controller.drawChaosGame()));
Håvard Daleng's avatar
Håvard Daleng committed
    this.initializeImageView();

Håvard Daleng's avatar
Håvard Daleng committed
    // Side menu

    //this.initializeMainButtons();
Håvard Daleng's avatar
Håvard Daleng committed
    this.initializeFractalButtons();
    this.initializeSideMenu();

    this.scene = new Scene(this.borderPane,1700,1000);
  }

  /**
   * Initialize the main buttons for the GUI.
   */
//  private void initializeMainButtons() {
//    this.startButton = new Button("Start");
//    startButton.setOnAction(event -> controller.startGame());
//    this.stopButton = new Button("Stop");
//    stopButton.setOnAction(event -> controller.stopGame());
//
//    this.newButton = new Button("New");
//
//    newButton.setOnAction(event ->{
//      this.canvas.getGraphicsContext2D().clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
//      chaosCanvas.clearCanvas();
//    });
//
//    this.clearButton = new Button("Clear");
//
//    clearButton.setOnAction(event -> {
//      getImageView().setImage(null);
//      setCurrentLine(0);
//    });
//
//    // Quit button
//    this.quitButton = new Button("Quit");
//    quitButton.setOnAction(event -> Platform.exit());
//
//  }
Håvard Daleng's avatar
Håvard Daleng committed

  /**
   * Initialize the components related to the chaos game itself.
   */
  private void initializeGameComponents() {
    // Description
    this.factory = new ChaosGameDescriptionFactory();
    this.description = factory.getDescriptions().get(0);
Håvard Daleng's avatar
Håvard Daleng committed
    this.chaosCanvas = new ChaosCanvas(1000, 1000, this.description.getMinCoords(),
    game = new ChaosGame(this.description, chaosCanvas);
    //controller.startGame(); // Start the game after it's created
}
Håvard Daleng's avatar
Håvard Daleng committed
  /**
   * Initialize components related to the image view and zoom function.
   */
  private void initializeImageView() {
    // Image view
    this.imageView = new ChaosGameImageView(this);
Håvard Daleng's avatar
Håvard Daleng committed
    width = 1000;
    height = 1000;
    this.canvas = new Canvas(width, height);
    //this.imageView.setImage(canvas.snapshot(null, null));
   * Color the entire image view white.
  public void clearImageView() {
    GraphicsContext gc = canvas.getGraphicsContext2D();
    gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
    imageView.setImage(null);
Håvard Daleng's avatar
Håvard Daleng committed
  }

  /**
   * Initialize the buttons related to managing the fractals.
   */
  private void initializeFractalButtons() {

    // Radio buttons for choosing fractal type
    ToggleGroup group = new ToggleGroup();
    this.sierpinskiRadioButton = new RadioButton("Sierpinski");
    sierpinskiRadioButton.setToggleGroup(group);
    //sierpinskiRadioButton.setSelected(true);
Håvard Daleng's avatar
Håvard Daleng committed
    this.barnsleyRadioButton = new RadioButton("Barnsley");
    barnsleyRadioButton.setToggleGroup(group);
    this.juliaRadioButton = new RadioButton("Julia");
    juliaRadioButton.setToggleGroup(group);
    this.improvedBarnsleyButton = new RadioButton("Improved Barnsley");
    improvedBarnsleyButton.setToggleGroup(group);


    // Set action for Sierpinski radio button.
    sierpinskiRadioButton.setOnAction(event -> {
      controller.updateDescription(0);
Håvard Daleng's avatar
Håvard Daleng committed
    });

    // Set action for Barnsley radio button.
    barnsleyRadioButton.setOnAction(event -> {
      controller.updateDescription(1);
Håvard Daleng's avatar
Håvard Daleng committed
    });

    // Set action for Julia radio button.
    juliaRadioButton.setOnAction(event -> {
      controller.updateDescription(2);
Håvard Daleng's avatar
Håvard Daleng committed
    });

    improvedBarnsleyButton.setOnAction(event -> {
      controller.updateDescription(3);
Håvard Daleng's avatar
Håvard Daleng committed
    });

    // Load fractal file button
    this.loadFractalFromFileButton = new Button("Load Fractal");
    // Write fractal to file button
    this.writeFractalToFileButton = new Button("Write to File");
  }

  /**
   * Initialize the side menu.
   */
  private void initializeSideMenu() {


    this.startButton = new Button("Start");
    this.stopButton = new Button("Stop");
    this.newButton = new Button("New");
    this.clearButton = new Button("Clear");
    this.quitButton = new Button("Quit");
    this.sideMenuButton = new Button("Side Menu");

Håvard Daleng's avatar
Håvard Daleng committed
    this.sideMenu = new VBox();
    // Parameters
    VBox parameterBox = new VBox();
Håvard Daleng's avatar
Håvard Daleng committed
    // Step Count GUI
    VBox stepCountBox = new VBox();
    Label stepCountLabel = new Label("Step Count");
    this.stepCountTextField = new TextField();
    this.stepCountTextField.setTextFormatter(Formatter.getIntFormatter()); // Set formatter
    stepCountTextField.setPrefHeight(5);
    stepCountTextField.setPrefWidth(50);

    stepCountBox.getChildren().addAll(stepCountLabel,stepCountTextField);
Håvard Daleng's avatar
Håvard Daleng committed
    // Minimum Coordinates GUI
    VBox minCoordinatesBox = new VBox();
    Label minCoordinatesLabel = new Label("Min. Coordinates");
    TextField minimumCoordinatesTextField = new TextField();
    minimumCoordinatesTextField.setPrefHeight(5);
    minimumCoordinatesTextField.setPrefWidth(50);
Håvard Daleng's avatar
Håvard Daleng committed
    Button changeMinimumCoordinatesButton = new Button("Change Min. Coordinates");
    minCoordinatesBox.getChildren().addAll(minCoordinatesLabel,
        minimumCoordinatesTextField,changeMinimumCoordinatesButton);

Håvard Daleng's avatar
Håvard Daleng committed
    // Maximum Coordinates GUI
    VBox maxCoordinatesBox = new VBox();
    Label maxCoordinatesLabel = new Label("Max Coordinates");
    TextField maximumCoordinatesTextField = new TextField();
    maximumCoordinatesTextField.setPrefHeight(5);
    maximumCoordinatesTextField.setPrefWidth(50);
Håvard Daleng's avatar
Håvard Daleng committed
    Button changeMaximumCoordinatesButton = new Button("Change Max Coordinates");
    maxCoordinatesBox.getChildren().addAll(maxCoordinatesLabel,
        maximumCoordinatesTextField,changeMaximumCoordinatesButton);

    HBox colorBox = new HBox();
    Label colorLabel = new Label("Use color");
    this.colorCheckBox = new CheckBox();
    Region colorRegion = new Region();
    colorRegion.setMinWidth(30);
    colorBox.getChildren().addAll(colorCheckBox, colorRegion, colorLabel);

    Region separator1 = new Region();
    separator1.setMinHeight(10);
    Region separator2 = new Region();
    separator2.setMinHeight(10);

Håvard Daleng's avatar
Håvard Daleng committed
    // Fill parameter box
    parameterBox.getChildren().addAll(stepCountBox, minCoordinatesBox, maxCoordinatesBox);
    parameterBox.setPadding(new Insets(10));

    // Add basic control buttons
    sideMenu.getChildren().addAll(startButton,stopButton,newButton,clearButton);
Håvard Daleng's avatar
Håvard Daleng committed
    // Add fractal radio buttons
    sideMenu.getChildren().addAll(sierpinskiRadioButton, barnsleyRadioButton, juliaRadioButton,
        improvedBarnsleyButton);

    sideMenu.getChildren().addAll(separator1, colorBox, separator2);
    this.initializeColorButtonHandler();

Håvard Daleng's avatar
Håvard Daleng committed
    // Add parameter VBox
    sideMenu.getChildren().add(parameterBox);
Håvard Daleng's avatar
Håvard Daleng committed
    // Add file buttons
    sideMenu.getChildren().addAll(loadFractalFromFileButton,writeFractalToFileButton);
Håvard Daleng's avatar
Håvard Daleng committed
    // Add quit button
    sideMenu.getChildren().add(quitButton);
Håvard Daleng's avatar
Håvard Daleng committed
    // Add padding
    sideMenu.setPadding(new Insets(10));

    // Create split pane and button to toggle sidebar
    this.sideMenuButton = new Button(">>");
    this.initializeSideButtonHandler();
    Region sideMenuButtonRegion = new Region();
    sideMenuButtonRegion.setMinWidth(200);
    HBox sideMenuButtonBox = new HBox();
    sideMenuButtonBox.getChildren().addAll(sideMenuButtonRegion, sideMenuButton);

    // The right VBox containing both the sidebar and the sidebar toggle button.
    VBox rightVBox = new VBox();

    rightVBox.getChildren().addAll(sideMenuButtonBox, sideMenu);
    this.sideMenu.setStyle("-fx-background-color: lightgrey; -fx-background-radius: 3;");
Håvard Daleng's avatar
Håvard Daleng committed
    this.borderPane = new BorderPane();
    this.borderPane.setCenter(imageView);
    this.borderPane.setRight(rightVBox);
Håvard Daleng's avatar
Håvard Daleng committed
    imageView.setFocusTraversable(true);
    rightVBox.setFocusTraversable(false);
Håvard Daleng's avatar
Håvard Daleng committed
    borderPane.setFocusTraversable(false);

  }

  /**
   * Initialise the side bar button handler, allowing the user
   * to show or hide the right sidebar.
   */
  private void initializeSideButtonHandler() {
    TranslateTransition openNav = new TranslateTransition(new Duration(350), sideMenu);
    openNav.setToX(0);
    TranslateTransition closeNav = new TranslateTransition(new Duration(350), sideMenu);

    this.sideMenuButton.setOnAction(e -> {
      if(sideMenu.getTranslateX() != 0){
        this.sideMenuButton.setText(">>");
        openNav.play();
      } else {
        closeNav.setToX(sideMenu.getWidth());
        closeNav.play();
        this.sideMenuButton.setText("<<");
      }
    });
  }

  /**
   * Initialize the color button handler.
   */
  private void initializeColorButtonHandler() {
    this.colorCheckBox.setOnAction(event -> {
      controller.game.setUseColor(colorCheckBox.isSelected());
  /**
   * Get the chaos canvas of this GUI view.
   *
   * @return the canvas.
   */
  public ChaosCanvas getChaosCanvas() {
    return this.chaosCanvas;
Håvard Daleng's avatar
Håvard Daleng committed

  public int getWidth(){
    return this.width;
  }
  public int getHeight(){
    return this.height;
  }
  public ImageView getImageView(){
    return this.imageView;
  }

  public void setCurrentLine(int currentLine) {
    this.currentLine = currentLine;
  }

  public void setImageViewFromImage(Image inputView) {
    this.imageView.setImage(inputView);
  }

  /**
   * Update the canvas and set a new zoom factor for the image view based on the ratio
   * between the old and new canvas heights.
   *
   * @param canvas the canvas to update with.
   */
  public void updateCanvas(ChaosCanvas canvas) {
    float zoomRatio = (float) this.chaosCanvas.getHeight() / canvas.getHeight();
    //this.imageView.fixedZoom(zoomRatio); // Set new zoom factor.
    this.chaosCanvas = canvas;
  }

  /**
   * Update which parts of the fractal are rendered and at what level of detail.
   *
   * @param zoomLevel the number of recursive zoom levels.
   * @param centreX the x-coordinate of the centre of the image view.
   * @param centreY the y-coordinate of the centre of the image view.
   */
  public void updateDetail(int zoomLevel, double centreX, double centreY) {
    this.clearImageView();
    this.chaosCanvas.clearCanvas();
    this.chaosCanvas.updateCoords(centreX, centreY, zoomLevel);
    controller.game.setCurrentPoint(new Vector2D(centreX, centreY));
Håvard Daleng's avatar
Håvard Daleng committed
  }

  /**
   * Update the observer based on changes to the chaos game.
   * TODO: this method may need to be changed depending on how we implement the UI. The update method may need to be split.
   *
   * @param game the game this observer is monitoring.
   */
  @Override
  public void update(ChaosGame game) {
    controller.drawChaosGame();
  }
  public TextField getStepCountTextField() {
    return this.stepCountTextField;
  }

  public CheckBox getColorCheckBox() {
    return this.colorCheckBox;
  }



  public Canvas getCanvas() {
    return this.canvas;
  public Button getStartButton() {
    return this.startButton;
  }
  public Button getStopButton() {
    return this.stopButton;
  }
  public Button getNewButton() {
    return this.newButton;
  }
  public Button getClearButton() {
    return this.clearButton;
  }
  public Button getQuitButton() {
    return this.quitButton;
  }