aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/gui/population/GUIGene.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jcgp/gui/population/GUIGene.java')
-rw-r--r--src/jcgp/gui/population/GUIGene.java187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/jcgp/gui/population/GUIGene.java b/src/jcgp/gui/population/GUIGene.java
new file mode 100644
index 0000000..5e6107f
--- /dev/null
+++ b/src/jcgp/gui/population/GUIGene.java
@@ -0,0 +1,187 @@
+package jcgp.gui.population;
+
+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.gui.constants.Constants;
+
+/**
+ * Defines the general behaviour of the visual representation of each chromosome gene.
+ * <br><br>
+ * In practice, this is subclass of {@code javafx.scene.Group} containing a {@code Circle}
+ * object and a {@code Text} object. Subclasses may add further elements to the group, for
+ * instance to display connection input and output sockets.
+ * <br><br>
+ * Genes also contain a locked property. When locked, some gene states behave slightly
+ * differently. This is used so genes remain highlighted even in the neutral state. The
+ * gene lock is in fact recursive; a gene can be locked multiple times and only unlocking
+ * it as many times will actually revert it back to its unlocked state. This allows multiple
+ * pathways to lock the same gene independently without affecting each other; the gene remains
+ * locked until no pathways are locking it.
+ *
+ * @author Eduardo Pedroni
+ *
+ */
+public abstract class GUIGene extends Group {
+
+ /**
+ * This {@code enum} type defines a finite list of all states
+ * a gene can take. Each state represents a particular steady
+ * situation, and has its own GUI appearance associated with it:
+ * a combination of connection line visibility, gene background colour
+ * and other visual characteristics.
+ *
+ * @author Eduardo Pedroni
+ *
+ */
+ public enum GUIGeneState {
+ /**
+ * No user interaction at all.
+ */
+ NEUTRAL,
+ /**
+ * User is simply hovering over the node.
+ */
+ HOVER,
+ /**
+ * User is hovering over a node connected to this one.
+ */
+ EXTENDED_HOVER,
+ /**
+ * User is hovering over an output connected to this gene.
+ */
+ ACTIVE_HOVER,
+
+ GOOD_TARGET,
+
+ NEUTRAL_TARGET,
+
+ BAD_TARGET
+ }
+
+ private GUIGeneState currentState = GUIGeneState.NEUTRAL;
+
+ private Text text;
+ private Circle mainCircle;
+
+ /**
+ * Recursive lock; lock == 0 means unlocked, lock > 0 means locked.
+ * Accessing using {@code setLock(...)}.
+ */
+ private int lock = 0;
+
+ /**
+ * Initialises the {@code Text} and {@code Circle} objects so that all genes are standardised.
+ */
+ protected GUIGene() {
+ text = new Text();
+ text.setFont(Font.font("Arial", 12));
+ text.setTextOrigin(VPos.CENTER);
+ text.setTextAlignment(TextAlignment.CENTER);
+ text.setWrappingWidth(Constants.NODE_RADIUS * 2);
+ text.setX(-Constants.NODE_RADIUS);
+
+ mainCircle = new Circle(Constants.NODE_RADIUS, Constants.NEUTRAL_PAINT);
+ mainCircle.setStroke(Paint.valueOf("black"));
+
+ getChildren().addAll(mainCircle, text);
+ }
+
+ /**
+ * Sets the gene's text field.
+ *
+ * @param newText the text string to be displayed.
+ */
+ public void setText(String newText) {
+ text.setText(newText);
+ }
+
+ /**
+ * @return the gene's current state.
+ */
+ public GUIGeneState getState() {
+ return currentState;
+ }
+
+ /**
+ * Gene states are standardised: all gene subclasses behave the same way in each state.
+ * <br>
+ * This design choice was made for the sake of consistency. Rather than controlling the
+ * appearance of the genes with logic in the state transition method AND the mouse handlers,
+ * the states are now consistent across all types of gene. The mouse handlers implement
+ * whatever logic is necessary to determine the gene's new state given a certain user input,
+ * but the states themselves are the same for all genes.
+ * <br>
+ * The transition logic for each type of gene is defined in its respective handler class:
+ * {@code InputHandlers}, {@code NodeHandlers} and {@code OutputHandlers}.
+ *
+ * @param newState the gene's new state.
+ */
+ public final void setState(GUIGeneState newState) {
+ switch (newState) {
+ case NEUTRAL:
+ mainCircle.setFill(isLocked() ? Constants.HARD_HIGHLIGHT_PAINT : Constants.NEUTRAL_PAINT);
+ setLinesVisible(isLocked());
+ break;
+ case HOVER:
+ mainCircle.setFill(Constants.MEDIUM_HIGHLIGHT_PAINT);
+ setLinesVisible(true);
+ break;
+ case EXTENDED_HOVER:
+ mainCircle.setFill(Constants.SOFT_HIGHLIGHT_PAINT);
+ setLinesVisible(isLocked());
+ break;
+ case ACTIVE_HOVER:
+ mainCircle.setFill(Constants.SOFT_HIGHLIGHT_PAINT);
+ setLinesVisible(true);
+ break;
+ case GOOD_TARGET:
+ mainCircle.setFill(Constants.GOOD_SELECTION_PAINT);
+ break;
+ case NEUTRAL_TARGET:
+ mainCircle.setFill(Constants.NEUTRAL_SELECTION_PAINT);
+ break;
+ case BAD_TARGET:
+ mainCircle.setFill(Constants.BAD_SELECTION_PAINT);
+ break;
+ }
+ currentState = newState;
+ }
+
+ /**
+ * For the sake of practicality, all {@code GUIGene} instances must implement this
+ * method. It sets the visibility of all of the gene's lines, if it has any.
+ *
+ * @param value the visibility value.
+ */
+ protected abstract void setLinesVisible(boolean value);
+
+ /**
+ * @return true if the gene is locked, false otherwise.
+ */
+ public boolean isLocked() {
+ return lock > 0;
+ }
+
+ /**
+ * Locks or unlocks the gene once. Locked genes
+ * behave slightly differently in some states.
+ * <br>
+ * Unlocking an already unlocked gene does nothing.
+ *
+ * @param value true to lock, false to unlock;
+ */
+ public void setLock(boolean value) {
+ if (value) {
+ lock++;
+ } else if (lock > 0) {
+ lock--;
+ } else {
+ lock = 0;
+ }
+ }
+}