package jcgp.gui; import javafx.application.Application; import javafx.application.Platform; import javafx.concurrent.Service; import javafx.concurrent.Task; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.stage.Stage; import javafx.stage.WindowEvent; import jcgp.JCGP; import jcgp.backend.modules.problem.TestCaseProblem.TestCase; import jcgp.gui.console.GUIConsole; import jcgp.gui.dragresize.HorizontalDragResize; import jcgp.gui.dragresize.VerticalDragResize; import jcgp.gui.population.FunctionSelector; import jcgp.gui.population.GUINode; import jcgp.gui.population.PopulationPane; import jcgp.gui.settings.SettingsPane; /** * Main class for the graphical user interface (GUI) * * * @author Eduardo Pedroni * */ public class GUI extends Application { /* Colours */ 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"; /* Sizes and distances */ public static final double RESIZE_MARGIN = 5.0; public static final double SETTINGS_MIN_WIDTH = 200; public static final double CONSOLE_MIN_HEIGHT = 100; private final JCGP jcgp; private Stage stage; private final FunctionSelector functionSelector; private PopulationPane populationPane; private GUIConsole console; private SettingsPane settingsPane; private boolean running = false; private final Object printLock = new Object(); private Service cgpService; private Runnable consoleFlush; public static void main(String[] args) { launch(); } public GUI() { jcgp = new JCGP(); functionSelector = new FunctionSelector(jcgp.getResources().getFunctionSet()); consoleFlush = new Runnable() { @Override public void run() { synchronized(printLock) { console.flush(); printLock.notifyAll(); } } }; cgpService = new Service () { @Override protected Task createTask() { Task t = new Task() { @Override protected Void call() throws Exception { while (!isCancelled() && !jcgp.isFinished()) { synchronized (printLock) { Platform.runLater(consoleFlush); jcgp.nextGeneration(); printLock.wait(); } } if (jcgp.isFinished()) { Platform.runLater(new Runnable() { @Override public void run() { runningMode(false); } }); } return null; } }; return t; } }; } @Override public void start(Stage primaryStage) throws Exception { console = new GUIConsole(); jcgp.setConsole(console); stage = primaryStage; /* * Instantiate the various GUI elements here. * * */ BorderPane leftFrame = new BorderPane(); BorderPane experimentLayer = new BorderPane(); populationPane = new PopulationPane(this); settingsPane = new SettingsPane(this); settingsPane.maxWidthProperty().bind(experimentLayer.widthProperty()); console.maxHeightProperty().bind(experimentLayer.heightProperty()); HorizontalDragResize.makeDragResizable(settingsPane); VerticalDragResize.makeDragResizable(console); leftFrame.setCenter(populationPane); leftFrame.setBottom(console); experimentLayer.setCenter(leftFrame); experimentLayer.setRight(settingsPane); primaryStage.setTitle("JCGP"); Pane sceneParent = new Pane(); experimentLayer.prefHeightProperty().bind(sceneParent.heightProperty()); experimentLayer.prefWidthProperty().bind(sceneParent.widthProperty()); sceneParent.getChildren().addAll(experimentLayer, functionSelector); primaryStage.setScene(new Scene(sceneParent)); primaryStage.setMinWidth(800); primaryStage.setMinHeight(600); primaryStage.show(); primaryStage.setOnCloseRequest(new EventHandler() { @Override public void handle(WindowEvent event) { settingsPane.getTestCaseTable().close(); } }); } public void runPause() { if (!jcgp.isFinished() && settingsPane.areParametersValid()) { if (!running) { runningMode(true); cgpService.restart(); } else { cgpService.cancel(); runningMode(false); } } } public void step() { if (!running && !jcgp.isFinished() && settingsPane.areParametersValid()) { if (settingsPane.isResetRequired()) { reset(); } populationPane.unlockOutputs(); jcgp.nextGeneration(); console.flush(); populationPane.updateGenes(); populationPane.relockOutputs(); settingsPane.revalidateParameters(); settingsPane.updateControls(false, jcgp.isFinished()); } } public void reset() { if (!running && settingsPane.areParametersValid()) { setEvaluating(false); jcgp.reset(); settingsPane.applyParameters(); reDraw(); } } public void reDraw() { populationPane.remakeTabs(); settingsPane.revalidateParameters(); settingsPane.updateControls(false, jcgp.isFinished()); console.flush(); } private void runningMode(boolean value) { if (value) { populationPane.unlockOutputs(); if (settingsPane.isResetRequired()) { reset(); } } else { populationPane.updateGenes(); populationPane.relockOutputs(); settingsPane.revalidateParameters(); } populationPane.setDisable(value); settingsPane.updateControls(value, jcgp.isFinished()); running = value; } public void updateFunctionSelector() { functionSelector.remakeFunctions(jcgp.getResources().getFunctionSet()); } public boolean isWorking() { return running; } public void bringFunctionSelector(MouseEvent event, GUINode node) { functionSelector.relocateAndShow(event, node); } public JCGP getExperiment() { return jcgp; } public void evaluateTestCase(TestCase testCase) { populationPane.evaluateTestCase(testCase); } public void hideGeneValues() { populationPane.hideValues(); } public void setEvaluating(boolean value) { populationPane.setEvaluating(value); } public Stage getStage() { return stage; } public void flushConsole() { console.flush(); } public int getChromosomeIndex() { return populationPane.getSelectionModel().getSelectedIndex(); } }