diff --git a/src/main/java/de/neemann/digital/fsm/FSM.java b/src/main/java/de/neemann/digital/fsm/FSM.java
index fc14459b1..6aee6a03e 100644
--- a/src/main/java/de/neemann/digital/fsm/FSM.java
+++ b/src/main/java/de/neemann/digital/fsm/FSM.java
@@ -301,7 +301,7 @@ public class FSM {
* @param dt the time step
* @param except element which is fixed
*/
- public void move(int dt, Movable except) {
+ public void move(int dt, MouseMovable except) {
if (state != MovingState.STOP) {
calculateForces();
if (state == MovingState.BOTH)
@@ -377,8 +377,8 @@ public class FSM {
* @param pos the position
* @return the element or null
*/
- public Movable getMovable(Vector pos) {
- Movable found = null;
+ public MouseMovable getMovable(Vector pos) {
+ Movable> found = null;
float dist = Float.MAX_VALUE;
for (Transition t : transitions)
if (t.matches(pos)) {
@@ -400,7 +400,8 @@ public class FSM {
dist = d;
found = s;
}
- }
+ } else if (s.matchesInitial(pos))
+ return s.getInitialMarkerMovable();
return found;
}
@@ -439,7 +440,7 @@ public class FSM {
* @param movable the element changed
* @param prop the property which has changed
*/
- void wasModified(Movable movable, Movable.Property prop) {
+ void wasModified(Movable> movable, Movable.Property prop) {
modified = true;
if (movable instanceof State) {
diff --git a/src/main/java/de/neemann/digital/fsm/MouseMovable.java b/src/main/java/de/neemann/digital/fsm/MouseMovable.java
new file mode 100644
index 000000000..64d94c457
--- /dev/null
+++ b/src/main/java/de/neemann/digital/fsm/MouseMovable.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020 Helmut Neemann.
+ * Use of this source code is governed by the GPL v3 license
+ * that can be found in the LICENSE file.
+ */
+package de.neemann.digital.fsm;
+
+import de.neemann.digital.draw.graphics.VectorFloat;
+import de.neemann.digital.draw.graphics.VectorInterface;
+
+/**
+ * Element which can be moved by the mouse
+ */
+public interface MouseMovable {
+ /**
+ * @return the position
+ */
+ VectorInterface getPos();
+
+ /**
+ * Sets the position by the mouse.
+ * Is called while dragging.
+ *
+ * @param pos the position
+ */
+ void setPosByMouse(VectorFloat pos);
+
+ /**
+ * Sets the position by the mouse.
+ * Is called if mouse button is released.
+ *
+ * @param pos the position
+ */
+ void setPos(VectorFloat pos);
+}
diff --git a/src/main/java/de/neemann/digital/fsm/Movable.java b/src/main/java/de/neemann/digital/fsm/Movable.java
index a3fa6a1e5..0a6e1f059 100644
--- a/src/main/java/de/neemann/digital/fsm/Movable.java
+++ b/src/main/java/de/neemann/digital/fsm/Movable.java
@@ -12,9 +12,9 @@ import de.neemann.digital.draw.graphics.VectorFloat;
*
* @param the type of the implementing class
*/
-public class Movable {
+public class Movable> implements MouseMovable {
- enum Property {POS, REMOVED, CONDITION, NAME, NUMBER, MOUSEPOS, VALUES, INITIAL, ADDED}
+ enum Property {POS, REMOVED, CONDITION, NAME, NUMBER, MOUSEPOS, VALUES, INITIAL, ADDED, INITIAL_ANGLE}
private static final float MASS = 50f;
private static final float FRICTION = 0.8f;
diff --git a/src/main/java/de/neemann/digital/fsm/State.java b/src/main/java/de/neemann/digital/fsm/State.java
index 890886bed..21bfe37c4 100644
--- a/src/main/java/de/neemann/digital/fsm/State.java
+++ b/src/main/java/de/neemann/digital/fsm/State.java
@@ -99,9 +99,7 @@ public class State extends Movable {
if (isInitial) {
Vector initRad = new Vector(INIT_RAD, INIT_RAD);
- int r = radius + INIT_RAD * 6;
- double angle = 2 * Math.PI / 32 * initialAngle;
- VectorInterface pos = getPos().add(new VectorFloat((float) (Math.cos(angle) * r), -(float) (Math.sin(angle) * r)));
+ VectorInterface pos = getInitialMarkerPos();
gr.drawCircle(pos.sub(initRad), pos.add(initRad), Style.FILLED);
VectorInterface delta = getPos().sub(pos).norm();
VectorInterface a0 = pos.add(delta.mul(INIT_RAD + Style.FILLED.getThickness()));
@@ -122,6 +120,15 @@ public class State extends Movable {
}
}
+ /**
+ * @return the initial marker position
+ */
+ VectorInterface getInitialMarkerPos() {
+ int r = radius + INIT_RAD * 6;
+ double angle = 2 * Math.PI / 32 * initialAngle;
+ return getPos().add(new VectorFloat((float) (Math.cos(angle) * r), -(float) (Math.sin(angle) * r)));
+ }
+
/**
* @return the radius of the state
*/
@@ -176,6 +183,18 @@ public class State extends Movable {
return pos.sub(getPos()).len() <= radius;
}
+ /**
+ * Returns true if the position matches the states initial marker
+ *
+ * @param pos the position
+ * @return true if pos inside of the states initial marker
+ */
+ public boolean matchesInitial(Vector pos) {
+ if (!isInitial)
+ return false;
+ return pos.sub(getInitialMarkerPos()).len() <= INIT_RAD;
+ }
+
@Override
public String toString() {
if (name != null && name.length() > 0)
@@ -221,18 +240,31 @@ public class State extends Movable {
}
/**
- * @return the angle of the initial marker
+ * @return a movable that represents the initial marker.
*/
- public int getInitialAngle() {
- return initialAngle;
- }
+ public MouseMovable getInitialMarkerMovable() {
+ return new MouseMovable() {
+ @Override
+ public VectorInterface getPos() {
+ return getInitialMarkerPos();
+ }
- /**
- * Sets the angle of the initial marker
- *
- * @param angle the angle
- */
- public void setInitialAngle(Integer angle) {
- initialAngle = angle;
+ @Override
+ public void setPosByMouse(VectorFloat pos) {
+ VectorInterface delta = pos.sub(State.this.getPos());
+ double angle = Math.atan2(-delta.getYFloat(), delta.getXFloat()) / Math.PI * 16;
+ if (angle < 0)
+ angle += 32;
+ int ia = (int) Math.round(angle);
+ if (initialAngle != ia) {
+ initialAngle = ia;
+ wasModified(Property.INITIAL_ANGLE);
+ }
+ }
+
+ @Override
+ public void setPos(VectorFloat pos) {
+ }
+ };
}
}
diff --git a/src/main/java/de/neemann/digital/fsm/gui/FSMComponent.java b/src/main/java/de/neemann/digital/fsm/gui/FSMComponent.java
index 35fc153f2..768e87930 100644
--- a/src/main/java/de/neemann/digital/fsm/gui/FSMComponent.java
+++ b/src/main/java/de/neemann/digital/fsm/gui/FSMComponent.java
@@ -10,10 +10,7 @@ import de.neemann.digital.core.element.Key;
import de.neemann.digital.core.element.Keys;
import de.neemann.digital.draw.graphics.*;
import de.neemann.digital.draw.graphics.Polygon;
-import de.neemann.digital.fsm.FSM;
-import de.neemann.digital.fsm.Movable;
-import de.neemann.digital.fsm.State;
-import de.neemann.digital.fsm.Transition;
+import de.neemann.digital.fsm.*;
import de.neemann.digital.gui.components.AttributeDialog;
import de.neemann.digital.lang.Lang;
import de.neemann.gui.Mouse;
@@ -34,12 +31,6 @@ import static de.neemann.digital.gui.components.CircuitComponent.ICON_DELETE;
public class FSMComponent extends JComponent {
private static final Key KEY_NUMBER = new Key.KeyInteger("stateNum", 0);
private static final Key KEY_INITIAL = new Key<>("isInitialState", false);
- private static final Key KEY_INITIAL_ANGLE = new Key.KeyInteger("initialAngle", 12)
- .setComboBoxValues(4, 12, 20, 28)
- .setMin(0)
- .setMax(31)
- .setDependsOn(KEY_INITIAL)
- .setSecondary();
private static final Key KEY_VALUES = new Key<>("stateValues", "");
private static final Key KEY_CONDITION = new Key<>("transCond", "");
private static final Key KEY_RADIUS = new Key.KeyInteger("transRad", 70)
@@ -51,7 +42,7 @@ public class FSMComponent extends JComponent {
private boolean isManualScale;
private AffineTransform transform = new AffineTransform();
- private Movable> elementMoved;
+ private MouseMovable elementMoved;
private FSM fsm;
private Vector lastMousePos;
private State newTransitionFromState;
@@ -87,7 +78,7 @@ public class FSMComponent extends JComponent {
if (elementMoved != null)
delta = posVector.sub(elementMoved.getPos());
} else if (mouse.isSecondaryClick(e)) {
- Movable> st = fsm.getMovable(posVector);
+ MouseMovable st = fsm.getMovable(posVector);
if (st instanceof State) {
newTransitionStartPos = posVector;
newTransitionFromState = (State) st;
@@ -107,7 +98,7 @@ public class FSMComponent extends JComponent {
if (newTransitionFromState != null) {
final Vector posVector = getPosVector(mouseEvent);
if (newTransitionStartPos.sub(posVector).len() > MIN_NEW_TRANS_DIST) {
- Movable> target = fsm.getMovable(posVector);
+ MouseMovable target = fsm.getMovable(posVector);
if (target instanceof State)
fsm.add(new Transition(newTransitionFromState, (State) target, lastCondition));
}
@@ -119,7 +110,7 @@ public class FSMComponent extends JComponent {
@Override
public void mouseClicked(MouseEvent mouseEvent) {
final Vector posVector = getPosVector(mouseEvent);
- Movable> elementClicked = fsm.getMovable(posVector);
+ MouseMovable elementClicked = fsm.getMovable(posVector);
if (mouse.isSecondaryClick(mouseEvent)) {
if (elementClicked == null)
createNewState(posVector, new Point(mouseEvent.getX(), mouseEvent.getY()));
@@ -161,7 +152,7 @@ public class FSMComponent extends JComponent {
ToolTipAction deleteAction = new ToolTipAction(Lang.get("menu_delete"), ICON_DELETE) {
@Override
public void actionPerformed(ActionEvent actionEvent) {
- Movable> element = fsm.getMovable(lastMousePos);
+ MouseMovable element = fsm.getMovable(lastMousePos);
if (element instanceof State) {
fsm.remove((State) element);
repaint();
@@ -188,7 +179,7 @@ public class FSMComponent extends JComponent {
setPreferredSize(new Dimension(600, 600));
}
- private static final Key>[] STATE_EDIT_KEYS = {Keys.LABEL, KEY_NUMBER, KEY_INITIAL, KEY_INITIAL_ANGLE, KEY_VALUES, KEY_RADIUS};
+ private static final Key>[] STATE_EDIT_KEYS = {Keys.LABEL, KEY_NUMBER, KEY_INITIAL, KEY_VALUES, KEY_RADIUS};
private void createNewState(Vector posVector, Point point) {
ElementAttributes attr = new ElementAttributes();
@@ -216,7 +207,6 @@ public class FSMComponent extends JComponent {
ElementAttributes attr = new ElementAttributes()
.set(KEY_NUMBER, state.getNumber())
.set(KEY_INITIAL, state.isInitial())
- .set(KEY_INITIAL_ANGLE, state.getInitialAngle())
.set(KEY_VALUES, state.getValues())
.set(KEY_RADIUS, state.getVisualRadius())
.set(Keys.LABEL, state.getName());
@@ -228,7 +218,6 @@ public class FSMComponent extends JComponent {
if (newAttr != null) {
state.setNumber(newAttr.get(KEY_NUMBER));
state.setInitial(newAttr.get(KEY_INITIAL));
- state.setInitialAngle(newAttr.get(KEY_INITIAL_ANGLE));
state.setValues(newAttr.get(KEY_VALUES));
state.setRadius(newAttr.get(KEY_RADIUS));
state.setName(newAttr.get(Keys.LABEL));
@@ -318,7 +307,7 @@ public class FSMComponent extends JComponent {
/**
* @return the element picked by the mouse
*/
- Movable> getElementMoved() {
+ MouseMovable getElementMoved() {
return elementMoved;
}
diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml
index 0dfed8806..5fff5baf1 100644
--- a/src/main/resources/lang/lang_de.xml
+++ b/src/main/resources/lang/lang_de.xml
@@ -2080,10 +2080,6 @@ Daher steht auch das Signal 'D_out' zur Verfügung, um in diesem Fall den Wert z
Wenn gesetzt, ist dies der Initialzustand, in welchem der Automat gestartet
wird.
- Winkel Initial-Marker
- Winkel bei dem der Marker des Initialzustandes gezeichnet werden soll.
- Ist ein Wert zwischen 0 und 31.
-
Ausgänge
Legt Ausgangswerte fest.
Mit einfachen Zuweisungen wie "A=1, B=0" können Ausgänge gesetzt werden.
diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml
index eb1cd545c..199eba9e4 100644
--- a/src/main/resources/lang/lang_en.xml
+++ b/src/main/resources/lang/lang_en.xml
@@ -2035,10 +2035,6 @@ Therefore, the signal 'D_out' is also available to check the value in this case.
The number which represents this state.
Initial State
If set, this state is the initial state.
- Angle Initial Marker
- Angle at which the marker of the initial state should be drawn.
- Is a value between 0 and 31.
-
Outputs
Defines the output values.
With simple assignments like "A=1, B=0" outputs can be set.