Newer
Older
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;
Håvard Daleng
committed
import edu.ntnu.stud.chaosgame.controller.utility.Formatter;
import edu.ntnu.stud.chaosgame.model.data.Vector2D;
import edu.ntnu.stud.chaosgame.model.generators.ChaosGameDescriptionFactory;
Håvard Daleng
committed
import java.util.Objects;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.canvas.Canvas;
Håvard Daleng
committed
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.*;
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;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ChaosGameGui implements ChaosGameObserver {
private Canvas canvas;
private ChaosCanvas chaosCanvas;
/**
* The ChaosGameDescription.
*/
private ChaosGameDescription description;
/**
* The ChaosGameDescriptionFactory.
*/
private ChaosGameDescriptionFactory factory;
/**
* The ImageView for the GUI..
*/
private ChaosGameImageView imageView;
/**
* 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.
*/
private Button startButton;
private Button stopButton;
private Button newButton;
private Button clearButton;
private Button quitButton;
private Button sideMenuButton;
/**
* 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;
Håvard Daleng
committed
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
primaryStage.setTitle("Fractal Chaos Game");
primaryStage.setScene(scene);
primaryStage.setOnShown(event -> this.imageView.requestFocus());
primaryStage.show();
/**
* Initialize the components of the GUI.
*/
private void initializeComponents() {
// Timeline
//this.timeline = new Timeline(new KeyFrame(Duration.seconds(0.05), event -> controller.drawChaosGame()));
//this.initializeMainButtons();
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());
//
// }
/**
* Initialize the components related to the chaos game itself.
*/
private void initializeGameComponents() {
// Description
this.factory = new ChaosGameDescriptionFactory();
Håvard Daleng
committed
this.description = factory.getDescriptions().get(0);
this.chaosCanvas = new ChaosCanvas(1000, 1000, this.description.getMinCoords(),
Håvard Daleng
committed
this.description.getMaxCoords());
game = new ChaosGame(this.description, chaosCanvas);
//controller.startGame(); // Start the game after it's created
}
/**
* Initialize components related to the image view and zoom function.
*/
private void initializeImageView() {
// Image view
this.imageView = new ChaosGameImageView(this);
this.canvas = new Canvas(width, height);
Håvard Daleng
committed
//this.imageView.setImage(canvas.snapshot(null, null));
Håvard Daleng
committed
this.clearImageView();
* Color the entire image view white.
Håvard Daleng
committed
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
imageView.setImage(null);
}
/**
* 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);
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 -> {
});
// Set action for Barnsley radio button.
barnsleyRadioButton.setOnAction(event -> {
});
// Set action for Julia radio button.
juliaRadioButton.setOnAction(event -> {
});
improvedBarnsleyButton.setOnAction(event -> {
});
// 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");
this.sideMenu = new VBox();
// Parameters
VBox parameterBox = new VBox();
// Step Count GUI
VBox stepCountBox = new VBox();
Label stepCountLabel = new Label("Step Count");
Håvard Daleng
committed
this.stepCountTextField = new TextField();
this.stepCountTextField.setTextFormatter(Formatter.getIntFormatter()); // Set formatter
stepCountTextField.setPrefHeight(5);
stepCountTextField.setPrefWidth(50);
Håvard Daleng
committed
stepCountBox.getChildren().addAll(stepCountLabel,stepCountTextField);
// Minimum Coordinates GUI
VBox minCoordinatesBox = new VBox();
Label minCoordinatesLabel = new Label("Min. Coordinates");
TextField minimumCoordinatesTextField = new TextField();
minimumCoordinatesTextField.setPrefHeight(5);
minimumCoordinatesTextField.setPrefWidth(50);
Button changeMinimumCoordinatesButton = new Button("Change Min. Coordinates");
minCoordinatesBox.getChildren().addAll(minCoordinatesLabel,
minimumCoordinatesTextField,changeMinimumCoordinatesButton);
// Maximum Coordinates GUI
VBox maxCoordinatesBox = new VBox();
Label maxCoordinatesLabel = new Label("Max Coordinates");
TextField maximumCoordinatesTextField = new TextField();
maximumCoordinatesTextField.setPrefHeight(5);
maximumCoordinatesTextField.setPrefWidth(50);
Button changeMaximumCoordinatesButton = new Button("Change Max Coordinates");
maxCoordinatesBox.getChildren().addAll(maxCoordinatesLabel,
maximumCoordinatesTextField,changeMaximumCoordinatesButton);
Håvard Daleng
committed
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);
// 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);
sideMenu.getChildren().addAll(sierpinskiRadioButton, barnsleyRadioButton, juliaRadioButton,
improvedBarnsleyButton);
Håvard Daleng
committed
sideMenu.getChildren().addAll(separator1, colorBox, separator2);
this.initializeColorButtonHandler();
// Add parameter VBox
sideMenu.getChildren().add(parameterBox);
// Add file buttons
sideMenu.getChildren().addAll(loadFractalFromFileButton,writeFractalToFileButton);
// Add quit button
sideMenu.getChildren().add(quitButton);
// 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;");
this.borderPane = new BorderPane();
this.borderPane.setCenter(imageView);
this.borderPane.setRight(rightVBox);
rightVBox.setFocusTraversable(false);
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("<<");
}
});
}
Håvard Daleng
committed
/**
* Initialize the color button handler.
*/
private void initializeColorButtonHandler() {
this.colorCheckBox.setOnAction(event -> {
controller.game.setUseColor(colorCheckBox.isSelected());
Håvard Daleng
committed
this.clearImageView();
this.chaosCanvas.clearCanvas();
});
}
/**
* Get the chaos canvas of this GUI view.
*
* @return the canvas.
*/
public ChaosCanvas getChaosCanvas() {
return this.chaosCanvas;
}
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);
}
Håvard Daleng
committed
/**
* 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.
*/
Håvard Daleng
committed
@Override
Håvard Daleng
committed
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));
}
/**
* 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;
}