aboutsummaryrefslogtreecommitdiffstats
path: root/src/jcgp/gui/population/GUIGene.java
blob: 02b87e718c543a2d542fab77ec85bccbeb70f447 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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. 
 * 
 * @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.
	 * <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() ? 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;
		}
	}
}