diff options
author | Eduardo Pedroni <ep625@york.ac.uk> | 2014-03-26 21:34:37 +0000 |
---|---|---|
committer | Eduardo Pedroni <ep625@york.ac.uk> | 2014-03-26 21:34:37 +0000 |
commit | 2bf2d3ac2c578de481ecfd545d58be73c5628996 (patch) | |
tree | ec47cfeedaed5bf677cab1bc9e910782369fe127 | |
parent | bc4fafb9d3c60993253f7e78c10338c901de653a (diff) |
Node grid has been refactored a few times, settings pane is almost complete, console is all done.
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | src/jcgp/GUI.java | 85 | ||||
-rw-r--r-- | src/jcgp/JCGP.java | 109 | ||||
-rw-r--r-- | src/jcgp/function/FunctionSet.java | 23 | ||||
-rw-r--r-- | src/jcgp/gui/Console.java | 13 | ||||
-rw-r--r-- | src/jcgp/gui/GUIConsole.java | 96 | ||||
-rw-r--r-- | src/jcgp/gui/SettingsPane.java | 253 | ||||
-rw-r--r-- | src/jcgp/gui/population/ChromosomePane.java | 21 | ||||
-rw-r--r-- | src/jcgp/gui/population/GUIGene.java | 2 | ||||
-rw-r--r-- | src/jcgp/gui/population/GUIInput.java | 3 | ||||
-rw-r--r-- | src/jcgp/gui/population/GUINode.java | 74 | ||||
-rw-r--r-- | src/jcgp/gui/population/GUIOutput.java | 42 | ||||
-rw-r--r-- | src/jcgp/gui/settings/GUIBooleanParameter.java | 24 | ||||
-rw-r--r-- | src/jcgp/gui/settings/GUIDoubleParameter.java | 33 | ||||
-rw-r--r-- | src/jcgp/gui/settings/GUIIntegerParameter.java | 18 | ||||
-rw-r--r-- | src/jcgp/gui/settings/GUIParameter.java | 5 | ||||
-rw-r--r-- | src/jcgp/modules/Module.java | 5 | ||||
-rw-r--r-- | src/jcgp/modules/ea/StandardEA.java | 16 | ||||
-rw-r--r-- | src/jcgp/modules/fitness/TestCaseEvaluator.java | 12 | ||||
-rw-r--r-- | src/jcgp/modules/mutator/PointMutator.java | 12 |
20 files changed, 644 insertions, 220 deletions
@@ -189,4 +189,20 @@ Registering parameters is no longer necessary. The CGP class will query modules 21/3 -FunctionSet has been rewritten to allow only certain functions to be deactivated, the GUI will now be integrated.
\ No newline at end of file + +FunctionSet has been rewritten to allow only certain functions to be deactivated, the GUI will now be integrated. + + +25/3 + +http://andrewtill.blogspot.ch/2012/12/dragging-to-resize-javafx-region.html + +Looking into drag-to-resize for the console and the menu. All sorted. + +Settings and console can be resized but not beyond a minimum value, and the +grid node grows to fill the void. + + +26/3 + +Sorted out the console, resizing is mint, settings are nearing completion and the node grid has been refactored multiple times.
\ No newline at end of file diff --git a/src/jcgp/GUI.java b/src/jcgp/GUI.java index 669a4e2..a893494 100644 --- a/src/jcgp/GUI.java +++ b/src/jcgp/GUI.java @@ -1,43 +1,66 @@ package jcgp; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + import javafx.application.Application; -import javafx.event.EventHandler; -import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TabPane.TabClosingPolicy; -import javafx.scene.input.MouseDragEvent; -import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import jcgp.JCGP.Resources; -import jcgp.gui.Console; +import jcgp.gui.GUIConsole; import jcgp.gui.SettingsPane; import jcgp.gui.population.ChromosomePane; -import jcgp.gui.population.GUIGene; 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 = "#89AAD6"; + // 89AAD6 + public static final String MEDIUM_HIGHLIGHT_COLOUR = "#75BAFF"; public static final String SOFT_HIGHLIGHT_COLOUR = "#C7DFFF"; - public static final String GOOD_SELECTION_COLOUR = "#BDFFC2"; - public static final String NEUTRAL_SELECTION_COLOUR = "#FBFFB8"; - public static final String BAD_SELECTION_COLOUR = "#FF9C9C"; + // BDFFC2 + public static final String GOOD_SELECTION_COLOUR = "#38C25B"; + // FBFFB8 + public static final String NEUTRAL_SELECTION_COLOUR = "#EDEB72"; + // FF9C9C + public static final String BAD_SELECTION_COLOUR = "#F53D3D"; + + /* Sizes and distances */ + + public static final double RESIZE_MARGIN = 5.0; + + public static final double SETTINGS_WIDTH = 190; + 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 mainPane; - private static Console console; + private static GUIConsole console = new GUIConsole(); private SettingsPane settings; + + public static final PrintStream out = new PrintStream(new OutputStream() { + @Override + public void write(int b) throws IOException { + console.getTextArea().appendText(String.valueOf((char) b)); + } + }); public static void main(String[] args) { @@ -45,7 +68,6 @@ public class GUI extends Application { resources = cgp.getResources(); launch(); - } @Override @@ -70,41 +92,24 @@ public class GUI extends Application { settings = new SettingsPane(cgp); - mainPane.setPrefHeight(500); + //mainPane.setPrefHeight(500); + + leftPane = new BorderPane(); + leftPane.setCenter(mainPane); + leftPane.setBottom(console); window = new BorderPane(); - window.setCenter(mainPane); - window.setRight(settings); - primaryStage.addEventFilter(MouseDragEvent.MOUSE_DRAG_RELEASED, new EventHandler<MouseDragEvent>() { - @Override - public void handle(MouseDragEvent event) { - // preemptively determine whether this event will reach a GUIGene - // sodding Controls... - if (event.getTarget() instanceof Node) { - Node source = ((Node) event.getTarget()); - while (source != null) { - if (source instanceof GUIGene) { - return; - } - source = source.getParent(); - } - } - event.consume(); - ((GUIGene) event.getGestureSource()).resetState(); - ((GUIGene) event.getGestureSource()).updateLines(); + window.setCenter(leftPane); + window.setRight(settings); - } - }); + //primaryStage.setMinHeight(600); + //primaryStage.setMinWidth(800); - - primaryStage.setMinHeight(600); - primaryStage.setMinWidth(800); + primaryStage.setTitle("JCGP"); primaryStage.setScene(new Scene(window)); primaryStage.show(); - - } } diff --git a/src/jcgp/JCGP.java b/src/jcgp/JCGP.java index 21161fa..dc121c9 100644 --- a/src/jcgp/JCGP.java +++ b/src/jcgp/JCGP.java @@ -5,7 +5,6 @@ import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Random; -import java.util.Set; import javafx.beans.property.Property; import jcgp.function.Arithmetic; @@ -34,12 +33,12 @@ public class JCGP { * */ public static class Resources { - private HashMap<String, Parameter> moduleParameters = new HashMap<String, Parameter>(); - private HashMap<String, Parameter> coreParameters = new HashMap<String, Parameter>(); - private HashMap<String, Parameter> allParameters = new HashMap<String, Parameter>(); + private HashMap<String, Parameter> parameters = new HashMap<String, Parameter>(); private Random numberGenerator; + private TestCase[] testCases; + // function sets private FunctionSet[] functionSets = new FunctionSet[] { new Arithmetic(), @@ -47,86 +46,91 @@ public class JCGP { new BooleanLogic() }; private FunctionSet functionSet = functionSets[0]; - private TestCase[] testCases; - public Resources() { createCoreParameters(); numberGenerator = new Random((int) get("seed")); - functionSet = functionSets[0]; set("arity", functionSet.getMaxArity()); } public Object get(String key) { - return allParameters.get(key).getValue(); + return parameters.get(key).getValue(); + } + + public int getInt(String key) { + return (int) parameters.get(key).getValue(); + } + + public double getDouble(String key) { + return (double) parameters.get(key).getValue(); + } + + public boolean getBoolean(String key) { + return (boolean) parameters.get(key).getValue(); } public void set(String key, Object value) { - allParameters.get(key).setValue(value); + parameters.get(key).setValue(value); } public Property<?> getProperty(String key) { - return allParameters.get(key).valueProperty(); + return parameters.get(key).valueProperty(); + } + + public Parameter getParameter(String key) { + return parameters.get(key); } public void setManagedParameter(String key, boolean value) { - allParameters.get(key).setManaged(value); + parameters.get(key).setManaged(value); } public void setHiddenParameter(String key, boolean value) { - allParameters.get(key).setHidden(value); + parameters.get(key).setHidden(value); } public boolean contains(String key) { - return allParameters.containsKey(key); + return parameters.containsKey(key); } private void createCoreParameters() { - coreParameters.put("rows", new IntegerParameter(9, "Rows")); - coreParameters.put("columns", new IntegerParameter(10, "Columns")); - coreParameters.put("inputs", new IntegerParameter(3, "Inputs")); - coreParameters.put("outputs", new IntegerParameter(3, "Outputs")); - coreParameters.put("popSize", new IntegerParameter(5, "Population")); - coreParameters.put("levelsBack", new IntegerParameter(2, "Levels back")); + parameters.put("rows", new IntegerParameter(8, "Rows")); + parameters.put("columns", new IntegerParameter(9, "Columns")); + parameters.put("inputs", new IntegerParameter(3, "Inputs")); + parameters.put("outputs", new IntegerParameter(3, "Outputs")); + parameters.put("popSize", new IntegerParameter(5, "Population")); + parameters.put("levelsBack", new IntegerParameter(2, "Levels back")); - coreParameters.put("nodes", new IntegerParameter(90, "Nodes", true, true)); + parameters.put("nodes", new IntegerParameter(72, "Nodes", true, true)); - coreParameters.put("generations", new IntegerParameter(1000000, "Generations")); - coreParameters.put("currentGen", new IntegerParameter(0, "Generation")); - coreParameters.put("runs", new IntegerParameter(5, "Runs")); + parameters.put("generations", new IntegerParameter(1000000, "Generations")); + parameters.put("currentGen", new IntegerParameter(0, "Generation", true, false)); + parameters.put("runs", new IntegerParameter(5, "Runs")); - coreParameters.put("arity", new IntegerParameter(0, "Max arity", true, true)); + parameters.put("arity", new IntegerParameter(0, "Max arity", true, true)); - coreParameters.put("seed", new IntegerParameter(123, "Random seed", true, true)); + parameters.put("seed", new IntegerParameter(123, "Seed")); - coreParameters.put("debug", new BooleanParameter(false, "Debug")); - - allParameters.putAll(coreParameters); + parameters.put("debug", new BooleanParameter(false, "Debug")); + parameters.put("report", new IntegerParameter(1, "Report")); } + // TODO fix this up private void resetParameters(EvolutionaryAlgorithm ea, Mutator mu, FitnessFunction ff) { - Iterator<Entry<String, Parameter>> it = coreParameters.entrySet().iterator(); + Iterator<Entry<String, Parameter>> it = parameters.entrySet().iterator(); while (it.hasNext()) { ((Parameter) ((Map.Entry<String, Parameter>) it.next()).getValue()).reset(); } - - allParameters.clear(); - allParameters.putAll(coreParameters); - addModuleParameters(ea, mu, ff); } - private void addModuleParameters(EvolutionaryAlgorithm ea, Mutator mu, FitnessFunction ff) { - moduleParameters.clear(); - moduleParameters.putAll(ea.activate(this)); - moduleParameters.putAll(mu.activate(this)); - moduleParameters.putAll(ff.activate(this)); - - allParameters.putAll(moduleParameters); - } - + /** + * + * + * @return the iterator for the set of base parameters + */ public Iterator<Entry<String, Parameter>> iterator() { - return allParameters.entrySet().iterator(); + return parameters.entrySet().iterator(); } /* @@ -145,10 +149,10 @@ public class JCGP { } /* - * Function set functions + * FunctionSet functions */ public Function getRandomFunction() { - return functionSet.getFunction(numberGenerator.nextInt(functionSet.getFunctionCount())); + return functionSet.getFunction(numberGenerator.nextInt(functionSet.getAllowedFunctionCount())); } public Function getFunction(int index) { @@ -159,6 +163,20 @@ public class JCGP { functionSet = functionSets[index]; } + /** + * @return the functionSets + */ + public FunctionSet[] getFunctionSets() { + return functionSets; + } + + /** + * @return the functionSet + */ + public FunctionSet getFunctionSet() { + return functionSet; + } + /* * Test cases */ @@ -204,7 +222,6 @@ public class JCGP { public JCGP() { - resources.addModuleParameters(evolutionaryAlgorithm, mutator, fitnessFunction); resources.setTestCases(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{4, 5, 6}), new TestCase(new Integer[]{1, 12, 4}, new Integer[]{6, 21, 2})); diff --git a/src/jcgp/function/FunctionSet.java b/src/jcgp/function/FunctionSet.java index 07b4ea4..49ff7e7 100644 --- a/src/jcgp/function/FunctionSet.java +++ b/src/jcgp/function/FunctionSet.java @@ -3,6 +3,7 @@ package jcgp.function; import java.util.ArrayList; import java.util.Iterator; + /** * * @author Eduardo Pedroni @@ -14,14 +15,14 @@ public abstract class FunctionSet { protected int maxArity; protected String name; -// public int getTotalFunctionCount() { -// return functionList.length; -// } - - public int getFunctionCount() { + public int getAllowedFunctionCount() { return allowedFunctions.size(); } + public int getTotalFunctionCount() { + return functionList.length; + } + public Function getFunction(int index) { return allowedFunctions.get(index); } @@ -35,14 +36,15 @@ public abstract class FunctionSet { } public void disableFunction(int index) { - for (Iterator<Function> iterator = allowedFunctions.iterator(); iterator.hasNext();) { - if (index < functionList.length) { + if (index < functionList.length) { + for (Iterator<Function> iterator = allowedFunctions.iterator(); iterator.hasNext();) { Function function = (Function) iterator.next(); if (function == functionList[index]) { iterator.remove(); } } - + } else { + throw new IndexOutOfBoundsException("Function " + index + " does not exist, the set only has " + functionList.length + " functions."); } } @@ -51,4 +53,9 @@ public abstract class FunctionSet { allowedFunctions.add(functionList[index]); } } + + @Override + public String toString() { + return name; + } }
\ No newline at end of file diff --git a/src/jcgp/gui/Console.java b/src/jcgp/gui/Console.java deleted file mode 100644 index 9008531..0000000 --- a/src/jcgp/gui/Console.java +++ /dev/null @@ -1,13 +0,0 @@ -package jcgp.gui; - -import javafx.scene.control.TextArea; - -public class Console extends TextArea { - - public Console() { - super(); - setDisable(true); - setPrefHeight(100); - } - -} diff --git a/src/jcgp/gui/GUIConsole.java b/src/jcgp/gui/GUIConsole.java new file mode 100644 index 0000000..a14a23b --- /dev/null +++ b/src/jcgp/gui/GUIConsole.java @@ -0,0 +1,96 @@ +package jcgp.gui; + +import javafx.event.EventHandler; +import javafx.scene.Cursor; +import javafx.scene.control.TextArea; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import jcgp.GUI; + +public class GUIConsole extends AnchorPane { + + private boolean dragging; + private TextArea textArea = new TextArea("Welcome to JCGP!\n"); + + public GUIConsole() { + super(); + textArea.setEditable(false); + textArea.setWrapText(true); + + //setStyle("-fx-border-width: 5 0 0 0; -fx-border-color: #D1D1D1"); + + setResizeListeners(); + + AnchorPane.setTopAnchor(textArea, GUI.RESIZE_MARGIN); + AnchorPane.setBottomAnchor(textArea, 0.0); + AnchorPane.setRightAnchor(textArea, 0.0); + AnchorPane.setLeftAnchor(textArea, 0.0); + + setMinHeight(GUI.CONSOLE_HEIGHT); + setPrefHeight(GUI.CONSOLE_HEIGHT); + + getChildren().add(textArea); + + } + + /** + * + */ + private void setResizeListeners() { + setOnMousePressed(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + // ignore clicks outside of the draggable margin + if(isInDraggableZone(event)) { + dragging = true; + } + } + }); + setOnMouseDragged(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + if(dragging) { + double newHeight = getHeight() - event.getY(); + if (newHeight >= getMinHeight()) { + setPrefHeight(newHeight); + } else { + setPrefHeight(getMinHeight()); + } + } + } + }); + setOnMouseMoved(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + if(isInDraggableZone(event) || dragging) { + setCursor(Cursor.V_RESIZE); + } + else { + setCursor(Cursor.DEFAULT); + } + } + }); + setOnMouseReleased(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + dragging = false; + setCursor(Cursor.DEFAULT); + } + }); + textArea.setOnMouseEntered(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + setCursor(Cursor.DEFAULT); + } + }); + } + + private boolean isInDraggableZone(MouseEvent event) { + return event.getY() < (GUI.RESIZE_MARGIN); + } + + public TextArea getTextArea() { + return textArea; + } + +} diff --git a/src/jcgp/gui/SettingsPane.java b/src/jcgp/gui/SettingsPane.java index f7e7767..594147f 100644 --- a/src/jcgp/gui/SettingsPane.java +++ b/src/jcgp/gui/SettingsPane.java @@ -1,37 +1,266 @@ package jcgp.gui; +import java.util.ArrayList; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.geometry.Insets; +import javafx.scene.Cursor; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; import javafx.scene.layout.VBox; +import javafx.scene.text.Font; import javafx.scene.text.Text; +import jcgp.GUI; import jcgp.JCGP; +import jcgp.function.FunctionSet; +import jcgp.gui.settings.GUIBooleanParameter; +import jcgp.gui.settings.GUIDoubleParameter; import jcgp.gui.settings.GUIIntegerParameter; +import jcgp.gui.settings.GUIParameter; +import jcgp.modules.ea.EvolutionaryAlgorithm; +import jcgp.modules.fitness.FitnessFunction; +import jcgp.modules.mutator.Mutator; +import jcgp.parameters.BooleanParameter; +import jcgp.parameters.DoubleParameter; import jcgp.parameters.IntegerParameter; import jcgp.parameters.Parameter; -public class SettingsPane extends VBox { +public class SettingsPane extends AnchorPane { + private VBox mainContainer, eas, mutators, ffs; + private boolean dragging = false; + public SettingsPane(JCGP cgp) { super(); - setPrefSize(180, 500); + setResizeListeners(); - Text parameters = new Text("Parameters"); - getChildren().add(parameters); + //setStyle("-fx-border-width: 0 0 0 5; -fx-border-color: #D1D1D1"); - Iterator<Entry<String, Parameter>> it = cgp.getResources().iterator(); - while (it.hasNext()) { - Parameter p = (Parameter) ((Map.Entry<String, Parameter>) it.next()).getValue(); - if (p instanceof IntegerParameter) { - GUIIntegerParameter gip = new GUIIntegerParameter((IntegerParameter) p); - getChildren().add(gip); - } - } + mainContainer = new VBox(); + + AnchorPane.setTopAnchor(mainContainer, 0.0); + AnchorPane.setBottomAnchor(mainContainer, 0.0); + AnchorPane.setRightAnchor(mainContainer, 0.0); + AnchorPane.setLeftAnchor(mainContainer, GUI.RESIZE_MARGIN); + mainContainer.setPadding(new Insets(5, 0, 0, 0)); + mainContainer.setSpacing(6); + + setMinWidth(GUI.SETTINGS_WIDTH); + setPrefWidth(GUI.SETTINGS_WIDTH); + + makeBaseParameters(cgp); + makeEAParameters(cgp); + mainContainer.getChildren().add(eas); + + makeMutatorParameters(cgp); + mainContainer.getChildren().add(mutators); + makeFitnessFunctionParameters(cgp); + mainContainer.getChildren().add(ffs); + + makeNodeFunctionParameters(cgp); + + getChildren().add(mainContainer); + } + + private void makeBaseParameters(JCGP cgp) { + VBox vb = new VBox(); + vb.setSpacing(2); + + Text header = new Text("Base Parameters"); + header.setFont(Font.font("Arial", 14)); + header.setUnderline(true); + + vb.getChildren().add(header); + + ArrayList<GUIParameter> gp = new ArrayList<GUIParameter>(); + + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("rows"))); + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("columns"))); + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("inputs"))); + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("outputs"))); + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("levelsBack"))); + + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("popSize"))); + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("generations"))); + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("runs"))); + + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("seed"))); + gp.add(new GUIIntegerParameter((IntegerParameter) cgp.getResources().getParameter("report"))); + gp.add(new GUIBooleanParameter((BooleanParameter) cgp.getResources().getParameter("debug"))); + + vb.getChildren().addAll(gp); + + mainContainer.getChildren().add(vb); + } + + private void makeEAParameters(JCGP cgp) { + eas = new VBox(); + eas.setSpacing(2); + + Text header = new Text("EA"); + header.setFont(Font.font("Arial", 14)); + header.setUnderline(true); + + eas.getChildren().add(header); + + ComboBox<EvolutionaryAlgorithm> eab = new ComboBox<EvolutionaryAlgorithm>(); + eab.getItems().addAll(cgp.getEvolutionaryAlgorithms()); + eab.getSelectionModel().select(cgp.getEvolutionaryAlgorithm()); + eab.prefWidthProperty().bind(mainContainer.widthProperty()); + eas.getChildren().add(eab); + + addParameters(cgp.getEvolutionaryAlgorithm().getLocalParameters().entrySet().iterator(), eas); + } + + private void makeMutatorParameters(JCGP cgp) { + mutators = new VBox(); + mutators.setSpacing(2); + + Text header = new Text("Mutator"); + header.setFont(Font.font("Arial", 14)); + header.setUnderline(true); + + mutators.getChildren().add(header); + + ComboBox<Mutator> mb = new ComboBox<Mutator>(); + mb.getItems().addAll(cgp.getMutators()); + mb.getSelectionModel().select(cgp.getMutator()); + mb.prefWidthProperty().bind(mainContainer.widthProperty()); + mutators.getChildren().add(mb); + + addParameters(cgp.getMutator().getLocalParameters().entrySet().iterator(), mutators); + } + + private void makeFitnessFunctionParameters(JCGP cgp) { + ffs = new VBox(); + ffs.setSpacing(2); + + Text header = new Text("Fitness Function"); + header.setFont(Font.font("Arial", 14)); + header.setUnderline(true); + + ffs.getChildren().add(header); + + ComboBox<FitnessFunction> ff = new ComboBox<FitnessFunction>(); + ff.getItems().addAll(cgp.getFitnessFunctions()); + ff.getSelectionModel().select(cgp.getFitnessFunction()); + ff.prefWidthProperty().bind(mainContainer.widthProperty()); + ffs.getChildren().add(ff); + + addParameters(cgp.getFitnessFunction().getLocalParameters().entrySet().iterator(), ffs); + } + + private void makeNodeFunctionParameters(JCGP cgp) { + VBox vb = new VBox(); + vb.setSpacing(2); + + Text header = new Text("Node Functions"); + header.setFont(Font.font("Arial", 14)); + header.setUnderline(true); + + vb.getChildren().add(header); + + ComboBox<FunctionSet> nf = new ComboBox<FunctionSet>(); + nf.getItems().addAll(cgp.getResources().getFunctionSets()); + nf.getSelectionModel().select(cgp.getResources().getFunctionSet()); + nf.prefWidthProperty().bind(mainContainer.widthProperty()); + vb.getChildren().add(nf); + + // TODO make this function re-usable + addFunctions(cgp.getResources().getFunctionSet(), vb); + + mainContainer.getChildren().add(vb); } + /** + * @param cgp + * @param vb + */ + private void addParameters(Iterator<Entry<String, Parameter>> it, VBox vb) { + while (it.hasNext()) { + Parameter parameter = ((Map.Entry<String, Parameter>) it.next()).getValue(); + if (parameter instanceof IntegerParameter) { + vb.getChildren().add(new GUIIntegerParameter((IntegerParameter) parameter)); + } else if (parameter instanceof DoubleParameter) { + vb.getChildren().add(new GUIDoubleParameter((DoubleParameter) parameter)); + } else if (parameter instanceof BooleanParameter) { + vb.getChildren().add(new GUIBooleanParameter((BooleanParameter) parameter)); + } + } + } + private void addFunctions(final FunctionSet fs, VBox vb) { + CheckBox cb; + for (int i = 0; i < fs.getTotalFunctionCount(); i++) { + cb = new CheckBox(fs.getFunction(i).getName()); + cb.setId(String.valueOf(i)); + cb.setSelected(true); + final int index = i; + cb.setOnAction(new EventHandler<ActionEvent>() { + @Override + public void handle(ActionEvent event) { + if (((CheckBox) event.getSource()).isSelected()) { + fs.enableFunction(index); + } else { + fs.disableFunction(index); + } + } + }); + vb.getChildren().add(cb); + } + } + private void setResizeListeners() { + setOnMousePressed(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + if(isInDraggableZone(event)) { + dragging = true; + } + } + }); + setOnMouseDragged(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + if(dragging) { + double newWidth = getWidth() - event.getX(); + if (newWidth >= getMinWidth()) { + setPrefWidth(newWidth); + } else { + setPrefWidth(getMinWidth()); + } + } + } + }); + setOnMouseMoved(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + if(isInDraggableZone(event) || dragging) { + setCursor(Cursor.H_RESIZE); + } + else { + setCursor(Cursor.DEFAULT); + } + } + }); + setOnMouseReleased(new EventHandler<MouseEvent>() { + @Override + public void handle(MouseEvent event) { + dragging = false; + setCursor(Cursor.DEFAULT); + } + }); + } + private boolean isInDraggableZone(MouseEvent event) { + return event.getX() < (GUI.RESIZE_MARGIN); + } + } diff --git a/src/jcgp/gui/population/ChromosomePane.java b/src/jcgp/gui/population/ChromosomePane.java index 0c7b3d2..7fa8a54 100644 --- a/src/jcgp/gui/population/ChromosomePane.java +++ b/src/jcgp/gui/population/ChromosomePane.java @@ -28,6 +28,8 @@ public class ChromosomePane extends ScrollPane { super(); connectionLines = new ArrayList<Line>(); + //setMouseTransparent(true); + content = new Pane(); content.setId("content pane for genes"); @@ -82,19 +84,6 @@ public class ChromosomePane extends ScrollPane { setContent(content); } - -// public GUINode getGuiNode(int row, int column) { -// return guiNodes[row][column]; -// } -// -// public GUIInput getGuiInput(int index) { -// return guiInputs[index]; -// } -// -// public GUIOutput getGuiOutput(int index) { -// return guiOutputs[index]; -// } - public GUIGene getGuiGene(Connection gene) { if (gene instanceof Input) { return guiInputs[((Input) gene).getIndex()]; @@ -107,11 +96,6 @@ public class ChromosomePane extends ScrollPane { } - public Pane getContentPane() { - return content; - } - - public boolean isTarget() { return target; } @@ -119,5 +103,4 @@ public class ChromosomePane extends ScrollPane { public void setTarget(boolean newValue) { target = newValue; } - } diff --git a/src/jcgp/gui/population/GUIGene.java b/src/jcgp/gui/population/GUIGene.java index 1be662e..3addca7 100644 --- a/src/jcgp/gui/population/GUIGene.java +++ b/src/jcgp/gui/population/GUIGene.java @@ -27,7 +27,7 @@ public abstract class GUIGene extends Group { public static final double THETA = Math.PI / 1.4; public static final double SOCKET_RADIUS = Math.sqrt(NODE_RADIUS) / 1.8; - public static final double NODE_TEXT = 0; + public static final double NODE_TEXT = NODE_RADIUS / 2.5; protected Text text; protected Circle mainCircle; diff --git a/src/jcgp/gui/population/GUIInput.java b/src/jcgp/gui/population/GUIInput.java index ac1a775..84e8a2a 100644 --- a/src/jcgp/gui/population/GUIInput.java +++ b/src/jcgp/gui/population/GUIInput.java @@ -18,7 +18,6 @@ import jcgp.population.Output; public class GUIInput extends GUIGene { - private Circle outputSocket; private Input input; public GUIInput(ChromosomePane parentRef, final Input input) { @@ -40,7 +39,7 @@ public class GUIInput extends GUIGene { text.setX(-NODE_RADIUS); text.setVisible(true); - outputSocket = new Circle(NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); + Circle outputSocket = new Circle(NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); outputSocket.setId(String.valueOf(0)); outputSocket.setStroke(Paint.valueOf("black")); diff --git a/src/jcgp/gui/population/GUINode.java b/src/jcgp/gui/population/GUINode.java index dd20006..eeacb9e 100644 --- a/src/jcgp/gui/population/GUINode.java +++ b/src/jcgp/gui/population/GUINode.java @@ -14,23 +14,14 @@ import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import jcgp.GUI; -import jcgp.function.Function; import jcgp.population.Connection; import jcgp.population.Input; import jcgp.population.Node; -import jcgp.population.Output; public class GUINode extends GUIGene { - private Circle[] sockets; - private Circle output; - private Line[] lines; - - private Label connectionNumber; - private Node node; - private int connectionIndex = 0; public GUINode(ChromosomePane parentRef, final Node node, Line[] connectionLines) { @@ -39,7 +30,7 @@ public class GUINode extends GUIGene { this.parent = parentRef; this.node = node; this.lines = connectionLines; - + // move the GUIGene to the right position relocate(((node.getColumn() + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS, (node.getRow() * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS); @@ -47,32 +38,25 @@ public class GUINode extends GUIGene { // set the line ends correctly updateLines(); - connectionNumber = new Label(); + final Label connectionNumber = new Label(); connectionNumber.setStyle("-fx-background-color:rgb(255, 255, 255); -fx-border-color:rgba(0, 0, 0, 0.5); "); connectionNumber.setVisible(false); - output = new Circle(NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); + Circle output = new Circle(NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); output.setStroke(Paint.valueOf("black")); mainCircle = new Circle(NODE_RADIUS, Paint.valueOf("white")); mainCircle.setStroke(Paint.valueOf("black")); text = new Text(node.getFunction().getName()); - this.node.functionProperty().addListener(new ChangeListener<Function>() { - @Override - public void changed(ObservableValue<? extends Function> observable, - Function oldValue, Function newValue) { - text.setText(newValue.getName()); - } - }); - text.setFont(Font.font("Arial", 12)); + text.setFont(Font.font("Arial", NODE_TEXT)); text.setTextOrigin(VPos.CENTER); text.setTextAlignment(TextAlignment.CENTER); text.setWrappingWidth(NODE_RADIUS * 2); text.setX(-NODE_RADIUS); text.setVisible(true); - sockets = new Circle[(int) GUI.resources.get("arity")]; + Circle[] sockets = new Circle[(int) GUI.resources.get("arity")]; double angle, xPos, yPos; for (int l = 0; l < sockets.length; l++) { angle = ((((double) (l + 1)) / ((double) ((int) GUI.resources.get("arity") + 1))) * THETA) - (THETA / 2); @@ -137,11 +121,15 @@ public class GUINode extends GUIGene { s.addEventFilter(MouseDragEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() { @Override - public void handle(MouseEvent event) { - if (event.isDragDetect()) { + public void handle(MouseEvent event) { + if (event.isStillSincePress()) { // mouse was released before dragging out of the socket updateLine(index); stateProperty.set(GUIGeneState.HOVER); + } else if (stateProperty.get() == GUIGeneState.SOURCE) { + // no connection has been made, fallback + resetState(); + updateLines(); } } }); @@ -157,19 +145,13 @@ public class GUINode extends GUIGene { // this happens even if we are the source of the drag if (isAllowed((GUIGene) event.getGestureSource(), (GUIGene) event.getSource())) { ((GUIGene) event.getGestureSource()).setConnectionLine((GUIGene) event.getSource()); - if (event.getGestureSource() instanceof GUINode) { - Connection source = ((GUINode) event.getGestureSource()).getChangingConnection(); - if (node == source) { - stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); - return; - } - } else if (event.getGestureSource() instanceof GUIOutput) { - Output source = ((GUIOutput) event.getGestureSource()).getGene(); - if (((GUIGene) event.getSource()).getGene() == source.getSource()) { - ((GUIGene) event.getSource()).setState(GUIGeneState.NO_CHANGE_TARGET); - } + + Connection source = ((GUIGene) event.getGestureSource()).getChangingConnection(); + if (node == source) { + stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); + } else { + stateProperty.set(GUIGeneState.TARGET); } - stateProperty.set(GUIGeneState.TARGET); } else { stateProperty.set(GUIGeneState.FORBIDDEN_TARGET); } @@ -289,7 +271,7 @@ public class GUINode extends GUIGene { case HOVER: mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); showLines(true); - if ((oldValue != GUIGeneState.LOCKED_HOVER || oldValue != GUIGeneState.SOURCE) && locked <= 0) { + if (locked <= 0) { setConnections(GUIGeneState.INDIRECT_HOVER); } else { setConnections(GUIGeneState.HOVER); @@ -326,16 +308,16 @@ public class GUINode extends GUIGene { } }); - for (int c = 0; c < lines.length; c++) { - final int i = c; - node.connections().get(c).addListener(new ChangeListener<Connection>() { - @Override - public void changed(ObservableValue<? extends Connection> observable, - Connection oldValue, Connection newValue) { - updateLine(i); - } - }); - } +// for (int c = 0; c < lines.length; c++) { +// final int i = c; +// node.connections().get(c).addListener(new ChangeListener<Connection>() { +// @Override +// public void changed(ObservableValue<? extends Connection> observable, +// Connection oldValue, Connection newValue) { +// updateLine(i); +// } +// }); +// } } diff --git a/src/jcgp/gui/population/GUIOutput.java b/src/jcgp/gui/population/GUIOutput.java index 87d420e..57042eb 100644 --- a/src/jcgp/gui/population/GUIOutput.java +++ b/src/jcgp/gui/population/GUIOutput.java @@ -21,10 +21,6 @@ import jcgp.population.Output; public class GUIOutput extends GUIGene { - private Circle socket; - - private Label connectionLabel; - private Line sourceLine; private Output output; @@ -52,11 +48,11 @@ public class GUIOutput extends GUIGene { text.setX(-NODE_RADIUS); text.setVisible(true); - socket = new Circle(-NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); + Circle socket = new Circle(-NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); socket.setId(String.valueOf(0)); socket.setStroke(Paint.valueOf("black")); - connectionLabel = new Label("S"); + final Label connectionLabel = new Label("S"); connectionLabel.setStyle("-fx-background-color:rgb(255, 255, 255); -fx-border-color:rgba(0, 0, 0, 0.5); "); connectionLabel.relocate(socket.getCenterX() + 5, socket.getCenterY() - 10); connectionLabel.setVisible(false); @@ -100,19 +96,27 @@ public class GUIOutput extends GUIGene { socket.addEventFilter(MouseDragEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { - sourceLine.setEndX(event.getX() + ((Circle) event.getSource()).getParent().getLayoutX()); - sourceLine.setEndY(event.getY() + ((Circle) event.getSource()).getParent().getLayoutY()); + if (!parent.isTarget()) { + sourceLine.setEndX(event.getX() + ((Circle) event.getSource()).getParent().getLayoutX()); + sourceLine.setEndY(event.getY() + ((Circle) event.getSource()).getParent().getLayoutY()); + } + } }); socket.addEventFilter(MouseDragEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { - if (event.isDragDetect()) { + if (event.isStillSincePress()) { // mouse was released before dragging out of the socket updateLines(); stateProperty.set(GUIGeneState.HOVER); + } else if (stateProperty.get() == GUIGeneState.SOURCE) { + // no connection has been made, fallback + resetState(); + updateLines(); } + } }); @@ -185,14 +189,9 @@ public class GUIOutput extends GUIGene { @Override public void handle(MouseEvent event) { // cursor has left this node without dragging, or it is dragging and this is the source - if (stateProperty.get() == GUIGeneState.HOVER) { - if (isLocked()) { - - } else { - stateProperty.set(GUIGeneState.NEUTRAL); - setConnections(GUIGeneState.NEUTRAL); - } - + if (stateProperty.get() == GUIGeneState.HOVER && !isLocked()) { + stateProperty.set(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.NEUTRAL); } } }); @@ -279,8 +278,13 @@ public class GUIOutput extends GUIGene { @Override public void resetState() { - stateProperty.set(GUIGeneState.NEUTRAL); - setConnections(GUIGeneState.NEUTRAL); + if (locked > 0) { + stateProperty.set(GUIGeneState.HOVER); + setConnections(GUIGeneState.HOVER); + } else { + stateProperty.set(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.NEUTRAL); + } } @Override diff --git a/src/jcgp/gui/settings/GUIBooleanParameter.java b/src/jcgp/gui/settings/GUIBooleanParameter.java new file mode 100644 index 0000000..7b20c3b --- /dev/null +++ b/src/jcgp/gui/settings/GUIBooleanParameter.java @@ -0,0 +1,24 @@ +package jcgp.gui.settings; + +import javafx.geometry.Pos; +import javafx.scene.control.CheckBox; +import jcgp.parameters.BooleanParameter; + +public class GUIBooleanParameter extends GUIParameter { + + public GUIBooleanParameter(BooleanParameter parameter) { + setAlignment(Pos.CENTER_LEFT); + setSpacing(5); + + this.parameter = parameter; + + value = new CheckBox(parameter.getName()); + ((CheckBox) value).setSelected(parameter.getValue()); + + value.setDisable(parameter.isManaged()); + + getChildren().add(value); + + } + +} diff --git a/src/jcgp/gui/settings/GUIDoubleParameter.java b/src/jcgp/gui/settings/GUIDoubleParameter.java new file mode 100644 index 0000000..d61899b --- /dev/null +++ b/src/jcgp/gui/settings/GUIDoubleParameter.java @@ -0,0 +1,33 @@ +package jcgp.gui.settings; + +import javafx.geometry.Pos; +import javafx.scene.control.TextField; +import javafx.scene.layout.Priority; +import javafx.scene.text.Text; +import jcgp.GUI; +import jcgp.parameters.DoubleParameter; + +public class GUIDoubleParameter extends GUIParameter { + + public GUIDoubleParameter(DoubleParameter parameter) { + setAlignment(Pos.CENTER_LEFT); + setSpacing(5); + + this.parameter = parameter; + + name = new Text(parameter.getName()); + value = new TextField(String.valueOf(parameter.getValue())); + + ((TextField) value).setAlignment(Pos.CENTER_RIGHT); + + setHgrow(value, Priority.ALWAYS); + + name.setWrappingWidth(GUI.WRAP_WIDTH); + + value.setDisable(parameter.isManaged()); + + getChildren().addAll(name, value); + + } + +} diff --git a/src/jcgp/gui/settings/GUIIntegerParameter.java b/src/jcgp/gui/settings/GUIIntegerParameter.java index 2bf5480..b7a23a4 100644 --- a/src/jcgp/gui/settings/GUIIntegerParameter.java +++ b/src/jcgp/gui/settings/GUIIntegerParameter.java @@ -1,23 +1,31 @@ package jcgp.gui.settings; +import javafx.geometry.Pos; import javafx.scene.control.TextField; +import javafx.scene.layout.Priority; import javafx.scene.text.Text; +import jcgp.GUI; import jcgp.parameters.IntegerParameter; public class GUIIntegerParameter extends GUIParameter { - private TextField value; - public GUIIntegerParameter(IntegerParameter parameter) { + setAlignment(Pos.CENTER_LEFT); + setSpacing(5); + this.parameter = parameter; name = new Text(parameter.getName()); - value = new TextField(String.valueOf((int) parameter.getValue())); + value = new TextField(String.valueOf(parameter.getValue())); + + ((TextField) value).setAlignment(Pos.CENTER_RIGHT); + + setHgrow(value, Priority.ALWAYS); + + name.setWrappingWidth(GUI.WRAP_WIDTH); value.setDisable(parameter.isManaged()); getChildren().addAll(name, value); - } - } diff --git a/src/jcgp/gui/settings/GUIParameter.java b/src/jcgp/gui/settings/GUIParameter.java index d084060..0547758 100644 --- a/src/jcgp/gui/settings/GUIParameter.java +++ b/src/jcgp/gui/settings/GUIParameter.java @@ -1,13 +1,14 @@ package jcgp.gui.settings; +import javafx.scene.control.Control; import javafx.scene.layout.HBox; import javafx.scene.text.Text; import jcgp.parameters.Parameter; public abstract class GUIParameter extends HBox { - + protected Parameter parameter; - protected Text name; + protected Control value; } diff --git a/src/jcgp/modules/Module.java b/src/jcgp/modules/Module.java index 4997ce7..7cf0b8d 100644 --- a/src/jcgp/modules/Module.java +++ b/src/jcgp/modules/Module.java @@ -7,5 +7,8 @@ import jcgp.parameters.Parameter; public interface Module { - public HashMap<String, Parameter> activate(Resources parameters); + public void activate(Resources parameters); + + public HashMap<String, Parameter> getLocalParameters(); + } diff --git a/src/jcgp/modules/ea/StandardEA.java b/src/jcgp/modules/ea/StandardEA.java index 7e77977..1d27004 100644 --- a/src/jcgp/modules/ea/StandardEA.java +++ b/src/jcgp/modules/ea/StandardEA.java @@ -61,9 +61,19 @@ public class StandardEA implements EvolutionaryAlgorithm { } @Override - public HashMap<String, Parameter> activate(Resources parameters) { - parameters.setManagedParameter("popSize", true); - + public void activate(Resources parameters) { + parameters.getParameter("popSize").setManaged(true); + } + + @Override + public HashMap<String, Parameter> getLocalParameters() { return localParameters; } + + @Override + public String toString() { + return "(μ + λ)"; + } + + } diff --git a/src/jcgp/modules/fitness/TestCaseEvaluator.java b/src/jcgp/modules/fitness/TestCaseEvaluator.java index cd131b5..77b282c 100644 --- a/src/jcgp/modules/fitness/TestCaseEvaluator.java +++ b/src/jcgp/modules/fitness/TestCaseEvaluator.java @@ -28,7 +28,17 @@ public class TestCaseEvaluator implements FitnessFunction { } @Override - public HashMap<String, Parameter> activate(Resources parameters) { + public void activate(Resources parameters) { + // nothing + } + + @Override + public HashMap<String, Parameter> getLocalParameters() { return new HashMap<String, Parameter>(); } + + @Override + public String toString() { + return "Test case"; + } } diff --git a/src/jcgp/modules/mutator/PointMutator.java b/src/jcgp/modules/mutator/PointMutator.java index 51a4390..e9be153 100644 --- a/src/jcgp/modules/mutator/PointMutator.java +++ b/src/jcgp/modules/mutator/PointMutator.java @@ -42,8 +42,18 @@ public class PointMutator implements Mutator { } @Override - public HashMap<String, Parameter> activate(Resources parameters) { + public void activate(Resources parameters) { + // nothing + } + + @Override + public HashMap<String, Parameter> getLocalParameters() { return localParameters; } + @Override + public String toString() { + return "Point mutation"; + } + } |