diff options
author | Eduardo Pedroni <ep625@york.ac.uk> | 2014-03-24 17:16:51 +0000 |
---|---|---|
committer | Eduardo Pedroni <ep625@york.ac.uk> | 2014-03-24 17:16:51 +0000 |
commit | bc4fafb9d3c60993253f7e78c10338c901de653a (patch) | |
tree | b62e6cacc72c0c8ff645744fdaf2ca007f1fc891 | |
parent | a09124d93c3e31d4e25ffe6c2f0a7663c02c35ed (diff) |
Node grid all done and apparently stable.
21 files changed, 388 insertions, 207 deletions
diff --git a/src/jcgp/GUI.java b/src/jcgp/GUI.java index 284f9ae..669a4e2 100644 --- a/src/jcgp/GUI.java +++ b/src/jcgp/GUI.java @@ -8,26 +8,26 @@ 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.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.gui.Console; import jcgp.gui.SettingsPane; import jcgp.gui.population.ChromosomePane; import jcgp.gui.population.GUIGene; -import jcgp.gui.population.GUINode; -import jcgp.gui.population.GUIOutput; public class GUI extends Application { public static final String NEUTRAL_COLOUR = "#FFFFFF"; - public static final String HARD_HIGHLIGHT_COLOUR = "#89AAD6"; + public static final String HARD_HIGHLIGHT_COLOUR = "#5496FF"; + public static final String MEDIUM_HIGHLIGHT_COLOUR = "#89AAD6"; 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"; - private static CGP cgp; + private static JCGP cgp; public static Resources resources; @@ -41,7 +41,7 @@ public class GUI extends Application { public static void main(String[] args) { - cgp = new CGP(); + cgp = new JCGP(); resources = cgp.getResources(); launch(); @@ -62,7 +62,7 @@ public class GUI extends Application { chromosomes = new ChromosomePane[(int) cgp.getResources().get("popSize")]; Tab tab; for (int i = 0; i < chromosomes.length; i++) { - chromosomes[i] = new ChromosomePane(cgp.getPopulation().getChromosome(i), cgp.getResources()); + chromosomes[i] = new ChromosomePane(cgp.getPopulation().getChromosome(i)); tab = new Tab("Chr " + i); tab.setContent(chromosomes[i]); mainPane.getTabs().add(tab); @@ -92,14 +92,12 @@ public class GUI extends Application { } event.consume(); ((GUIGene) event.getGestureSource()).resetState(); - if (event.getGestureSource() instanceof GUINode) { - ((GUINode) event.getGestureSource()).updateLines(); - } else if (event.getGestureSource() instanceof GUIOutput) { - ((GUIOutput) event.getGestureSource()).updateLine(); - } + ((GUIGene) event.getGestureSource()).updateLines(); + } }); + primaryStage.setMinHeight(600); primaryStage.setMinWidth(800); diff --git a/src/jcgp/CGP.java b/src/jcgp/JCGP.java index 32fb1f0..21161fa 100644 --- a/src/jcgp/CGP.java +++ b/src/jcgp/JCGP.java @@ -25,7 +25,7 @@ import jcgp.parameters.IntegerParameter; import jcgp.parameters.Parameter; import jcgp.population.Population; -public class CGP { +public class JCGP { /** * @@ -125,8 +125,8 @@ public class CGP { allParameters.putAll(moduleParameters); } - public Set<Entry<String, Parameter>> getEntries() { - return allParameters.entrySet(); + public Iterator<Entry<String, Parameter>> iterator() { + return allParameters.entrySet().iterator(); } /* @@ -203,7 +203,7 @@ public class CGP { private Population population = new Population(resources); - public CGP() { + public JCGP() { resources.addModuleParameters(evolutionaryAlgorithm, mutator, fitnessFunction); resources.setTestCases(new TestCase(new Integer[]{1, 2, 3}, new Integer[]{4, 5, 6}), diff --git a/src/jcgp/gui/SettingsPane.java b/src/jcgp/gui/SettingsPane.java index 06c35ec..f7e7767 100644 --- a/src/jcgp/gui/SettingsPane.java +++ b/src/jcgp/gui/SettingsPane.java @@ -6,21 +6,21 @@ import java.util.Map.Entry; import javafx.scene.layout.VBox; import javafx.scene.text.Text; -import jcgp.CGP; +import jcgp.JCGP; import jcgp.gui.settings.GUIIntegerParameter; import jcgp.parameters.IntegerParameter; import jcgp.parameters.Parameter; public class SettingsPane extends VBox { - public SettingsPane(CGP cgp) { + public SettingsPane(JCGP cgp) { super(); setPrefSize(180, 500); Text parameters = new Text("Parameters"); getChildren().add(parameters); - Iterator<Entry<String, Parameter>> it = cgp.getResources().getEntries().iterator(); + 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) { diff --git a/src/jcgp/gui/population/ChromosomePane.java b/src/jcgp/gui/population/ChromosomePane.java index 546314e..0c7b3d2 100644 --- a/src/jcgp/gui/population/ChromosomePane.java +++ b/src/jcgp/gui/population/ChromosomePane.java @@ -5,8 +5,11 @@ import java.util.ArrayList; import javafx.scene.control.ScrollPane; import javafx.scene.layout.Pane; import javafx.scene.shape.Line; -import jcgp.CGP.Resources; +import jcgp.GUI; import jcgp.population.Chromosome; +import jcgp.population.Connection; +import jcgp.population.Input; +import jcgp.population.Node; public class ChromosomePane extends ScrollPane { @@ -19,7 +22,9 @@ public class ChromosomePane extends ScrollPane { private ArrayList<Line> connectionLines; - public ChromosomePane(Chromosome chromosome, Resources resources) { + private boolean target = false; + + public ChromosomePane(Chromosome chromosome) { super(); connectionLines = new ArrayList<Line>(); @@ -28,19 +33,19 @@ public class ChromosomePane extends ScrollPane { // generate the GUIGenes // inputs - guiInputs = new GUIInput[(int) resources.get("inputs")]; + guiInputs = new GUIInput[(int) GUI.resources.get("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[(int) resources.get("rows")][(int) resources.get("columns")]; + guiNodes = new GUINode[(int) GUI.resources.get("rows")][(int) GUI.resources.get("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[(int) resources.get("arity")]; + Line lines[] = new Line[(int) GUI.resources.get("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); @@ -52,15 +57,15 @@ public class ChromosomePane extends ScrollPane { connectionLines.add(lines[l]); } // make the GUI elements - guiNodes[r][c] = new GUINode(this, chromosome.getNode(r, c), resources, lines); + guiNodes[r][c] = new GUINode(this, chromosome.getNode(r, c), lines); } content.getChildren().addAll(guiNodes[r]); } // outputs - guiOutputs = new GUIOutput[(int) resources.get("outputs")]; + guiOutputs = new GUIOutput[(int) GUI.resources.get("outputs")]; for (int i = 0; i < guiOutputs.length; i++) { - xPos = (((int) resources.get("columns") + 1) * (2 * GUIGene.NODE_RADIUS + GUIGene.SPACING)); + xPos = (((int) GUI.resources.get("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); @@ -68,7 +73,7 @@ public class ChromosomePane extends ScrollPane { line.setVisible(false); connectionLines.add(line); // make the GUI elements - guiOutputs[i] = new GUIOutput(this, chromosome.getOutput(i), resources, line); + guiOutputs[i] = new GUIOutput(this, chromosome.getOutput(i), line); content.getChildren().addAll(guiOutputs[i]); } @@ -78,20 +83,41 @@ public class ChromosomePane extends ScrollPane { } - public GUINode getGuiNode(int row, int column) { - return guiNodes[row][column]; - } - - public GUIInput getGuiInput(int index) { - return guiInputs[index]; - } +// 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 GUIOutput getGuiOutput(int index) { - return guiOutputs[index]; + 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 Pane getContentPane() { return content; } + + + public boolean isTarget() { + return target; + } + + public void setTarget(boolean newValue) { + target = newValue; + } } diff --git a/src/jcgp/gui/population/GUIGene.java b/src/jcgp/gui/population/GUIGene.java index 830192c..1be662e 100644 --- a/src/jcgp/gui/population/GUIGene.java +++ b/src/jcgp/gui/population/GUIGene.java @@ -4,6 +4,7 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.scene.Group; import javafx.scene.shape.Circle; import javafx.scene.text.Text; +import jcgp.population.Connection; import jcgp.population.Gene; enum GUIGeneState { @@ -11,6 +12,7 @@ enum GUIGeneState { HOVER, INDIRECT_HOVER, ACTIVE_HOVER, + LOCKED_HOVER, SOURCE, TARGET, NO_CHANGE_TARGET, @@ -52,13 +54,29 @@ public abstract class GUIGene extends Group { return locked > 0; } + public int getLocks() { + return locked; + } + public abstract void setLocked(boolean value); + public abstract void addLocks(int value); + + public abstract void removeLocks(int value); + + public abstract void updateLines(); + public abstract Gene getGene(); + + public abstract void setChangingConnection(Connection newConnection); + + public abstract Connection getChangingConnection(); public abstract void setConnections(GUIGeneState newState); public abstract void resetState(); + public abstract void setConnectionLine(GUIGene gene); + } diff --git a/src/jcgp/gui/population/GUIInput.java b/src/jcgp/gui/population/GUIInput.java index bf872dc..ac1a775 100644 --- a/src/jcgp/gui/population/GUIInput.java +++ b/src/jcgp/gui/population/GUIInput.java @@ -12,8 +12,8 @@ import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import jcgp.GUI; +import jcgp.population.Connection; import jcgp.population.Input; -import jcgp.population.Node; import jcgp.population.Output; public class GUIInput extends GUIGene { @@ -54,13 +54,13 @@ public class GUIInput extends GUIGene { public void handle(MouseDragEvent event) { // the drag has entered this node, react appropriately // this happens even if we are the source of the drag + ((GUIGene) event.getGestureSource()).setConnectionLine((GUIGene) event.getSource()); + if (event.getGestureSource() instanceof GUINode) { - Node source = ((GUINode) event.getGestureSource()).getGene(); - for (int i = 0; i < (int) GUI.resources.get("arity"); i++) { - if (input == source.getConnection(i)) { - stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); - return; - } + Connection source = ((GUINode) event.getGestureSource()).getChangingConnection(); + if (input == source) { + stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); + return; } } else if (event.getGestureSource() instanceof GUIOutput) { Output source = ((GUIOutput) event.getGestureSource()).getGene(); @@ -77,28 +77,45 @@ public class GUIInput extends GUIGene { public void handle(MouseDragEvent event) { // the drag has exited this node, react appropriately // this happens even if we are the source of the drag - if (stateProperty.get() == GUIGeneState.NO_CHANGE_TARGET) { - stateProperty.set(GUIGeneState.INDIRECT_HOVER); - } else { - stateProperty.set(GUIGeneState.NEUTRAL); + parent.setTarget(false); + if (event.isPrimaryButtonDown()) { + if (stateProperty.get() == GUIGeneState.NO_CHANGE_TARGET) { + stateProperty.set(GUIGeneState.INDIRECT_HOVER); + } else { + stateProperty.set(GUIGeneState.NEUTRAL); + ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.INDIRECT_HOVER); + } } } }); - + addEventFilter(MouseDragEvent.MOUSE_DRAG_RELEASED, new EventHandler<MouseDragEvent>() { @Override public void handle(MouseDragEvent event) { + GUIGene source = ((GUIGene) event.getGestureSource()); // set states to reflect the new situation - ((GUIGene) event.getGestureSource()).setState(GUIGeneState.NEUTRAL); - ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.NEUTRAL); - stateProperty.set(GUIGeneState.HOVER); + if (source.isLocked()) { + source.setState(GUIGeneState.HOVER); + source.setConnections(GUIGeneState.HOVER); + } else { + source.setState(GUIGeneState.NEUTRAL); + source.setConnections(GUIGeneState.NEUTRAL); + } + // the user released the drag gesture on this node, react appropriately - if (event.getGestureSource() instanceof GUINode) { - ((GUINode) event.getGestureSource()).setChangingConnection(input); - } else if (event.getGestureSource() instanceof GUIOutput) { - ((GUIOutput) event.getGestureSource()).getGene().setConnection(0, input); - } + if (source.isLocked()) { + // remove locks from the old connection, add the to the new + // note that the old connection may still have locks after this + parent.getGuiGene(source.getChangingConnection()).removeLocks(source.getLocks()); + source.setChangingConnection(input); + addLocks(source.getLocks()); + } else { + source.setChangingConnection(input); + } + + source.updateLines(); + stateProperty.set(GUIGeneState.HOVER); } }); @@ -107,7 +124,7 @@ public class GUIInput extends GUIGene { 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.INDIRECT_HOVER); + stateProperty.set(GUIGeneState.HOVER); } } }); @@ -116,7 +133,7 @@ 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.INDIRECT_HOVER) { + if (stateProperty.get() == GUIGeneState.HOVER) { stateProperty.set(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } @@ -129,27 +146,40 @@ public class GUIInput extends GUIGene { switch (newValue) { case ACTIVE_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); + 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.HARD_HIGHLIGHT_COLOUR)); + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); break; case INDIRECT_HOVER: mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); break; case NEUTRAL: - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); + 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.HARD_HIGHLIGHT_COLOUR)); + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); break; case TARGET: + parent.setTarget(true); mainCircle.setFill(Paint.valueOf(GUI.GOOD_SELECTION_COLOUR)); break; default: @@ -179,11 +209,43 @@ public class GUIInput extends GUIGene { @Override public void resetState() { stateProperty.set(GUIGeneState.NEUTRAL); - } @Override public void setLocked(boolean value) { locked += value ? 1 : -1; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + } + + @Override + public void setChangingConnection(Connection newConnection) { + // do nothing + } + + @Override + public Connection getChangingConnection() { + return null; + } + + @Override + public void addLocks(int value) { + locked += value; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + } + + @Override + public void updateLines() { + // nothing + } + + @Override + public void removeLocks(int value) { + locked -= value; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); + } + + @Override + public void setConnectionLine(GUIGene gene) { + // nothing } } diff --git a/src/jcgp/gui/population/GUINode.java b/src/jcgp/gui/population/GUINode.java index c5ab43a..dd20006 100644 --- a/src/jcgp/gui/population/GUINode.java +++ b/src/jcgp/gui/population/GUINode.java @@ -13,7 +13,6 @@ import javafx.scene.shape.Line; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; -import jcgp.CGP.Resources; import jcgp.GUI; import jcgp.function.Function; import jcgp.population.Connection; @@ -22,7 +21,7 @@ import jcgp.population.Node; import jcgp.population.Output; public class GUINode extends GUIGene { - + private Circle[] sockets; private Circle output; @@ -31,23 +30,23 @@ public class GUINode extends GUIGene { private Label connectionNumber; private Node node; - - private int connectionIndex; - - public GUINode(ChromosomePane parentRef, final Node node, Resources resources, Line[] connectionLines) { + + private int connectionIndex = 0; + + public GUINode(ChromosomePane parentRef, final Node node, Line[] connectionLines) { // store references 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); // set the line ends correctly updateLines(); - + connectionNumber = new Label(); connectionNumber.setStyle("-fx-background-color:rgb(255, 255, 255); -fx-border-color:rgba(0, 0, 0, 0.5); "); connectionNumber.setVisible(false); @@ -73,20 +72,20 @@ public class GUINode extends GUIGene { text.setX(-NODE_RADIUS); text.setVisible(true); - sockets = new Circle[(int) resources.get("arity")]; + 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) resources.get("arity") + 1))) * THETA) - (THETA / 2); + angle = ((((double) (l + 1)) / ((double) ((int) GUI.resources.get("arity") + 1))) * THETA) - (THETA / 2); xPos = -Math.cos(angle) * NODE_RADIUS; yPos = Math.sin(angle) * NODE_RADIUS; sockets[l] = new Circle(xPos, yPos, GUIGene.SOCKET_RADIUS, Paint.valueOf("white")); sockets[l].setId(String.valueOf(l)); sockets[l].setStroke(Paint.valueOf("black")); - + final Circle s = sockets[l]; final int index = l; - + /* * Mouse event handlers on sockets * @@ -98,7 +97,7 @@ public class GUINode extends GUIGene { startFullDrag(); } }); - + s.addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { @@ -108,7 +107,7 @@ public class GUINode extends GUIGene { connectionNumber.setVisible(true); } }); - + s.addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { @@ -116,24 +115,26 @@ public class GUINode extends GUIGene { connectionNumber.setVisible(false); } }); - + s.addEventFilter(MouseDragEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { // mouse was pressed on the socket stateProperty.set(GUIGeneState.SOURCE); connectionIndex = index; - } + } }); - + s.addEventFilter(MouseDragEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { - lines[connectionIndex].setEndX(event.getX() + ((Circle) event.getSource()).getParent().getLayoutX()); - lines[connectionIndex].setEndY(event.getY() + ((Circle) event.getSource()).getParent().getLayoutY()); + if (!parent.isTarget()) { + lines[connectionIndex].setEndX(event.getX() + ((Circle) event.getSource()).getParent().getLayoutX()); + lines[connectionIndex].setEndY(event.getY() + ((Circle) event.getSource()).getParent().getLayoutY()); + } } }); - + s.addEventFilter(MouseDragEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { @@ -142,10 +143,10 @@ public class GUINode extends GUIGene { updateLine(index); stateProperty.set(GUIGeneState.HOVER); } - } + } }); } - + /* * Mouse event handlers on whole gene */ @@ -155,13 +156,12 @@ public class GUINode extends GUIGene { // the drag has entered this node, react appropriately // 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) { - Node source = ((GUINode) event.getGestureSource()).getGene(); - for (int i = 0; i < lines.length; i++) { - if (node == source.getConnection(i)) { - stateProperty.set(GUIGeneState.NO_CHANGE_TARGET); - return; - } + 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(); @@ -181,6 +181,7 @@ public class GUINode extends GUIGene { public void handle(MouseDragEvent event) { // the drag has exited this node, react appropriately // this happens even if we are the source of the drag + parent.setTarget(false); if (event.isPrimaryButtonDown()) { if (event.getGestureSource() == event.getSource()) { stateProperty.set(GUIGeneState.SOURCE); @@ -189,58 +190,74 @@ public class GUINode extends GUIGene { stateProperty.set(GUIGeneState.INDIRECT_HOVER); } else { stateProperty.set(GUIGeneState.NEUTRAL); + ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.INDIRECT_HOVER); } } } } }); - + addEventFilter(MouseDragEvent.MOUSE_DRAG_RELEASED, new EventHandler<MouseDragEvent>() { @Override public void handle(MouseDragEvent event) { + GUIGene source = ((GUIGene) event.getGestureSource()); // set states to reflect the new situation - ((GUIGene) event.getGestureSource()).setState(GUIGeneState.NEUTRAL); - ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.NEUTRAL); - stateProperty.set(GUIGeneState.HOVER); + if (source.isLocked()) { + source.setState(GUIGeneState.HOVER); + source.setConnections(GUIGeneState.HOVER); + } else { + source.setState(GUIGeneState.NEUTRAL); + source.setConnections(GUIGeneState.NEUTRAL); + } + // the user released the drag gesture on this node, react appropriately if (isAllowed((GUIGene) event.getGestureSource(), (GUIGene) event.getSource())) { - if (event.getGestureSource() instanceof GUINode) { - ((GUINode) event.getGestureSource()).setChangingConnection(node); - } else if (event.getGestureSource() instanceof GUIOutput) { - ((GUIOutput) event.getGestureSource()).getGene().setConnection(0, node); + if (source.isLocked()) { + // remove locks from the old connection, add the to the new + // note that the old connection may still have locks after this + parent.getGuiGene(source.getChangingConnection()).removeLocks(source.getLocks()); + source.setChangingConnection(node); + addLocks(source.getLocks()); + } else { + if (source instanceof GUIOutput) { + source.resetState(); + } + source.setChangingConnection(node); } + } - if (event.getGestureSource() instanceof GUINode) { - ((GUINode) event.getGestureSource()).updateLines(); - } else if (event.getGestureSource() instanceof GUIOutput) { - ((GUIOutput) event.getGestureSource()).updateLine(); - } - + source.updateLines(); + stateProperty.set(GUIGeneState.HOVER); } }); - - + + addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() { @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); + } else if (locked > 0) { + setConnections(GUIGeneState.LOCKED_HOVER); } } }); - + addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() { @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()) { - + if (stateProperty.get() == GUIGeneState.HOVER && locked <= 0) { + stateProperty.set(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.NEUTRAL); + } else if (locked > 0) { + if (stateProperty.get() == GUIGeneState.SOURCE || stateProperty.get() == GUIGeneState.FORBIDDEN_TARGET) { + setConnections(GUIGeneState.INDIRECT_HOVER); } else { - stateProperty.set(GUIGeneState.NEUTRAL); - setConnections(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.HOVER); } + } } }); @@ -248,54 +265,67 @@ public class GUINode extends GUIGene { getChildren().addAll(mainCircle, text); getChildren().addAll(sockets); getChildren().addAll(output, connectionNumber); - + stateProperty.addListener(new ChangeListener<GUIGeneState>() { @Override public void changed(ObservableValue<? extends GUIGeneState> observable, GUIGeneState oldValue, GUIGeneState newValue) { - + switch (newValue) { case ACTIVE_HOVER: - mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); - showLines(true); + 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.HARD_HIGHLIGHT_COLOUR)); + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); showLines(true); - if (!isLocked()) { + if ((oldValue != GUIGeneState.LOCKED_HOVER || oldValue != GUIGeneState.SOURCE) && 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: - mainCircle.setFill(Paint.valueOf(GUI.NEUTRAL_COLOUR)); - showLines(false); - if (oldValue == GUIGeneState.ACTIVE_HOVER) { - setConnections(GUIGeneState.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; - } } }); - + for (int c = 0; c < lines.length; c++) { final int i = c; node.connections().get(c).addListener(new ChangeListener<Connection>() { @@ -306,10 +336,15 @@ public class GUINode extends GUIGene { } }); } - + } - - + + @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 @@ -368,7 +403,7 @@ public class GUINode extends GUIGene { updateLine(c); } } - + /** * Toggle visibility of all connection lines. * @@ -389,22 +424,11 @@ public class GUINode extends GUIGene { @Override public void setConnections(GUIGeneState newState) { for (int i = 0; i < lines.length; i++) { - if (node.getConnection(i) instanceof Node) { - if (!parent.getGuiNode(((Node) node.getConnection(i)).getRow(), ((Node) node.getConnection(i)).getColumn()).isLocked()) { - parent.getGuiNode(((Node) node.getConnection(i)).getRow(), ((Node) node.getConnection(i)).getColumn()).setState(newState); - } - } else if (node.getConnection(i) instanceof Input) { - if (!parent.getGuiInput(((Input) node.getConnection(i)).getIndex()).isLocked()) { - parent.getGuiInput(((Input) node.getConnection(i)).getIndex()).setState(newState); - } - } + parent.getGuiGene(node.getConnection(i)).setState(newState); } } - - /** - * This method sets the connection currently being changed to the - * specified value. - */ + + @Override public void setChangingConnection(Connection newConnection) { node.setConnection(connectionIndex, newConnection); } @@ -412,22 +436,48 @@ public class GUINode extends GUIGene { @Override public void resetState() { - stateProperty.set(GUIGeneState.NEUTRAL); - setConnections(GUIGeneState.NEUTRAL); - } + if (locked > 0) { + stateProperty.set(GUIGeneState.HOVER); + } else { + stateProperty.set(GUIGeneState.NEUTRAL); + setConnections(GUIGeneState.NEUTRAL); + } + } @Override public void setLocked(boolean value) { locked += value ? 1 : -1; stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); - + for (int i = 0; i < lines.length; i++) { - if (node.getConnection(i) instanceof Node) { - parent.getGuiNode(((Node) node.getConnection(i)).getRow(), ((Node) node.getConnection(i)).getColumn()).setLocked(value); - } else if (node.getConnection(i) instanceof Input) { - parent.getGuiInput(((Input) node.getConnection(i)).getIndex()).setLocked(value); - } + parent.getGuiGene(node.getConnection(i)).setLocked(value); + } + } + + @Override + public void addLocks(int value) { + locked += value; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); + + for (int i = 0; i < lines.length; i++) { + parent.getGuiGene(node.getConnection(i)).addLocks(value); + } + } + + @Override + public void removeLocks(int value) { + locked -= value; + stateProperty.set(locked > 0 ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); + + for (int i = 0; i < lines.length; i++) { + parent.getGuiGene(node.getConnection(i)).removeLocks(value); } } + + @Override + public void setConnectionLine(GUIGene gene) { + lines[connectionIndex].setEndX(gene.getLayoutX() + NODE_RADIUS); + lines[connectionIndex].setEndY(gene.getLayoutY()); + } } diff --git a/src/jcgp/gui/population/GUIOutput.java b/src/jcgp/gui/population/GUIOutput.java index 415d0fd..87d420e 100644 --- a/src/jcgp/gui/population/GUIOutput.java +++ b/src/jcgp/gui/population/GUIOutput.java @@ -14,7 +14,6 @@ import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import jcgp.GUI; -import jcgp.CGP.Resources; import jcgp.population.Connection; import jcgp.population.Input; import jcgp.population.Node; @@ -30,17 +29,17 @@ public class GUIOutput extends GUIGene { private Output output; - public GUIOutput(ChromosomePane parentRef, final Output output, Resources resources, Line line) { + public GUIOutput(ChromosomePane parentRef, final Output output, Line line) { this.parent = parentRef; this.output = output; this.sourceLine = line; - relocate((((int) resources.get("columns") + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS, + relocate((((int) GUI.resources.get("columns") + 1) * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS, (output.getIndex() * (2 * NODE_RADIUS + SPACING)) + NODE_RADIUS); - + // set the line ends correctly - updateLine(); + updateLines(); mainCircle = new Circle(NODE_RADIUS, Paint.valueOf("white")); mainCircle.setStroke(Paint.valueOf("black")); @@ -56,7 +55,7 @@ public class GUIOutput extends GUIGene { 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"); 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); @@ -111,13 +110,13 @@ public class GUIOutput extends GUIGene { public void handle(MouseEvent event) { if (event.isDragDetect()) { // mouse was released before dragging out of the socket - updateLine(); + updateLines(); stateProperty.set(GUIGeneState.HOVER); } } }); - + /* * Mouse event handlers on whole gene */ @@ -138,28 +137,33 @@ public class GUIOutput extends GUIGene { if (event.getGestureSource() == event.getSource()) { stateProperty.set(GUIGeneState.SOURCE); } else { - if (stateProperty.get() == GUIGeneState.NO_CHANGE_TARGET) { - stateProperty.set(GUIGeneState.INDIRECT_HOVER); - } else { - stateProperty.set(GUIGeneState.NEUTRAL); - } + stateProperty.set(isLocked() ? GUIGeneState.HOVER : GUIGeneState.NEUTRAL); } } } }); - + addEventFilter(MouseDragEvent.MOUSE_DRAG_RELEASED, new EventHandler<MouseDragEvent>() { @Override public void handle(MouseDragEvent event) { // making a connection to an output is illegal // set states to reflect the new situation - ((GUIGene) event.getGestureSource()).setState(GUIGeneState.NEUTRAL); - ((GUIGene) event.getGestureSource()).setConnections(GUIGeneState.NEUTRAL); + GUIGene source = ((GUIGene) event.getGestureSource()); + + if (source.isLocked()) { + source.setState(GUIGeneState.HOVER); + source.setConnections(GUIGeneState.HOVER); + } else { + source.setState(GUIGeneState.NEUTRAL); + source.setConnections(GUIGeneState.NEUTRAL); + } + + source.updateLines(); stateProperty.set(GUIGeneState.HOVER); } }); - - + + addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { @@ -169,7 +173,7 @@ public class GUIOutput extends GUIGene { } } }); - + addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { @@ -188,11 +192,11 @@ public class GUIOutput extends GUIGene { stateProperty.set(GUIGeneState.NEUTRAL); setConnections(GUIGeneState.NEUTRAL); } - + } } }); - + getChildren().addAll(mainCircle, text, socket, connectionLabel); @@ -208,9 +212,11 @@ public class GUIOutput extends GUIGene { mainCircle.setFill(Paint.valueOf(GUI.BAD_SELECTION_COLOUR)); break; case HOVER: - mainCircle.setFill(Paint.valueOf(GUI.HARD_HIGHLIGHT_COLOUR)); + mainCircle.setFill(Paint.valueOf(GUI.MEDIUM_HIGHLIGHT_COLOUR)); sourceLine.setVisible(true); - setConnections(GUIGeneState.ACTIVE_HOVER); + if (!isLocked()) { + setConnections(GUIGeneState.ACTIVE_HOVER); + } break; case INDIRECT_HOVER: mainCircle.setFill(Paint.valueOf(GUI.SOFT_HIGHLIGHT_COLOUR)); @@ -224,28 +230,31 @@ public class GUIOutput extends GUIGene { 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; - + } } }); - + output.sourceProperty().addListener(new ChangeListener<Connection>() { @Override public void changed(ObservableValue<? extends Connection> observable, Connection oldValue, Connection newValue) { - updateLine(); + updateLines(); } }); } - public void updateLine() { + @Override + public void updateLines() { if (output.getSource() instanceof Node) { int row = ((Node) output.getSource()).getRow(), column = ((Node) output.getSource()).getColumn(); @@ -265,11 +274,7 @@ public class GUIOutput extends GUIGene { @Override public void setConnections(GUIGeneState newState) { - if (output.getSource() instanceof Node) { - parent.getGuiNode(((Node) output.getSource()).getRow(), ((Node) output.getSource()).getColumn()).setState(newState); - } else if (output.getSource() instanceof Input) { - parent.getGuiInput(((Input) output.getSource()).getIndex()).setState(newState); - } + parent.getGuiGene(output.getSource()).setState(newState); } @Override @@ -280,15 +285,37 @@ public class GUIOutput extends GUIGene { @Override public void setLocked(boolean value) { - //stateProperty.set(GUIGeneState.HOVER); locked += value ? 1 : -1; setConnections(value ? GUIGeneState.HOVER : GUIGeneState.ACTIVE_HOVER); - - if (output.getSource() instanceof Node) { - parent.getGuiNode(((Node) output.getSource()).getRow(), ((Node) output.getSource()).getColumn()).setLocked(value); - } else if (output.getSource() instanceof Input) { - parent.getGuiInput(((Input) output.getSource()).getIndex()).setLocked(value); - } - + + parent.getGuiGene(output.getSource()).setLocked(value); + + } + + @Override + public void setChangingConnection(Connection newConnection) { + output.setConnection(0, newConnection); } + + @Override + public Connection getChangingConnection() { + return output.getSource(); + } + + @Override + public void addLocks(int value) { + locked += value; + } + + @Override + public void removeLocks(int value) { + locked -= value; + } + + @Override + public void setConnectionLine(GUIGene gene) { + sourceLine.setEndX(gene.getLayoutX() + NODE_RADIUS); + sourceLine.setEndY(gene.getLayoutY()); + } + } diff --git a/src/jcgp/modules/Module.java b/src/jcgp/modules/Module.java index 5ce96b9..4997ce7 100644 --- a/src/jcgp/modules/Module.java +++ b/src/jcgp/modules/Module.java @@ -2,7 +2,7 @@ package jcgp.modules; import java.util.HashMap; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.parameters.Parameter; public interface Module { diff --git a/src/jcgp/modules/ea/EvolutionaryAlgorithm.java b/src/jcgp/modules/ea/EvolutionaryAlgorithm.java index d3fa709..3bc7fcf 100644 --- a/src/jcgp/modules/ea/EvolutionaryAlgorithm.java +++ b/src/jcgp/modules/ea/EvolutionaryAlgorithm.java @@ -1,6 +1,6 @@ package jcgp.modules.ea; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.modules.Module; import jcgp.modules.mutator.Mutator; import jcgp.population.Chromosome; diff --git a/src/jcgp/modules/ea/StandardEA.java b/src/jcgp/modules/ea/StandardEA.java index f2473f5..7e77977 100644 --- a/src/jcgp/modules/ea/StandardEA.java +++ b/src/jcgp/modules/ea/StandardEA.java @@ -2,7 +2,7 @@ package jcgp.modules.ea; import java.util.HashMap; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.modules.mutator.Mutator; import jcgp.parameters.IntegerParameter; import jcgp.parameters.Parameter; diff --git a/src/jcgp/modules/fitness/FitnessFunction.java b/src/jcgp/modules/fitness/FitnessFunction.java index 509c230..f0800b0 100644 --- a/src/jcgp/modules/fitness/FitnessFunction.java +++ b/src/jcgp/modules/fitness/FitnessFunction.java @@ -1,6 +1,6 @@ package jcgp.modules.fitness; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.modules.Module; import jcgp.population.Population; diff --git a/src/jcgp/modules/fitness/TestCaseEvaluator.java b/src/jcgp/modules/fitness/TestCaseEvaluator.java index 1dade74..cd131b5 100644 --- a/src/jcgp/modules/fitness/TestCaseEvaluator.java +++ b/src/jcgp/modules/fitness/TestCaseEvaluator.java @@ -2,7 +2,7 @@ package jcgp.modules.fitness; import java.util.HashMap; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.parameters.Parameter; import jcgp.population.Population; diff --git a/src/jcgp/modules/mutator/Mutator.java b/src/jcgp/modules/mutator/Mutator.java index 5234f45..8dfa0f9 100644 --- a/src/jcgp/modules/mutator/Mutator.java +++ b/src/jcgp/modules/mutator/Mutator.java @@ -1,6 +1,6 @@ package jcgp.modules.mutator; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.modules.Module; import jcgp.population.Chromosome; diff --git a/src/jcgp/modules/mutator/PointMutator.java b/src/jcgp/modules/mutator/PointMutator.java index ea1ed32..51a4390 100644 --- a/src/jcgp/modules/mutator/PointMutator.java +++ b/src/jcgp/modules/mutator/PointMutator.java @@ -4,7 +4,7 @@ import java.util.HashMap; import jcgp.parameters.DoubleParameter; import jcgp.parameters.Parameter; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.population.Chromosome; import jcgp.population.MutableElement; import jcgp.population.Node; diff --git a/src/jcgp/population/Chromosome.java b/src/jcgp/population/Chromosome.java index a7f2ed3..6f50025 100644 --- a/src/jcgp/population/Chromosome.java +++ b/src/jcgp/population/Chromosome.java @@ -2,7 +2,7 @@ package jcgp.population; import java.util.ArrayList; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.exceptions.ParameterMismatchException; public class Chromosome { diff --git a/src/jcgp/population/Population.java b/src/jcgp/population/Population.java index bc9c9e8..586f556 100644 --- a/src/jcgp/population/Population.java +++ b/src/jcgp/population/Population.java @@ -1,6 +1,6 @@ package jcgp.population; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; public class Population { diff --git a/src/jcgp/tests/ChromosomeTests.java b/src/jcgp/tests/ChromosomeTests.java index 6323b88..f4ed79c 100644 --- a/src/jcgp/tests/ChromosomeTests.java +++ b/src/jcgp/tests/ChromosomeTests.java @@ -2,7 +2,7 @@ package jcgp.tests; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.population.Chromosome; import jcgp.population.Connection; import jcgp.population.Input; diff --git a/src/jcgp/tests/NodeTests.java b/src/jcgp/tests/NodeTests.java index 330ef7a..7ce5701 100644 --- a/src/jcgp/tests/NodeTests.java +++ b/src/jcgp/tests/NodeTests.java @@ -1,7 +1,7 @@ package jcgp.tests; import static org.junit.Assert.assertTrue; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.function.Arithmetic; import jcgp.function.Function; import jcgp.population.Chromosome; diff --git a/src/jcgp/tests/OutputTests.java b/src/jcgp/tests/OutputTests.java index 00cfea3..8658fa4 100644 --- a/src/jcgp/tests/OutputTests.java +++ b/src/jcgp/tests/OutputTests.java @@ -2,7 +2,7 @@ package jcgp.tests; import static org.junit.Assert.assertTrue; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.population.Chromosome; import jcgp.population.Connection; import jcgp.population.Output; diff --git a/src/jcgp/tests/PopulationTests.java b/src/jcgp/tests/PopulationTests.java index 474b8d5..ca737d6 100644 --- a/src/jcgp/tests/PopulationTests.java +++ b/src/jcgp/tests/PopulationTests.java @@ -1,7 +1,7 @@ package jcgp.tests; import static org.junit.Assert.assertTrue; -import jcgp.CGP.Resources; +import jcgp.JCGP.Resources; import jcgp.population.Chromosome; import jcgp.population.Population; |