Fixed & cleaned up GUIWire:
[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.wires.GUIWire;
13
14 public class WireHandle extends Handle
15 {
16         private boolean selected = false;
17         private final static double WIDTH = 2.0;
18         private final static double WIDTH_SQUARED = WIDTH * WIDTH;
19         public final GUIWire parent;
20
21         public WireHandle(GUIWire parent)
22         {
23                 this.parent = parent;
24                 parent.addPathChangedListener(c -> updateBounds());
25                 updateBounds();
26         }
27         
28         @Override
29         void destroy()
30         {
31                 super.destroy();
32                 parent.removePathChangedListener(c -> updateBounds());
33         }
34
35         public void updateBounds()
36         {
37                 Rectangle r = parent.getBounds();
38                 moveTo(r.x, r.y);
39                 setSize(r.width, r.height);
40         }
41         
42         @Override
43         public void render(GeneralGC gc)
44         {
45                 if(selected)
46                 {
47                         gc.setLineWidth(WIDTH);
48                         gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_YELLOW));
49                         gc.drawPolyline(parent.getEffectivePath());
50                 }
51         }
52                 
53         @Override
54         public void onSelect()
55         {
56                 selected = true;
57                 callRedrawListeners();
58         }
59
60         @Override
61         public void onDeselect()
62         {
63                 selected = false;
64                 callRedrawListeners();
65         }
66         
67         @Override
68         public void reqDelete()
69         {
70                 parent.destroy();
71         }
72         
73         @Override
74         public boolean contains(double x, double y)
75         {
76                 return click(parent, x, y).isPresent();
77         }
78         
79         @Override
80         public boolean click(double x, double y, int stateMask, EditorState state)
81         {
82                 Optional<WireClickData> op = click(parent, x, y);
83                 if(op.isEmpty())
84                         return false;
85                 WireClickData data = op.get();
86                 return state.clickedHandle(new WireHandleClickInfo(this, data.segment, data.pos, stateMask));
87         }
88         
89         public static class WireHandleClickInfo extends HandleClickInfo
90         {
91                 public final int segment;
92                 public final Point posOnWire;
93                 WireHandleClickInfo(WireHandle clicked, int segment, Point posOnWire, int stateMask)
94                 {
95                         super(clicked, stateMask);
96                         this.segment = segment;
97                         this.posOnWire = posOnWire;
98                 }
99                 
100         }
101         
102         private static Optional<WireClickData> click(GUIWire w, double x, double y)
103         {
104                 Rectangle modifiedBounds = w.getBounds();
105                 modifiedBounds.x -= WIDTH;
106                 modifiedBounds.y -= WIDTH;
107                 modifiedBounds.width += WIDTH * 2;
108                 modifiedBounds.height += WIDTH * 2;
109                 if (modifiedBounds.contains(x, y))
110                 {
111                         double[] effectivePath = w.getEffectivePath();
112                         for (int i = 3; i < effectivePath.length; i += 2)
113                         {
114                                 double a1 = effectivePath[i - 3], a2 = effectivePath[i - 2], b1 = effectivePath[i - 1],
115                                                 b2 = effectivePath[i], r1 = b2 - a2, r2 = a1 - b1;
116
117                                 double f = ((x - a1) * r2 + (a2 - y) * r1) / (-r2 * r2 - r1 * r1);
118                                 if (f >= 0 && f <= 1)
119                                 {
120                                         double e1 = a1 + f * (b1 - a1), e2 = a2 + f * (b2 - a2);
121                                         r1 = e1 - x;
122                                         r2 = e2 - y;
123                                         if (r1 * r1 + r2 * r2 <= WIDTH_SQUARED)
124                                                 return Optional.of(new WireClickData(new Point(e1, e2), (i / 2) - 1));
125                                 }
126                         }
127                 }
128                 return Optional.empty();
129         }
130
131         private final static class WireClickData
132         {
133                 WireClickData(Point pos, int segment)
134                 {
135                         this.pos = pos;
136                         this.segment = segment;
137                 }
138
139                 /**
140                  * Position on the wire that is closest to the click
141                  */
142                 public final Point pos;
143                 /**
144                  * Segment of the wire that the {@link Point} pos is on
145                  */
146                 public final int segment;
147         }
148         
149         @Override
150         public HandleType getType()
151         {
152                 return HandleType.WIRE;
153         }
154 }