From e6dd7711c7dad5e000445208eb5845801f4ccffc Mon Sep 17 00:00:00 2001 From: Eduardo Pedroni Date: Sun, 6 Apr 2014 21:58:53 +0100 Subject: About to make big changes to the way fitness works, committing just in case --- src/jcgp/gui/population/ChromosomePane.java | 133 +++++++++++++++++ src/jcgp/gui/population/FunctionSelector.java | 73 +++++++++ src/jcgp/gui/population/GUIGene.java | 40 +++-- src/jcgp/gui/population/GUIInput.java | 145 ++++++++---------- src/jcgp/gui/population/GUINode.java | 207 ++++++++++++-------------- src/jcgp/gui/population/GUIOutput.java | 142 ++++++++---------- src/jcgp/gui/population/PopulationPane.java | 49 ++++++ 7 files changed, 503 insertions(+), 286 deletions(-) create mode 100644 src/jcgp/gui/population/ChromosomePane.java create mode 100644 src/jcgp/gui/population/FunctionSelector.java create mode 100644 src/jcgp/gui/population/PopulationPane.java (limited to 'src/jcgp/gui/population') diff --git a/src/jcgp/gui/population/ChromosomePane.java b/src/jcgp/gui/population/ChromosomePane.java new file mode 100644 index 0000000..cba58d2 --- /dev/null +++ b/src/jcgp/gui/population/ChromosomePane.java @@ -0,0 +1,133 @@ +package jcgp.gui.population; + +import java.util.ArrayList; + +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.Pane; +import javafx.scene.shape.Line; +import jcgp.backend.population.Chromosome; +import jcgp.backend.population.Connection; +import jcgp.backend.population.Input; +import jcgp.backend.population.Node; +import jcgp.backend.resources.Resources; + + +public class ChromosomePane extends ScrollPane { + + private GUINode[][] guiNodes; + private GUIInput[] guiInputs; + private GUIOutput[] guiOutputs; + + private Pane content; + + private ArrayList connectionLines; + + private ArrayList relock = new ArrayList(); + + private boolean target = false; + + public ChromosomePane(Chromosome chromosome, Resources resources) { + super(); + connectionLines = new ArrayList(); + + content = new Pane(); + content.setId("content pane for genes"); + + // generate the GUIGenes + // inputs + guiInputs = new GUIInput[resources.getInt("inputs")]; + for (int i = 0; i < guiInputs.length; i++) { + // make the GUI elements + guiInputs[i] = new GUIInput(this, chromosome.getInput(i)); + content.getChildren().addAll(guiInputs[i]); + } + // nodes + guiNodes = new GUINode[resources.getInt("rows")][resources.getInt("columns")]; + double angle, xPos, yPos; + for (int r = 0; r < guiNodes.length; r++) { + for (int c = 0; c < guiNodes[r].length; c++) { + // make the connection lines + Line lines[] = new Line[resources.getInt("arity")]; + for (int l = 0; l < lines.length; l++) { + angle = ((((double) (l + 1)) / ((double) (lines.length + 1))) * GUIGene.THETA) - (GUIGene.THETA / 2); + xPos = (-Math.cos(angle) * GUIGene.NODE_RADIUS) + (((c + 1) * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)) + GUIGene.NODE_RADIUS); + yPos = (Math.sin(angle) * GUIGene.NODE_RADIUS) + ((r * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)) + GUIGene.NODE_RADIUS); + + lines[l] = new Line(xPos, yPos, xPos, yPos); + lines[l].setMouseTransparent(true); + lines[l].setVisible(false); + connectionLines.add(lines[l]); + } + // make the GUI elements + guiNodes[r][c] = new GUINode(this, chromosome.getNode(r, c), lines); + } + content.getChildren().addAll(guiNodes[r]); + } + + // outputs + guiOutputs = new GUIOutput[resources.getInt("outputs")]; + for (int i = 0; i < guiOutputs.length; i++) { + xPos = ((resources.getInt("columns") + 1) * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)); + yPos = (chromosome.getOutput(i).getIndex() * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)) + GUIGene.NODE_RADIUS; + // make the line + Line line = new Line(xPos, yPos, xPos, yPos); + line.setMouseTransparent(true); + line.setVisible(false); + connectionLines.add(line); + // make the GUI elements + guiOutputs[i] = new GUIOutput(this, chromosome.getOutput(i), line); + content.getChildren().addAll(guiOutputs[i]); + } + + content.getChildren().addAll(connectionLines); + setPrefWidth(620); + setContent(content); + } + + public GUIGene getGuiGene(Connection gene) { + if (gene instanceof Input) { + return guiInputs[((Input) gene).getIndex()]; + } else if (gene instanceof Node) { + return guiNodes[((Node) gene).getRow()][((Node) gene).getColumn()]; + } else { + // something bad happened! + throw new ClassCastException(); + } + } + + public boolean isTarget() { + return target; + } + + public void setTarget(boolean newValue) { + target = newValue; + } + + public void updateGenes() { + for (int r = 0; r < guiNodes.length; r++) { + for (int c = 0; c < guiNodes[r].length; c++) { + guiNodes[r][c].updateLines(); + guiNodes[r][c].updateFunction(); + } + } + for (int i = 0; i < guiOutputs.length; i++) { + guiOutputs[i].updateLines(); + } + } + + public void unlockOutputs() { + relock.clear(); + for (int i = 0; i < guiOutputs.length; i++) { + if (guiOutputs[i].isLocked()) { + guiOutputs[i].unlock(); + relock.add(guiOutputs[i]); + } + } + } + + public void relockOutputs() { + for (int i = 0; i < relock.size(); i++) { + relock.get(i).lock(); + } + } +} diff --git a/src/jcgp/gui/population/FunctionSelector.java b/src/jcgp/gui/population/FunctionSelector.java new file mode 100644 index 0000000..0a9606f --- /dev/null +++ b/src/jcgp/gui/population/FunctionSelector.java @@ -0,0 +1,73 @@ +package jcgp.gui.population; + +import javafx.event.EventHandler; +import javafx.scene.control.Label; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.VBox; +import jcgp.backend.function.FunctionSet; +import jcgp.gui.GUI; + +public class FunctionSelector extends VBox { + + private GUINode target; + + public FunctionSelector(FunctionSet functionSet) { + setFillWidth(true); + setVisible(false); + setStyle("-fx-border-color: #A0A0A0; -fx-border-width: 1 1 0 1"); + + remakeFunctions(functionSet); + + addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + dismiss(); + } + }); + } + + public void remakeFunctions(final FunctionSet fs) { + getChildren().clear(); + + for (int i = 0; i < fs.getAllowedFunctionCount(); i++) { + final int index = i; + Label l = new Label(fs.getAllowedFunction(i).getName()); + l.setMaxWidth(Double.MAX_VALUE); + l.setStyle("-fx-background-color: #FFFFFF; -fx-border-color: #A0A0A0; -fx-border-width: 0 0 1 0; -fx-padding: 2"); + + l.addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + ((Label) event.getSource()).setStyle("-fx-background-color: " + GUI.SOFT_HIGHLIGHT_COLOUR + "; -fx-border-color: #B0B0B0; -fx-border-width: 0 0 1 0; -fx-padding: 2"); + } + }); + l.addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + ((Label) event.getSource()).setStyle("-fx-background-color: #FFFFFF; -fx-border-color: #A0A0A0; -fx-border-width: 0 0 1 0; -fx-padding: 2"); + } + }); + l.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + target.getGene().setFunction(fs.getAllowedFunction(index)); + target.updateFunction(); + dismiss(); + } + }); + + getChildren().add(l); + } + } + + public void relocateAndShow(MouseEvent event, GUINode node) { + relocate(event.getSceneX() - 5, event.getSceneY() - 5); + target = node; + setVisible(true); + } + + private void dismiss() { + setVisible(false); + } + +} diff --git a/src/jcgp/gui/population/GUIGene.java b/src/jcgp/gui/population/GUIGene.java index 26be2a5..6e9d098 100644 --- a/src/jcgp/gui/population/GUIGene.java +++ b/src/jcgp/gui/population/GUIGene.java @@ -1,12 +1,14 @@ package jcgp.gui.population; -import javafx.beans.property.SimpleObjectProperty; +import javafx.geometry.VPos; import javafx.scene.Group; +import javafx.scene.paint.Paint; import javafx.scene.shape.Circle; +import javafx.scene.text.Font; import javafx.scene.text.Text; +import javafx.scene.text.TextAlignment; import jcgp.backend.population.Connection; import jcgp.backend.population.Gene; -import jcgp.gui.ChromosomePane; enum GUIGeneState { NEUTRAL, @@ -30,27 +32,34 @@ public abstract class GUIGene extends Group { public static final double NODE_TEXT = NODE_RADIUS / 2.5; - protected Text text; - protected Circle mainCircle; + protected Text text = new Text(); + protected Circle mainCircle = new Circle(NODE_RADIUS, Paint.valueOf("white")); - protected SimpleObjectProperty stateProperty = new SimpleObjectProperty(GUIGeneState.NEUTRAL); + private GUIGeneState state = GUIGeneState.NEUTRAL; protected ChromosomePane parent; protected int locked = 0; - - public SimpleObjectProperty stateProperty() { - return stateProperty; + + public GUIGene() { + text.setFont(Font.font("Arial", 12)); + text.setTextOrigin(VPos.CENTER); + text.setTextAlignment(TextAlignment.CENTER); + text.setWrappingWidth(NODE_RADIUS * 2); + text.setX(-NODE_RADIUS); + text.setVisible(true); + + mainCircle.setStroke(Paint.valueOf("black")); } public void setState(GUIGeneState newState) { - stateProperty.set(newState); - } - - public void showText(boolean value) { - text.setVisible(value); + state = newState; } + public GUIGeneState getState() { + return state; + } + public boolean isLocked() { return locked > 0; } @@ -63,6 +72,11 @@ public abstract class GUIGene extends Group { public abstract void addLocks(int value); + /** + * test + * + * @param value + */ public abstract void removeLocks(int value); public abstract void updateLines(); diff --git a/src/jcgp/gui/population/GUIInput.java b/src/jcgp/gui/population/GUIInput.java index f47186c..b4eccaa 100644 --- a/src/jcgp/gui/population/GUIInput.java +++ b/src/jcgp/gui/population/GUIInput.java @@ -1,20 +1,13 @@ package jcgp.gui.population; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; import javafx.event.EventHandler; -import javafx.geometry.VPos; import javafx.scene.input.MouseDragEvent; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Paint; import javafx.scene.shape.Circle; -import javafx.scene.text.Font; -import javafx.scene.text.Text; -import javafx.scene.text.TextAlignment; import jcgp.backend.population.Connection; import jcgp.backend.population.Input; import jcgp.backend.population.Output; -import jcgp.gui.ChromosomePane; import jcgp.gui.GUI; public class GUIInput extends GUIGene { @@ -22,23 +15,16 @@ public class GUIInput extends GUIGene { private Input input; public GUIInput(ChromosomePane parentRef, final Input input) { - + super(); + this.parent = parentRef; this.input = input; relocate(NODE_RADIUS, (input.getIndex() * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS); - mainCircle = new Circle(NODE_RADIUS, Paint.valueOf("white")); - mainCircle.setStroke(Paint.valueOf("black")); - - text = new Text("I: " + input.getIndex()); - text.setFont(Font.font("Arial", 12)); - text.setTextOrigin(VPos.CENTER); - text.setTextAlignment(TextAlignment.CENTER); - text.setWrappingWidth(NODE_RADIUS * 2); - text.setX(-NODE_RADIUS); - text.setVisible(true); + text.setText("I: " + input.getIndex()); + Circle outputSocket = new Circle(NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); outputSocket.setId(String.valueOf(0)); @@ -59,7 +45,7 @@ public class GUIInput extends GUIGene { if (event.getGestureSource() instanceof GUINode) { Connection source = ((GUINode) event.getGestureSource()).getChangingConnection(); if (input == source) { - stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); + setState(GUIGeneState.NO_CHANGE_TARGET); return; } } else if (event.getGestureSource() instanceof GUIOutput) { @@ -68,7 +54,7 @@ public class GUIInput extends GUIGene { ((GUIGene) event.getSource()).setState(GUIGeneState.NO_CHANGE_TARGET); } } - stateProperty.set(GUIGeneState.TARGET); + setState(GUIGeneState.TARGET); } }); @@ -79,10 +65,10 @@ public class GUIInput extends GUIGene { // this happens even if we are the source of the drag parent.setTarget(false); if (event.isPrimaryButtonDown()) { - if (stateProperty.get() == GUIGeneState.NO_CHANGE_TARGET) { - stateProperty.set(GUIGeneState.INDIRECT_HOVER); + if (getState() == GUIGeneState.NO_CHANGE_TARGET) { + setState(GUIGeneState.INDIRECT_HOVER); } else { - stateProperty.set(GUIGeneState.NEUTRAL); + setState(GUIGeneState.NEUTRAL); ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.INDIRECT_HOVER); } } @@ -115,7 +101,7 @@ public class GUIInput extends GUIGene { } source.updateLines(); - stateProperty.set(GUIGeneState.HOVER); + setState(GUIGeneState.HOVER); } }); @@ -123,8 +109,8 @@ public class GUIInput extends GUIGene { @Override public void handle(MouseEvent event) { // cursor has entered this node without dragging, or it is dragging and this is the source - if (stateProperty.get() == GUIGeneState.NEUTRAL) { - stateProperty.set(GUIGeneState.HOVER); + if (getState() == GUIGeneState.NEUTRAL) { + setState(GUIGeneState.HOVER); } } }); @@ -133,62 +119,61 @@ public class GUIInput 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) { - stateProperty.set(GUIGeneState.NEUTRAL); + if (getState() == GUIGeneState.HOVER) { + setState(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } } }); + } + + @Override + public void setState(GUIGeneState newState) { + super.setState(newState); - stateProperty.addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, GUIGeneState oldValue, GUIGeneState newValue) { - - switch (newValue) { - case ACTIVE_HOVER: - if (locked > 0) { - stateProperty().set(GUIGeneState.LOCKED_HOVER); - } else { - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - } - break; - case FORBIDDEN_TARGET: - mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); - break; - case LOCKED_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - break; - case HOVER: - mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); - break; - case INDIRECT_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - break; - case NEUTRAL: - if (locked > 0) { - stateProperty.set(GUIGeneState.HOVER); - } else { - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); - } - break; - case NO_CHANGE_TARGET: - parent.setTarget(true); - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_SELECTION_COLOUR)); - break; - case SOURCE: - mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); - break; - case TARGET: - parent.setTarget(true); - mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); - break; - default: - break; - - } + switch (newState) { + case ACTIVE_HOVER: + if (locked > 0) { + setState(GUIGeneState.LOCKED_HOVER); + } else { + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); } - }); - + break; + case FORBIDDEN_TARGET: + mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); + break; + case LOCKED_HOVER: + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + break; + case HOVER: + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); + break; + case INDIRECT_HOVER: + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + break; + case NEUTRAL: + if (locked > 0) { + setState(GUIGeneState.HOVER); + } else { + mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); + } + break; + case NO_CHANGE_TARGET: + parent.setTarget(true); + mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_SELECTION_COLOUR)); + break; + case SOURCE: + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); + break; + case TARGET: + parent.setTarget(true); + mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); + break; + default: + break; + + } + } @Override @@ -208,13 +193,13 @@ public class GUIInput extends GUIGene { @Override public void resetState() { - stateProperty.set(GUIGeneState.NEUTRAL); + setState(GUIGeneState.NEUTRAL); } @Override void setLocked(boolean value) { locked += value ? 1 : -1; - stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + setState(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); } @Override @@ -230,7 +215,7 @@ public class GUIInput extends GUIGene { @Override public void addLocks(int value) { locked += value; - stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + setState(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); } @Override @@ -241,7 +226,7 @@ public class GUIInput extends GUIGene { @Override public void removeLocks(int value) { locked -= value; - stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); + setState(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); } @Override diff --git a/src/jcgp/gui/population/GUINode.java b/src/jcgp/gui/population/GUINode.java index 450647f..98ba738 100644 --- a/src/jcgp/gui/population/GUINode.java +++ b/src/jcgp/gui/population/GUINode.java @@ -1,22 +1,15 @@ package jcgp.gui.population; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; import javafx.event.EventHandler; -import javafx.geometry.VPos; import javafx.scene.control.Label; import javafx.scene.input.MouseDragEvent; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Paint; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; -import javafx.scene.text.Font; -import javafx.scene.text.Text; -import javafx.scene.text.TextAlignment; import jcgp.backend.population.Connection; import jcgp.backend.population.Input; import jcgp.backend.population.Node; -import jcgp.gui.ChromosomePane; import jcgp.gui.GUI; public class GUINode extends GUIGene { @@ -26,7 +19,8 @@ public class GUINode extends GUIGene { private int connectionIndex = 0; public GUINode(ChromosomePane parentRef, final Node node, Line[] connectionLines) { - + super(); + // store references this.parent = parentRef; this.node = node; @@ -46,21 +40,12 @@ public class GUINode extends GUIGene { 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()); - 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); + text.setText(node.getFunction().getName()); Circle[] sockets = new Circle[GUI.resources.getInt("arity")]; double angle, xPos, yPos; for (int l = 0; l < sockets.length; l++) { - angle = ((((double) (l + 1)) / ((GUI.resources.getDouble("arity") + 1))) * THETA) - (THETA / 2); + angle = (((l + 1) / ((GUI.resources.getDouble("arity") + 1))) * THETA) - (THETA / 2); xPos = -Math.cos(angle) * NODE_RADIUS; yPos = Math.sin(angle) * NODE_RADIUS; @@ -75,7 +60,7 @@ public class GUINode extends GUIGene { * Mouse event handlers on sockets * */ - s.addEventFilter(MouseDragEvent.DRAG_DETECTED, new EventHandler() { + s.addEventFilter(MouseEvent.DRAG_DETECTED, new EventHandler() { @Override public void handle(MouseEvent event) { // the mouse has been dragged out of the socket, this means a full drag is in progress @@ -101,16 +86,16 @@ public class GUINode extends GUIGene { } }); - s.addEventFilter(MouseDragEvent.MOUSE_PRESSED, new EventHandler() { + s.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler() { @Override public void handle(MouseEvent event) { // mouse was pressed on the socket - stateProperty.set(GUIGeneState.SOURCE); + setState(GUIGeneState.SOURCE); connectionIndex = index; } }); - s.addEventFilter(MouseDragEvent.MOUSE_DRAGGED, new EventHandler() { + s.addEventFilter(MouseEvent.MOUSE_DRAGGED, new EventHandler() { @Override public void handle(MouseEvent event) { if (!parent.isTarget()) { @@ -120,14 +105,14 @@ public class GUINode extends GUIGene { } }); - s.addEventFilter(MouseDragEvent.MOUSE_RELEASED, new EventHandler() { + s.addEventFilter(MouseEvent.MOUSE_RELEASED, new EventHandler() { @Override 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) { + setState(GUIGeneState.HOVER); + } else if (getState() == GUIGeneState.SOURCE) { // no connection has been made, fallback resetState(); updateLines(); @@ -139,6 +124,14 @@ public class GUINode extends GUIGene { /* * Mouse event handlers on whole gene */ + + addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + GUI.functionSelector.relocateAndShow(event, (GUINode) event.getSource()); + } + }); + addEventFilter(MouseDragEvent.MOUSE_DRAG_ENTERED, new EventHandler() { @Override public void handle(MouseDragEvent event) { @@ -149,12 +142,12 @@ public class GUINode extends GUIGene { Connection source = ((GUIGene) event.getGestureSource()).getChangingConnection(); if (node == source) { - stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); + setState(GUIGeneState.NO_CHANGE_TARGET); } else { - stateProperty.set(GUIGeneState.TARGET); + setState(GUIGeneState.TARGET); } } else { - stateProperty.set(GUIGeneState.FORBIDDEN_TARGET); + setState(GUIGeneState.FORBIDDEN_TARGET); } } }); @@ -167,12 +160,12 @@ public class GUINode extends GUIGene { parent.setTarget(false); if (event.isPrimaryButtonDown()) { if (event.getGestureSource() == event.getSource()) { - stateProperty.set(GUIGeneState.SOURCE); + setState(GUIGeneState.SOURCE); } else { - if (stateProperty.get() == GUIGeneState.NO_CHANGE_TARGET) { - stateProperty.set(GUIGeneState.INDIRECT_HOVER); + if (getState() == GUIGeneState.NO_CHANGE_TARGET) { + setState(GUIGeneState.INDIRECT_HOVER); } else { - stateProperty.set(GUIGeneState.NEUTRAL); + setState(GUIGeneState.NEUTRAL); ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.INDIRECT_HOVER); } } @@ -210,7 +203,7 @@ public class GUINode extends GUIGene { } source.updateLines(); - stateProperty.set(GUIGeneState.HOVER); + setState(GUIGeneState.HOVER); } }); @@ -219,8 +212,8 @@ public class GUINode extends GUIGene { @Override public void handle(MouseEvent event) { // cursor has entered this node without dragging, or it is dragging and this is the source - if (stateProperty.get() == GUIGeneState.NEUTRAL) { - stateProperty.set(GUIGeneState.HOVER); + if (getState() == GUIGeneState.NEUTRAL) { + setState(GUIGeneState.HOVER); } else if (locked > 0) { setConnections(GUIGeneState.LOCKED_HOVER); } @@ -231,11 +224,11 @@ public class GUINode 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 && locked <= 0) { - stateProperty.set(GUIGeneState.NEUTRAL); + if (getState() == GUIGeneState.HOVER && locked <= 0) { + setState(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } else if (locked > 0) { - if (stateProperty.get() == GUIGeneState.SOURCE || stateProperty.get() == GUIGeneState.FORBIDDEN_TARGET) { + if (getState() == GUIGeneState.SOURCE || getState() == GUIGeneState.FORBIDDEN_TARGET) { setConnections(GUIGeneState.INDIRECT_HOVER); } else { setConnections(GUIGeneState.HOVER); @@ -249,85 +242,72 @@ public class GUINode extends GUIGene { getChildren().addAll(sockets); getChildren().addAll(output, connectionNumber); - stateProperty.addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, GUIGeneState oldValue, GUIGeneState newValue) { + } - switch (newValue) { - case ACTIVE_HOVER: - if (locked > 0) { - stateProperty().set(GUIGeneState.LOCKED_HOVER); - } else { - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - showLines(true); - } - setConnections(GUIGeneState.ACTIVE_HOVER); - break; - case LOCKED_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - break; - case FORBIDDEN_TARGET: - mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); - break; - case HOVER: - mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); - showLines(true); - if (locked <= 0) { - setConnections(GUIGeneState.INDIRECT_HOVER); - } else { - setConnections(GUIGeneState.HOVER); - } - break; - case INDIRECT_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - break; - case NEUTRAL: - if (locked > 0) { - stateProperty.set(GUIGeneState.HOVER); - } else { - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); - showLines(false); - if (oldValue == GUIGeneState.ACTIVE_HOVER) { - setConnections(GUIGeneState.NEUTRAL); - } - } - break; - case NO_CHANGE_TARGET: - parent.setTarget(true); - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_SELECTION_COLOUR)); - break; - case SOURCE: - mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); - break; - case TARGET: - parent.setTarget(true); - mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); - break; - default: - break; + @Override + public void setState(GUIGeneState newState) { + switch (newState) { + case ACTIVE_HOVER: + if (locked > 0) { + setState(GUIGeneState.LOCKED_HOVER); + } else { + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + showLines(true); + } + setConnections(GUIGeneState.ACTIVE_HOVER); + break; + case LOCKED_HOVER: + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + break; + case FORBIDDEN_TARGET: + mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); + break; + case HOVER: + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); + showLines(true); + if (locked <= 0) { + setConnections(GUIGeneState.INDIRECT_HOVER); + } else { + setConnections(GUIGeneState.HOVER); + } + break; + case INDIRECT_HOVER: + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + break; + case NEUTRAL: + if (locked > 0) { + setState(GUIGeneState.HOVER); + } else { + mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); + showLines(false); + if (getState() == GUIGeneState.ACTIVE_HOVER) { + setConnections(GUIGeneState.NEUTRAL); } } - }); - -// for (int c = 0; c < lines.length; c++) { -// final int i = c; -// node.connections().get(c).addListener(new ChangeListener() { -// @Override -// public void changed(ObservableValue observable, -// Connection oldValue, Connection newValue) { -// updateLine(i); -// } -// }); -// } + break; + case NO_CHANGE_TARGET: + parent.setTarget(true); + mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_SELECTION_COLOUR)); + break; + case SOURCE: + mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); + break; + case TARGET: + parent.setTarget(true); + mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); + break; + default: + break; + } + super.setState(newState); } - + @Override public Connection getChangingConnection() { return node.getConnection(connectionIndex); } - private boolean isAllowed(GUIGene source, GUIGene target) { if (source instanceof GUINode) { // if the source is a node, all inputs and some nodes are valid @@ -381,6 +361,7 @@ public class GUINode extends GUIGene { /** * Updates the end of all lines to match the associated connections. */ + @Override public void updateLines() { for (int c = 0; c < lines.length; c++) { updateLine(c); @@ -420,9 +401,9 @@ public class GUINode extends GUIGene { @Override public void resetState() { if (locked > 0) { - stateProperty.set(GUIGeneState.HOVER); + setState(GUIGeneState.HOVER); } else { - stateProperty.set(GUIGeneState.NEUTRAL); + setState(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } @@ -431,7 +412,7 @@ public class GUINode extends GUIGene { @Override void setLocked(boolean value) { locked += value ? 1 : -1; - stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + setState(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); for (int i = 0; i < lines.length; i++) { parent.getGuiGene(node.getConnection(i)).setLocked(value); @@ -441,7 +422,7 @@ public class GUINode extends GUIGene { @Override public void addLocks(int value) { locked += value; - stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + setState(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); for (int i = 0; i < lines.length; i++) { parent.getGuiGene(node.getConnection(i)).addLocks(value); @@ -451,7 +432,7 @@ public class GUINode extends GUIGene { @Override public void removeLocks(int value) { locked -= value; - stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); + setState(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); for (int i = 0; i < lines.length; i++) { parent.getGuiGene(node.getConnection(i)).removeLocks(value); diff --git a/src/jcgp/gui/population/GUIOutput.java b/src/jcgp/gui/population/GUIOutput.java index 9c5dfa5..4a12385 100644 --- a/src/jcgp/gui/population/GUIOutput.java +++ b/src/jcgp/gui/population/GUIOutput.java @@ -1,23 +1,16 @@ package jcgp.gui.population; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; import javafx.event.EventHandler; -import javafx.geometry.VPos; import javafx.scene.control.Label; import javafx.scene.input.MouseDragEvent; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Paint; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; -import javafx.scene.text.Font; -import javafx.scene.text.Text; -import javafx.scene.text.TextAlignment; import jcgp.backend.population.Connection; import jcgp.backend.population.Input; import jcgp.backend.population.Node; import jcgp.backend.population.Output; -import jcgp.gui.ChromosomePane; import jcgp.gui.GUI; public class GUIOutput extends GUIGene { @@ -27,7 +20,8 @@ public class GUIOutput extends GUIGene { private Output output; public GUIOutput(ChromosomePane parentRef, final Output output, Line line) { - + super(); + this.parent = parentRef; this.output = output; this.sourceLine = line; @@ -38,16 +32,7 @@ public class GUIOutput extends GUIGene { // set the line ends correctly updateLines(); - mainCircle = new Circle(NODE_RADIUS, Paint.valueOf("white")); - mainCircle.setStroke(Paint.valueOf("black")); - - text = new Text("O: " + output.getIndex()); - text.setFont(Font.font("Arial", 12)); - text.setTextOrigin(VPos.CENTER); - text.setTextAlignment(TextAlignment.CENTER); - text.setWrappingWidth(NODE_RADIUS * 2); - text.setX(-NODE_RADIUS); - text.setVisible(true); + text.setText("O: " + output.getIndex()); Circle socket = new Circle(-NODE_RADIUS, 0, SOCKET_RADIUS, Paint.valueOf("white")); socket.setId(String.valueOf(0)); @@ -62,7 +47,7 @@ public class GUIOutput extends GUIGene { * Mouse event handlers on sockets * */ - socket.addEventFilter(MouseDragEvent.DRAG_DETECTED, new EventHandler() { + socket.addEventFilter(MouseEvent.DRAG_DETECTED, new EventHandler() { @Override public void handle(MouseEvent event) { // the mouse has been dragged out of the socket, this means a full drag is in progress @@ -86,15 +71,15 @@ public class GUIOutput extends GUIGene { } }); - socket.addEventFilter(MouseDragEvent.MOUSE_PRESSED, new EventHandler() { + socket.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler() { @Override public void handle(MouseEvent event) { // mouse was pressed on the socket - stateProperty.set(GUIGeneState.SOURCE); + setState(GUIGeneState.SOURCE); } }); - socket.addEventFilter(MouseDragEvent.MOUSE_DRAGGED, new EventHandler() { + socket.addEventFilter(MouseEvent.MOUSE_DRAGGED, new EventHandler() { @Override public void handle(MouseEvent event) { if (!parent.isTarget()) { @@ -105,14 +90,14 @@ public class GUIOutput extends GUIGene { } }); - socket.addEventFilter(MouseDragEvent.MOUSE_RELEASED, new EventHandler() { + socket.addEventFilter(MouseEvent.MOUSE_RELEASED, new EventHandler() { @Override public void handle(MouseEvent event) { if (event.isStillSincePress()) { // mouse was released before dragging out of the socket updateLines(); - stateProperty.set(GUIGeneState.HOVER); - } else if (stateProperty.get() == GUIGeneState.SOURCE) { + setState(GUIGeneState.HOVER); + } else if (getState() == GUIGeneState.SOURCE) { // no connection has been made, fallback resetState(); updateLines(); @@ -129,7 +114,7 @@ public class GUIOutput extends GUIGene { @Override public void handle(MouseDragEvent event) { // the drag has entered this node, react appropriately - stateProperty.set(GUIGeneState.FORBIDDEN_TARGET); + setState(GUIGeneState.FORBIDDEN_TARGET); } }); @@ -140,9 +125,9 @@ public class GUIOutput extends GUIGene { // this happens even if we are the source of the drag if (event.isPrimaryButtonDown()) { if (event.getGestureSource() == event.getSource()) { - stateProperty.set(GUIGeneState.SOURCE); + setState(GUIGeneState.SOURCE); } else { - stateProperty.set(isLocked() ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); + setState(isLocked() ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); } } } @@ -164,7 +149,7 @@ public class GUIOutput extends GUIGene { } source.updateLines(); - stateProperty.set(GUIGeneState.HOVER); + setState(GUIGeneState.HOVER); } }); @@ -173,8 +158,8 @@ public class GUIOutput extends GUIGene { @Override public void handle(MouseEvent event) { // cursor has entered this node without dragging, or it is dragging and this is the source - if (stateProperty.get() == GUIGeneState.NEUTRAL) { - stateProperty.set(GUIGeneState.HOVER); + if (getState() == GUIGeneState.NEUTRAL) { + setState(GUIGeneState.HOVER); } } }); @@ -190,8 +175,8 @@ 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 && !isLocked()) { - stateProperty.set(GUIGeneState.NEUTRAL); + if (getState() == GUIGeneState.HOVER && !isLocked()) { + setState(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } } @@ -199,52 +184,49 @@ public class GUIOutput extends GUIGene { getChildren().addAll(mainCircle, text, socket, connectionLabel); + + } - stateProperty.addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, GUIGeneState oldValue, GUIGeneState newValue) { - - - switch (newValue) { - case ACTIVE_HOVER: - break; - case FORBIDDEN_TARGET: - mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); - break; - case HOVER: - mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); - sourceLine.setVisible(true); - if (!isLocked()) { - setConnections(GUIGeneState.ACTIVE_HOVER); - } - break; - case INDIRECT_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - break; - case NEUTRAL: - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); - sourceLine.setVisible(false); - break; - case NO_CHANGE_TARGET: - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_SELECTION_COLOUR)); - break; - case SOURCE: - mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); - setConnections(GUIGeneState.NEUTRAL); - setConnections(GUIGeneState.INDIRECT_HOVER); - break; - case TARGET: - mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); - break; - default: - break; - - } + @Override + public void setState(GUIGeneState newState) { + super.setState(newState); + + switch (newState) { + case ACTIVE_HOVER: + break; + case FORBIDDEN_TARGET: + mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); + break; + case HOVER: + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); + sourceLine.setVisible(true); + if (!isLocked()) { + setConnections(GUIGeneState.ACTIVE_HOVER); } - }); - + break; + case INDIRECT_HOVER: + mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + break; + case NEUTRAL: + mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); + sourceLine.setVisible(false); + break; + case NO_CHANGE_TARGET: + mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_SELECTION_COLOUR)); + break; + case SOURCE: + mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); + setConnections(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.INDIRECT_HOVER); + break; + case TARGET: + mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); + break; + default: + break; + } } - + @Override public void updateLines() { if (output.getSource() instanceof Node) { @@ -272,10 +254,10 @@ public class GUIOutput extends GUIGene { @Override public void resetState() { if (locked > 0) { - stateProperty.set(GUIGeneState.HOVER); + setState(GUIGeneState.HOVER); setConnections(GUIGeneState.HOVER); } else { - stateProperty.set(GUIGeneState.NEUTRAL); + setState(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } } @@ -318,14 +300,14 @@ public class GUIOutput extends GUIGene { public void unlock() { if (isLocked()) { setLocked(false); - stateProperty.set(GUIGeneState.NEUTRAL); + setState(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } } public void lock() { if (!isLocked()) { - stateProperty.set(GUIGeneState.HOVER); + setState(GUIGeneState.HOVER); setLocked(true); } } diff --git a/src/jcgp/gui/population/PopulationPane.java b/src/jcgp/gui/population/PopulationPane.java new file mode 100644 index 0000000..3a83a86 --- /dev/null +++ b/src/jcgp/gui/population/PopulationPane.java @@ -0,0 +1,49 @@ +package jcgp.gui.population; + +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import jcgp.JCGP; +import jcgp.backend.population.Population; +import jcgp.backend.resources.Resources; + +public class PopulationPane extends TabPane { + + public PopulationPane(JCGP jcgp) { + super(); + + setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE); + + remakeTabs(jcgp.getPopulation(), jcgp.getResources()); + } + + public void remakeTabs(Population population, Resources resources) { + getTabs().clear(); + + Tab tab; + ChromosomePane cp; + for (int i = 0; i < resources.getInt("popSize"); i++) { + cp = new ChromosomePane(population.getChromosome(i), resources); + tab = new Tab("Chr " + i); + tab.setContent(cp); + getTabs().add(tab); + } + } + + public void updateGenes() { + for (int i = 0; i < getChildrenUnmodifiable().size(); i++) { + ((ChromosomePane) getTabs().get(i).getContent()).updateGenes(); + } + } + + public void unlockOutputs() { + for (int i = 0; i < getChildrenUnmodifiable().size(); i++) { + ((ChromosomePane) getTabs().get(i).getContent()).unlockOutputs(); + } + } + + public void relockOutputs() { + for (int i = 0; i < getChildrenUnmodifiable().size(); i++) { + ((ChromosomePane) getTabs().get(i).getContent()).relockOutputs(); + } + } +} -- cgit v1.2.3