Fixed a bug in Am2900; created dlatch8/80; relayouted some components
[Mograsim.git] / net.mograsim.logic.model.editor / src / net / mograsim / logic / model / editor / handles / WireHandle.java
1 package net.mograsim.logic.model.editor.handles;
2
3 import java.util.Optional;
4
5 import org.eclipse.swt.SWT;
6 import org.eclipse.swt.widgets.Display;
7
8 import net.haspamelodica.swt.helper.gcs.GeneralGC;
9 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
10 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
11 import net.mograsim.logic.model.editor.states.EditorState;
12 import net.mograsim.logic.model.model.LogicModelModifiable;
13 import net.mograsim.logic.model.model.wires.ModelWire;
14
15 public class WireHandle extends Handle
16 {
17         private boolean selected = false;
18         private final static double WIDTH = 2.0;
19         private final static double WIDTH_SQUARED = WIDTH * WIDTH;
20         private final LogicModelModifiable model;
21         public final ModelWire parent;
22
23         public WireHandle(LogicModelModifiable model, ModelWire parent)
24         {
25                 super(5);
26                 this.model = model;
27                 this.parent = parent;
28                 parent.addPathChangedListener(c -> updateBounds());
29                 updateBounds();
30         }
31
32         @Override
33         void destroy()
34         {
35                 super.destroy();
36                 parent.removePathChangedListener(c -> updateBounds());
37         }
38
39         public void updateBounds()
40         {
41                 Rectangle r = parent.getBounds();
42                 moveTo(r.x, r.y);
43                 setSize(r.width, r.height);
44         }
45
46         @Override
47         public void render(GeneralGC gc)
48         {
49                 if (selected)
50                 {
51                         gc.setLineWidth(WIDTH);
52                         gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_YELLOW));
53                         gc.drawPolyline(parent.getEffectivePath());
54                 }
55         }
56
57         @Override
58         public void onSelect()
59         {
60                 selected = true;
61                 callRedrawListeners();
62         }
63
64         @Override
65         public void onDeselect()
66         {
67                 selected = false;
68                 callRedrawListeners();
69         }
70
71         @Override
72         public void reqDelete()
73         {
74                 // this wire could already be removed implicitly when removing a selection containing both wires and components
75                 if (model.getWireByName(parent.name) != null)
76                         model.destroyWire(parent);
77         }
78
79         @Override
80         public boolean contains(double x, double y)
81         {
82                 return click(parent, x, y).isPresent();
83         }
84
85         @Override
86         public boolean click(double x, double y, int stateMask, EditorState state)
87         {
88                 Optional<WireClickData> op = click(parent, x, y);
89                 if (op.isEmpty())
90                         return false;
91                 WireClickData data = op.get();
92                 return state.clickedHandle(new WireHandleClickInfo(this, data.segment, data.pos, stateMask));
93         }
94
95         public static class WireHandleClickInfo extends HandleClickInfo
96         {
97                 public final int segment;
98                 public final Point posOnWire;
99
100                 WireHandleClickInfo(WireHandle clicked, int segment, Point posOnWire, int stateMask)
101                 {
102                         super(clicked, stateMask);
103                         this.segment = segment;
104                         this.posOnWire = posOnWire;
105                 }
106
107         }
108
109         private static Optional<WireClickData> click(ModelWire w, double x, double y)
110         {
111                 Rectangle modifiedBounds = w.getBounds();
112                 modifiedBounds.x -= WIDTH;
113                 modifiedBounds.y -= WIDTH;
114                 modifiedBounds.width += WIDTH * 2;
115                 modifiedBounds.height += WIDTH * 2;
116                 if (modifiedBounds.contains(x, y))
117                 {
118                         double[] effectivePath = w.getEffectivePath();
119                         for (int i = 3; i < effectivePath.length; i += 2)
120                         {
121                                 double a1 = effectivePath[i - 3], a2 = effectivePath[i - 2], b1 = effectivePath[i - 1], b2 = effectivePath[i], r1 = b2 - a2,
122                                                 r2 = a1 - b1;
123
124                                 double f = ((x - a1) * r2 + (a2 - y) * r1) / (-r2 * r2 - r1 * r1);
125                                 if (f >= 0 && f <= 1)
126                                 {
127                                         double e1 = a1 + f * (b1 - a1), e2 = a2 + f * (b2 - a2);
128                                         r1 = e1 - x;
129                                         r2 = e2 - y;
130                                         if (r1 * r1 + r2 * r2 <= WIDTH_SQUARED)
131                                                 return Optional.of(new WireClickData(new Point(e1, e2), (i / 2) - 1));
132                                 }
133                         }
134                 }
135                 return Optional.empty();
136         }
137
138         private final static class WireClickData
139         {
140                 WireClickData(Point pos, int segment)
141                 {
142                         this.pos = pos;
143                         this.segment = segment;
144                 }
145
146                 /**
147                  * Position on the wire that is closest to the click
148                  */
149                 public final Point pos;
150                 /**
151                  * Segment of the wire that the {@link Point} pos is on
152                  */
153                 public final int segment;
154         }
155
156         @Override
157         public HandleType getType()
158         {
159                 return HandleType.WIRE;
160         }
161 }