package jcgp.gui; import javafx.application.Application; import javafx.application.Platform; import javafx.concurrent.Service; import javafx.concurrent.Task; import javafx.scene.Scene; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TabPane.TabClosingPolicy; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import jcgp.JCGP; import jcgp.JCGP.Resources; import jcgp.gui.console.GUIConsole; import jcgp.gui.settings.SettingsPane; public class GUI extends Application { /* Colours */ /** NEUTRAL_COLOUR is the colour elements should be when no interaction is occurring * (no hovering, clicking, dragging or any other form of interaction). */ public static final String NEUTRAL_COLOUR = "#FFFFFF"; public static final String HARD_HIGHLIGHT_COLOUR = "#5496FF"; public static final String MEDIUM_HIGHLIGHT_COLOUR = "#75BAFF"; public static final String SOFT_HIGHLIGHT_COLOUR = "#C7DFFF"; public static final String GOOD_SELECTION_COLOUR = "#38C25B"; public static final String NEUTRAL_SELECTION_COLOUR = "#FFEF73"; public static final String BAD_SELECTION_COLOUR = "#FF5C5C"; public static final String INVALID_PARAMETER_STYLE = "-fx-border-color: C9C9C9; -fx-border-radius: 2; -fx-padding: 0; -fx-background-color: " + BAD_SELECTION_COLOUR; public static final String WARNING_PARAMETER_STYLE = "-fx-border-color: C9C9C9; -fx-border-radius: 2; -fx-padding: 0; -fx-background-color: " + NEUTRAL_SELECTION_COLOUR; public static final String VALID_PARAMETER_STYLE = "-fx-border-color: C9C9C9; -fx-border-radius: 2; -fx-padding: 0; -fx-background-color: " + NEUTRAL_COLOUR; /* Sizes and distances */ public static final double RESIZE_MARGIN = 5.0; public static final double SETTINGS_WIDTH = 200; public static final double CONSOLE_HEIGHT = 100; public static final double WRAP_WIDTH = 90; private static JCGP cgp; public static Resources resources; private BorderPane leftPane; private BorderPane window; private ChromosomePane[] chromosomes; private TabPane chromosomeTabs; private GUIConsole console = new GUIConsole(); private SettingsPane settings; private boolean evolving = false; private Object printLock = new Object(); private Service cgpService = new Service () { @Override protected Task createTask() { Task t = new Task() { @Override protected Void call() throws Exception { while (!isCancelled() && !cgp.isFinished()) { synchronized (printLock) { Platform.runLater(consoleFlush); cgp.nextGeneration(); printLock.wait(); } } if (cgp.isFinished()) { Platform.runLater(new Runnable() { @Override public void run() { runningMode(false); } }); } return null; } }; return t; } }; private Runnable consoleFlush = new Runnable() { @Override public void run() { synchronized(printLock) { console.flush(); printLock.notifyAll(); } } }; public static void main(String[] args) { cgp = new JCGP(); resources = cgp.getResources(); launch(); } @Override public void start(Stage primaryStage) throws Exception { resources.setConsole(console); /* * Instantiate the various GUI elements here. * * */ leftPane = new BorderPane(); chromosomeTabs = new TabPane(); chromosomeTabs.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE); makeChromosomeTabPane(); settings = new SettingsPane(cgp, this); leftPane.setCenter(chromosomeTabs); leftPane.setBottom(console); window = new BorderPane(); window.setCenter(leftPane); window.setRight(settings); primaryStage.setTitle("JCGP"); primaryStage.setScene(new Scene(window)); primaryStage.show(); } /** * */ private void makeChromosomeTabPane() { chromosomeTabs.getTabs().clear(); chromosomes = new ChromosomePane[cgp.getResources().getInt("popSize")]; Tab tab; for (int i = 0; i < chromosomes.length; i++) { chromosomes[i] = new ChromosomePane(cgp.getPopulation().getChromosome(i), resources); tab = new Tab("Chr " + i); tab.setContent(chromosomes[i]); chromosomeTabs.getTabs().add(tab); } } private void updateNodeGrids() { for (int i = 0; i < chromosomes.length; i++) { chromosomes[i].update(); } } private void unlockOutputs() { for (int i = 0; i < chromosomes.length; i++) { chromosomes[i].unlockOutputs(); } } private void relockOutputs() { for (int i = 0; i < chromosomes.length; i++) { chromosomes[i].relockOutputs(); } } public void disableChromosomePanes(boolean value) { chromosomeTabs.setDisable(value); } public void runPause() { if (!cgp.isFinished() && settings.areParametersValid()) { if (!evolving) { runningMode(true); cgpService.restart(); } else { cgpService.cancel(); runningMode(false); } } } public void step() { if (!evolving && !cgp.isFinished() && settings.areParametersValid()) { if (settings.isResetRequired()) { reset(); } unlockOutputs(); Task task = new Task() { @Override protected Void call() throws Exception { cgp.nextGeneration(); Platform.runLater(consoleFlush); return null; } }; Thread t = new Thread(task); t.start(); try { t.join(); } catch (InterruptedException e) { // nothing } finally { updateNodeGrids(); relockOutputs(); } } } public void reset() { if (!evolving && settings.areParametersValid()) { settings.applyParameters(); cgp.reset(); makeChromosomeTabPane(); settings.revalidateParameters(); } } private void runningMode(boolean value) { chromosomeTabs.setDisable(value); settings.disableSettings(value); if (value) { unlockOutputs(); settings.getRunButton().setText("Pause"); if (settings.isResetRequired()) { reset(); } } else { updateNodeGrids(); relockOutputs(); settings.getRunButton().setText("Run"); } evolving = value; } }