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. *

* 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. * * @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 } private GUIGeneState currentState = GUIGeneState.NEUTRAL; private Text text; private Circle mainCircle; 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. *
* 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. *
* 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() ? true : false); break; case HOVER: mainCircle.setFill(Constants.MEDIUM_HIGHLIGHT_PAINT); setLinesVisible(true); break; case EXTENDED_HOVER: mainCircle.setFill(Constants.SOFT_HIGHLIGHT_PAINT); setLinesVisible(isLocked() ? true : false); break; case ACTIVE_HOVER: mainCircle.setFill(Constants.SOFT_HIGHLIGHT_PAINT); setLinesVisible(true); 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); public boolean isLocked() { return lock > 0; } public void setLock(boolean value) { if (value) { lock++; } else if (lock > 0) { lock--; } else { lock = 0; } } }