Merge branch 'development' of
[Mograsim.git] / net.mograsim.logic.model.editor / src / net / mograsim / logic / model / editor / handles / HandleManager.java
1 package net.mograsim.logic.model.editor.handles;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.concurrent.atomic.AtomicInteger;
12 import java.util.function.Consumer;
13 import java.util.stream.Collectors;
14
15 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
16 import net.mograsim.logic.model.editor.Editor;
17 import net.mograsim.logic.model.editor.states.EditorState;
18 import net.mograsim.logic.model.model.ViewModelModifiable;
19 import net.mograsim.logic.model.model.components.GUIComponent;
20 import net.mograsim.logic.model.model.wires.GUIWire;
21 import net.mograsim.logic.model.model.wires.MovablePin;
22 import net.mograsim.logic.model.model.wires.Pin;
23
24 public class HandleManager
25 {
26         private final Map<Pin, StaticPinHandle> handlePerPin;
27         private final Map<Pin, InterfacePinHandle> handlePerInterfacePin;
28         private final Map<GUIWire, List<WirePointHandle>> pointHandlesPerWire;
29         private final Map<GUIWire, WireHandle> handlePerWire;
30         private final Set<Handle> handles;
31         private final Set<WirePointHandle> wirePointHandles;
32         private final Map<GUIComponent, ComponentHandle> handlePerComp;
33
34         private final Collection<Consumer<Handle>> handleAddedListeners;
35         private final Collection<Consumer<Handle>> handleRemovedListeners;
36         private final Editor editor;
37         private boolean initialized = false;
38
39         private CornerHandle cornerHandle;
40
41         public HandleManager(Editor editor)
42         {
43                 this.editor = editor;
44                 handlePerPin = new HashMap<>();
45                 handlePerInterfacePin = new HashMap<>();
46                 pointHandlesPerWire = new HashMap<>();
47                 handlePerComp = new HashMap<>();
48                 handles = new HashSet<>();
49                 wirePointHandles = new HashSet<>();
50                 handlePerWire = new HashMap<>();
51
52                 handleAddedListeners = new ArrayList<>();
53                 handleRemovedListeners = new ArrayList<>();
54
55                 ViewModelModifiable model = editor.getSubmodel();
56
57                 model.addComponentAddedListener(c -> registerComponent(c));
58
59                 model.addComponentRemovedListener(c ->
60                 {
61                         removeComponentHandle(c);
62                 });
63
64                 model.addWireAddedListener(w ->
65                 {
66                         registerWire(w);
67                 });
68
69                 model.addWireRemovedListener(w ->
70                 {
71                         removeWireHandle(w);
72                         removeWirePointHandles(w);
73                 });
74         }
75
76         ////////////////////////////////////////
77         // -- Setting up initial handles -- ///
78         //////////////////////////////////////
79
80         public void init()
81         {
82                 if (initialized)
83                         System.err.println("Warning! HandleManager was already initialized.");
84                 else
85                 {
86                         ViewModelModifiable model = editor.getSubmodel();
87                         Map<String, GUIComponent> compsByName = model.getComponentsByName();
88                         Set<GUIComponent> comps = new HashSet<>(compsByName.values());
89                         GUIComponent interfaceComp = compsByName.get("_submodelinterface");
90                         comps.remove(interfaceComp);
91                         registerInterfaceComponent(interfaceComp);
92                         comps.forEach(c -> registerComponent(c));
93
94                         model.getWires().forEach(w -> registerWire(w));
95                         addHandle(cornerHandle = new CornerHandle(editor.toBeEdited));
96                 }
97         }
98
99         private void registerInterfaceComponent(GUIComponent c)
100         {
101                 c.getPins().values().forEach(p -> addInterfacePinHandle(p));
102                 c.addPinAddedListener(p -> addInterfacePinHandle(p));
103                 c.addPinRemovedListener(p -> removeInterfacePinHandle(p));
104         }
105
106         private void registerComponent(GUIComponent c)
107         {
108                 addComponentHandle(c);
109
110                 c.getPins().values().forEach(p -> addPinHandle(p));
111
112                 c.addPinAddedListener(p -> addPinHandle(p));
113                 c.addPinRemovedListener(p -> removePinHandle(p));
114         }
115
116         private void registerWire(GUIWire wire)
117         {
118                 Point[] path = wire.getPath();
119                 AtomicInteger oldLength = new AtomicInteger(path == null ? 0 : path.length);
120                 wire.addPathChangedListener(w ->
121                 {
122                         Point[] newPath = w.getPath();
123                         int newLength = newPath == null ? 0 : newPath.length;
124                         int diff = oldLength.getAndSet(newLength) - newLength;
125                         if (diff != 0)
126                         {
127                                 if (diff > 0)
128                                 {
129                                         for (int i = 0; i < diff; i++)
130                                                 addWirePointHandle(w);
131                                 }
132
133                                 List<WirePointHandle> wpHandles = pointHandlesPerWire.get(w);
134                                 int size = wpHandles.size();
135                                 for (int i = 0; i < size; i++)
136                                 {
137                                         wpHandles.get(i).setIndex(i);
138                                 }
139                         }
140                         pointHandlesPerWire.get(w).forEach(h -> h.updatePos());
141                 });
142                 addWireHandle(wire);
143                 if (path == null)
144                         return;
145                 for (int i = 0; i < path.length; i++)
146                 {
147                         addWirePointHandle(wire);
148                 }
149         }
150
151         /////////////////////////////////////
152         // -- Adding/Removing handles -- ///
153         ///////////////////////////////////
154
155         private void addComponentHandle(GUIComponent c)
156         {
157                 ComponentHandle h = new ComponentHandle(c);
158                 handlePerComp.put(c, h);
159                 addHandle(h);
160         }
161
162         private void removeComponentHandle(GUIComponent c)
163         {
164                 ComponentHandle h = handlePerComp.get(c);
165                 handlePerComp.remove(c);
166                 removeHandle(h);
167         }
168
169         private void addPinHandle(Pin owner)
170         {
171                 StaticPinHandle h = new StaticPinHandle(owner);
172                 handlePerPin.put(owner, h);
173                 addHandle(h);
174         }
175
176         private void removePinHandle(Pin owner)
177         {
178                 StaticPinHandle h = handlePerPin.get(owner);
179                 handlePerPin.remove(owner);
180                 removeHandle(h);
181         }
182
183         private void addInterfacePinHandle(Pin p)
184         {
185                 // The following is not an alternative to the cast, because the new pin is not yet in the map, when the listener is called
186                 // editor.toBeEdited.getSubmodelMovablePins().get(p.name);
187                 MovablePin pM = (MovablePin) p;
188                 InterfacePinHandle h = new InterfacePinHandle(pM, editor.toBeEdited);
189                 handlePerInterfacePin.put(pM, h);
190                 addHandle(h);
191         }
192
193         private void removeInterfacePinHandle(Pin p)
194         {
195                 InterfacePinHandle h = handlePerInterfacePin.get(p);
196                 handlePerInterfacePin.remove(p);
197                 removeHandle(h);
198         }
199
200         private void addWirePointHandle(GUIWire w)
201         {
202                 List<WirePointHandle> wireHandles = pointHandlesPerWire.get(w);
203                 WirePointHandle h;
204                 if (wireHandles != null)
205                         wireHandles.add(h = new WirePointHandle(this, w, wireHandles.size()));
206                 else
207                 {
208                         wireHandles = new ArrayList<>();
209                         h = new WirePointHandle(this, w, 0);
210                         wireHandles.add(h);
211                         pointHandlesPerWire.put(h.parent, wireHandles);
212                 }
213                 this.wirePointHandles.add(h);
214                 addHandle(h);
215         }
216
217         void destroyWirePointHandle(GUIWire owner, WirePointHandle h)
218         {
219                 List<WirePointHandle> handles = pointHandlesPerWire.get(owner);
220                 int pointIndex = handles.indexOf(h);
221                 handles.remove(pointIndex);
222                 removeHandle(h);
223                 owner.removePathPoint(pointIndex);
224         }
225
226         private void removeWirePointHandles(GUIWire owner)
227         {
228                 if (!pointHandlesPerWire.containsKey(owner))
229                         return;
230                 pointHandlesPerWire.get(owner).forEach(h ->
231                 {
232                         wirePointHandles.remove(h);
233                         removeHandle(h);
234                 });
235                 pointHandlesPerWire.remove(owner);
236         }
237
238         private void addWireHandle(GUIWire w)
239         {
240                 WireHandle h = new WireHandle(w);
241                 handlePerWire.put(w, h);
242                 addHandle(h);
243         }
244
245         private void removeWireHandle(GUIWire w)
246         {
247                 WireHandle h = handlePerWire.get(w);
248                 handlePerWire.remove(w);
249                 removeHandle(h);
250         }
251
252         private void addHandle(Handle h)
253         {
254                 handles.add(h);
255                 callHandleAddedListeners(h);
256         }
257
258         private void removeHandle(Handle h)
259         {
260                 handles.remove(h);
261                 callHandleRemovedListeners(h);
262                 h.destroy();
263         }
264
265         public StaticPinHandle getHandle(Pin parent)
266         {
267                 return handlePerPin.get(parent);
268         }
269
270         public ComponentHandle getHandle(GUIComponent parent)
271         {
272                 return handlePerComp.get(parent);
273         }
274
275         public WireHandle getHandle(GUIWire parent)
276         {
277                 return handlePerWire.get(parent);
278         }
279
280         public Handle getInterfacePinHandle(Pin p)
281         {
282                 return handlePerInterfacePin.get(p);
283         }
284
285         /**
286          * @return A Collection of the registered {@link WirePointHandle}s of the specified wire
287          */
288         public Collection<WirePointHandle> getWirePointHandles(GUIWire parent)
289         {
290                 return pointHandlesPerWire.get(parent).stream().collect(Collectors.toSet());
291         }
292
293         /**
294          * @return An unmodifiable view of all registered {@link Handle}s
295          */
296         public Collection<Handle> getHandles()
297         {
298                 return Collections.unmodifiableCollection(handles);
299         }
300
301         /**
302          * @return An unmodifiable view of all registered {@link StaticPinHandle}s
303          */
304         public Collection<StaticPinHandle> getPinHandles()
305         {
306                 return Collections.unmodifiableCollection(handlePerPin.values());
307         }
308
309         /**
310          * @return An unmodifiable view of all registered {@link InterfacePinHandle}s
311          */
312         public Collection<InterfacePinHandle> getInterfacePinHandles()
313         {
314                 return Collections.unmodifiableCollection(handlePerInterfacePin.values());
315         }
316
317         /**
318          * @return An unmodifiable view of all registered {@link ComponentHandle}s
319          */
320         public Collection<ComponentHandle> getComponentHandles()
321         {
322                 return Collections.unmodifiableCollection(handlePerComp.values());
323         }
324
325         /**
326          * @return An unmodifiable view of all registered {@link WireHandle}s
327          */
328         public Collection<WireHandle> getWireHandles()
329         {
330                 return Collections.unmodifiableCollection(handlePerWire.values());
331         }
332
333         /**
334          * @return An unmodifiable view of all registered {@link WirePointHandle}s
335          */
336         public Collection<WirePointHandle> getWirePointHandles()
337         {
338                 return Collections.unmodifiableSet(wirePointHandles);
339         }
340
341         public void click(Point clicked, int stateMask)
342         {
343                 EditorState entryState = editor.stateManager.getState();
344
345                 if (!cornerHandle.click(clicked.x, clicked.y, stateMask, entryState))
346                         if (!click(handlePerPin.values(), clicked, entryState, stateMask))
347                                 if (!click(handlePerInterfacePin.values(), clicked, entryState, stateMask))
348                                         if (!click(getWirePointHandles(), clicked, entryState, stateMask))
349                                                 if (!click(getWireHandles(), clicked, entryState, stateMask))
350                                                         if (!click(handlePerComp.values(), clicked, entryState, stateMask))
351                                                                 entryState.clickedEmpty(clicked, stateMask);
352                 entryState.clicked(clicked, stateMask);
353         }
354
355         private static boolean click(Collection<? extends Handle> handles, Point clicked, EditorState state, int stateMask)
356         {
357                 for (Handle h : handles)
358                         if (h.click(clicked.x, clicked.y, stateMask, state))
359                                 return true;
360                 return false;
361         }
362
363         public void addHandleAddedListener(Consumer<Handle> c)
364         {
365                 handleAddedListeners.add(c);
366         }
367
368         private void callHandleAddedListeners(Handle added)
369         {
370                 handleAddedListeners.forEach(l -> l.accept(added));
371         }
372
373         public void removeHandleAddedListener(Consumer<Handle> c)
374         {
375                 handleAddedListeners.remove(c);
376         }
377
378         public void addHandleRemovedListener(Consumer<Handle> c)
379         {
380                 handleRemovedListeners.add(c);
381         }
382
383         private void callHandleRemovedListeners(Handle removed)
384         {
385                 handleRemovedListeners.forEach(l -> l.accept(removed));
386         }
387
388         public void removeHandleRemovedListener(Consumer<Handle> c)
389         {
390                 handleRemovedListeners.remove(c);
391         }
392 }