1 package net.mograsim.logic.model.editor.handles;
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;
11 import java.util.concurrent.atomic.AtomicInteger;
12 import java.util.function.Consumer;
13 import java.util.stream.Collectors;
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.editor.util.PrioritySet;
19 import net.mograsim.logic.model.model.LogicModelModifiable;
20 import net.mograsim.logic.model.model.components.ModelComponent;
21 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
22 import net.mograsim.logic.model.model.wires.ModelWire;
23 import net.mograsim.logic.model.model.wires.MovablePin;
24 import net.mograsim.logic.model.model.wires.Pin;
26 public class HandleManager
28 private final Map<Pin, StaticPinHandle> handlePerPin;
29 private final Map<Pin, InterfacePinHandle> handlePerInterfacePin;
30 private final Map<ModelWire, List<WirePointHandle>> pointHandlesPerWire;
31 private final Map<ModelWire, WireHandle> handlePerWire;
32 private final Set<Handle> handles;
33 private final Set<WirePointHandle> wirePointHandles;
34 private final Map<ModelComponent, ComponentHandle> handlePerComp;
36 private final Collection<Consumer<Handle>> handleAddedListeners;
37 private final Collection<Consumer<Handle>> handleRemovedListeners;
38 private final Editor editor;
39 private boolean initialized = false;
41 public HandleManager(Editor editor)
44 handlePerPin = new HashMap<>();
45 handlePerInterfacePin = new HashMap<>();
46 pointHandlesPerWire = new HashMap<>();
47 handlePerComp = new HashMap<>();
48 handles = new PrioritySet<>((a, b) -> Integer.compare(a.getPriority(), b.getPriority()));
49 wirePointHandles = new HashSet<>();
50 handlePerWire = new HashMap<>();
52 handleAddedListeners = new ArrayList<>();
53 handleRemovedListeners = new ArrayList<>();
55 LogicModelModifiable model = editor.getSubmodel();
57 model.addComponentAddedListener(c -> registerComponent(c));
59 model.addComponentRemovedListener(c ->
61 removeComponentHandle(c);
64 model.addWireAddedListener(w ->
69 model.addWireRemovedListener(w ->
72 removeWirePointHandles(w);
76 ////////////////////////////////////////
77 // -- Setting up initial handles -- ///
78 //////////////////////////////////////
83 System.err.println("Warning! HandleManager was already initialized.");
86 LogicModelModifiable model = editor.getSubmodel();
87 Map<String, ModelComponent> compsByName = model.getComponentsByName();
88 Set<ModelComponent> comps = new HashSet<>(compsByName.values());
89 ModelComponent interfaceComp = compsByName.get(SubmodelComponent.SUBMODEL_INTERFACE_NAME);
90 comps.remove(interfaceComp);
91 registerInterfaceComponent(interfaceComp);
92 comps.forEach(c -> registerComponent(c));
94 model.getWiresByName().values().forEach(w -> registerWire(w));
95 addHandle(new CornerHandle(editor.toBeEdited));
99 private void registerInterfaceComponent(ModelComponent c)
101 c.getPins().values().forEach(p -> addInterfacePinHandle(p));
102 c.addPinAddedListener(p -> addInterfacePinHandle(p));
103 c.addPinRemovedListener(p -> removeInterfacePinHandle(p));
106 private void registerComponent(ModelComponent c)
108 addComponentHandle(c);
110 c.getPins().values().forEach(p -> addPinHandle(p));
112 c.addPinAddedListener(p -> addPinHandle(p));
113 c.addPinRemovedListener(p -> removePinHandle(p));
116 private void registerWire(ModelWire wire)
118 Point[] path = wire.getPath();
119 AtomicInteger oldLength = new AtomicInteger(path == null ? 0 : path.length);
120 wire.addPathChangedListener(w ->
122 Point[] newPath = w.getPath();
123 int newLength = newPath == null ? 0 : newPath.length;
124 int diff = newLength - oldLength.getAndSet(newLength);
129 for (int i = 0; i < diff; i++)
130 addWirePointHandle(w);
133 List<WirePointHandle> wpHandles = pointHandlesPerWire.get(w);
134 int size = wpHandles.size();
135 for (int i = 0; i < size; i++)
137 wpHandles.get(i).setIndex(i);
140 pointHandlesPerWire.get(w).forEach(h -> h.updatePos());
145 for (int i = 0; i < path.length; i++)
147 addWirePointHandle(wire);
151 /////////////////////////////////////
152 // -- Adding/Removing handles -- ///
153 ///////////////////////////////////
155 private void addComponentHandle(ModelComponent c)
157 ComponentHandle h = new ComponentHandle(editor.getSubmodel(), c);
158 handlePerComp.put(c, h);
162 private void removeComponentHandle(ModelComponent c)
164 ComponentHandle h = handlePerComp.get(c);
165 handlePerComp.remove(c);
169 private void addPinHandle(Pin owner)
171 StaticPinHandle h = new StaticPinHandle(owner);
172 handlePerPin.put(owner, h);
176 private void removePinHandle(Pin owner)
178 StaticPinHandle h = handlePerPin.get(owner);
179 handlePerPin.remove(owner);
183 private void addInterfacePinHandle(Pin p)
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);
193 private void removeInterfacePinHandle(Pin p)
195 InterfacePinHandle h = handlePerInterfacePin.get(p);
196 handlePerInterfacePin.remove(p);
200 private void addWirePointHandle(ModelWire w)
202 List<WirePointHandle> wireHandles = pointHandlesPerWire.get(w);
204 if (wireHandles != null)
205 wireHandles.add(h = new WirePointHandle(this, w, wireHandles.size()));
208 wireHandles = new ArrayList<>();
209 h = new WirePointHandle(this, w, 0);
211 pointHandlesPerWire.put(h.parent, wireHandles);
213 this.wirePointHandles.add(h);
217 void destroyWirePointHandle(ModelWire owner, WirePointHandle h)
219 if (pointHandlesPerWire.containsKey(owner))
221 List<WirePointHandle> handles = pointHandlesPerWire.get(owner);
222 int pointIndex = handles.indexOf(h);
223 handles.remove(pointIndex);
225 owner.removePathPoint(pointIndex);
229 private void removeWirePointHandles(ModelWire owner)
231 if (!pointHandlesPerWire.containsKey(owner))
233 pointHandlesPerWire.get(owner).forEach(h ->
235 wirePointHandles.remove(h);
238 pointHandlesPerWire.remove(owner);
241 private void addWireHandle(ModelWire w)
243 WireHandle h = new WireHandle(editor.getSubmodel(), w);
244 handlePerWire.put(w, h);
248 private void removeWireHandle(ModelWire w)
250 WireHandle h = handlePerWire.get(w);
251 handlePerWire.remove(w);
255 private void addHandle(Handle h)
258 callHandleAddedListeners(h);
261 private void removeHandle(Handle h)
264 callHandleRemovedListeners(h);
268 public StaticPinHandle getHandle(Pin parent)
270 return handlePerPin.get(parent);
273 public ComponentHandle getHandle(ModelComponent parent)
275 return handlePerComp.get(parent);
278 public WireHandle getHandle(ModelWire parent)
280 return handlePerWire.get(parent);
283 public Handle getInterfacePinHandle(Pin p)
285 return handlePerInterfacePin.get(p);
289 * @return A Collection of the registered {@link WirePointHandle}s of the specified wire
291 public Collection<WirePointHandle> getWirePointHandles(ModelWire parent)
293 return pointHandlesPerWire.get(parent).stream().collect(Collectors.toSet());
297 * @return An unmodifiable view of all registered {@link Handle}s
299 public Collection<Handle> getHandles()
301 return Collections.unmodifiableCollection(handles);
305 * @return An unmodifiable view of all registered {@link StaticPinHandle}s
307 public Collection<StaticPinHandle> getPinHandles()
309 return Collections.unmodifiableCollection(handlePerPin.values());
313 * @return An unmodifiable view of all registered {@link InterfacePinHandle}s
315 public Collection<InterfacePinHandle> getInterfacePinHandles()
317 return Collections.unmodifiableCollection(handlePerInterfacePin.values());
321 * @return An unmodifiable view of all registered {@link ComponentHandle}s
323 public Collection<ComponentHandle> getComponentHandles()
325 return Collections.unmodifiableCollection(handlePerComp.values());
329 * @return An unmodifiable view of all registered {@link WireHandle}s
331 public Collection<WireHandle> getWireHandles()
333 return Collections.unmodifiableCollection(handlePerWire.values());
337 * @return An unmodifiable view of all registered {@link WirePointHandle}s
339 public Collection<WirePointHandle> getWirePointHandles()
341 return Collections.unmodifiableSet(wirePointHandles);
344 public void click(Point clicked, int stateMask)
346 EditorState entryState = editor.stateManager.getState();
347 // TODO: As soon as wires connected to a component being removed also are removed, change priority)
348 if (!click(handles, clicked, entryState, stateMask))
349 entryState.clickedEmpty(clicked, stateMask);
350 entryState.clicked(clicked, stateMask);
353 private static boolean click(Collection<? extends Handle> handles, Point clicked, EditorState state, int stateMask)
355 for (Handle h : handles)
356 if (h.click(clicked.x, clicked.y, stateMask, state))
361 public void addHandleAddedListener(Consumer<Handle> c)
363 handleAddedListeners.add(c);
366 private void callHandleAddedListeners(Handle added)
368 handleAddedListeners.forEach(l -> l.accept(added));
371 public void removeHandleAddedListener(Consumer<Handle> c)
373 handleAddedListeners.remove(c);
376 public void addHandleRemovedListener(Consumer<Handle> c)
378 handleRemovedListeners.add(c);
381 private void callHandleRemovedListeners(Handle removed)
383 handleRemovedListeners.forEach(l -> l.accept(removed));
386 public void removeHandleRemovedListener(Consumer<Handle> c)
388 handleRemovedListeners.remove(c);