Added option to switch off snapping in the Editor
[Mograsim.git] / net.mograsim.logic.model.editor / src / net / mograsim / logic / model / editor / Editor.java
1 package net.mograsim.logic.model.editor;
2
3 import java.util.HashMap;
4 import java.util.HashSet;
5 import java.util.Map;
6 import java.util.Optional;
7 import java.util.Set;
8
9 import com.google.gson.JsonElement;
10 import com.google.gson.JsonObject;
11
12 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
13 import net.mograsim.logic.model.editor.handles.ComponentHandle;
14 import net.mograsim.logic.model.editor.handles.Handle;
15 import net.mograsim.logic.model.editor.handles.HandleManager;
16 import net.mograsim.logic.model.editor.handles.PinHandle;
17 import net.mograsim.logic.model.editor.states.StateManager;
18 import net.mograsim.logic.model.editor.ui.DialogManager;
19 import net.mograsim.logic.model.editor.ui.EditorGUI;
20 import net.mograsim.logic.model.model.ViewModelModifiable;
21 import net.mograsim.logic.model.model.components.GUIComponent;
22 import net.mograsim.logic.model.model.wires.GUIWire;
23 import net.mograsim.logic.model.serializing.DeserializedSubmodelComponent;
24 import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
25
26 public final class Editor
27 {
28         final Selection selection = new Selection();
29         final Set<ComponentInfo> copyBuffer = new HashSet<>();
30         public final DeserializedSubmodelComponent toBeEdited;
31         public final HandleManager handleManager;
32         final static Map<GUIComponent, String> identifierPerComponent = new HashMap<>();
33         public final EditorGUI gui;
34         public final StateManager stateManager;
35         private final SaveLoadManager saveManager;
36         private Snapping snapping = Snapping.ABSOLUTE;
37         private double snapX = 5, snapY = 5;
38         public final DialogManager dialogManager;
39         public final EditorUserInput userInput;
40
41         public Editor(DeserializedSubmodelComponent toBeEdited)
42         {
43                 this.toBeEdited = toBeEdited;
44                 handleManager = new HandleManager(this);
45                 gui = new EditorGUI(this);
46                 userInput = new EditorUserInput(this);
47                 stateManager = new StateManager(this);
48                 handleManager.init();
49                 saveManager = new SaveLoadManager(this);
50                 dialogManager = new DialogManager(gui.shell);
51
52                 toBeEdited.submodel.addComponentRemovedListener(c -> identifierPerComponent.remove(c));
53                 
54                 gui.open();
55         }
56         
57         public ViewModelModifiable getSubmodel()
58         {
59                 return toBeEdited.getSubmodelModifiable();
60         }
61
62         public Selection getSelection()
63         {
64                 return selection;
65         }
66
67         //TODO: Remove this error prone method: Relative offset may change between multiple moves,
68         //because Handles have different ways of responding to reqMove(...), causing strange behaviour
69         @Deprecated
70         public void moveSelection(double x, double y)
71         {
72                 Point ref = selection.getTopLeft();
73                 Point snapped = new Point(x, y);
74                 applySnapping(snapped);
75
76                 for (Handle c : selection)
77                 {
78                         double newX, newY;
79                         newX = snapped.x + c.getPosX() - ref.x;
80                         newY = snapped.y + c.getPosY() - ref.y;
81                         c.reqMove(newX, newY);
82                 }
83         }
84         
85         public void moveHandles(double x, double y, Map<Handle, Point> handleOffsetMap)
86         {
87                 Point snapped = new Point(x, y);
88                 applySnapping(snapped);
89
90                 for (Handle c : handleOffsetMap.keySet())
91                 {
92                         Point offset = handleOffsetMap.get(c);
93                         double newX, newY;
94                         newX = snapped.x + offset.x;
95                         newY = snapped.y + offset.y;
96                         c.reqMove(newX, newY);
97                 }
98         }
99
100         public void deleteSelection()
101         {
102                 selection.forEach(h -> h.reqDelete());
103                 selection.clear();
104         }
105
106         public void copy()
107         {
108                 copyBuffer.clear();
109                 Point refPoint = selection.getTopLeft();
110                 for (Handle h : selection)
111                 {
112                         Optional<ComponentInfo> cInfo = h.reqCopy(refPoint);
113                         if(cInfo.isPresent())
114                                 copyBuffer.add(cInfo.get());
115                 }
116         }
117
118         public void paste(double x, double y)
119         {
120                 selection.clear();
121                 for (ComponentInfo info : copyBuffer)
122                 {
123                         GUIComponent comp = addComponent(info.identifier, info.params);
124                         ComponentHandle h = handleManager.getHandle(comp);
125                         h.reqMove(info.relX, info.relY);
126                         selection.add(h);
127                 }
128                 moveSelection(x, y);
129         }
130         
131         public void save()
132         {
133                 saveManager.save();
134         }
135
136         public void addComponent(double x, double y)
137         {
138                 GUIComponent c = addComponent(gui.getAddListSelected(), new JsonObject());
139                 selection.clear();
140                 selection.add(handleManager.getHandle(c));
141                 moveSelection(x, y);
142         }
143         
144         private GUIComponent addComponent(String identifier, JsonElement params)
145         {
146                 GUIComponent comp = IndirectGUIComponentCreator.createComponent(toBeEdited.getSubmodelModifiable(), identifier,
147                                 params);
148                 identifierPerComponent.put(comp, identifier);
149                 return comp;
150         }
151         
152         public static String getIdentifier(GUIComponent c)
153         {
154                 return identifierPerComponent.get(c);
155         }
156
157         public void duplicate()
158         {
159                 copy();
160                 Point origin = selection.getTopLeft();
161                 paste(origin.x + 20, origin.y + 20);
162         }
163
164         private void applySnapping(Point newP)
165         {
166                 switch (snapping)
167                 {
168                 case OFF:
169                         break;
170                 case ABSOLUTE:
171                         newP.x -= newP.x % snapX;
172                         newP.y -= newP.y % snapY;
173                         break;
174                 }
175         }
176
177         public static class ComponentInfo
178         {
179                 public final double relX, relY;
180                 public final String identifier;
181                 public final JsonElement params;
182                 
183                 public ComponentInfo(double relX, double relY, String identifier, JsonElement params)
184                 {
185                         this.relX = relX;
186                         this.relY = relY;
187                         this.identifier = identifier;
188                         this.params = params;
189                 }
190         }
191
192         public void addWire(PinHandle a, PinHandle b)
193         {
194                 new GUIWire(toBeEdited.getSubmodelModifiable(), a.getPin(), b.getPin(), new Point[0]);
195         }
196
197         public static enum Snapping
198         {
199                 OFF, ABSOLUTE;
200                 
201                 @Override
202                 public String toString()
203                 {
204                         return super.toString().toLowerCase();
205                 }
206         }
207         
208         public static void main(String[] args)
209         {
210                 SaveLoadManager.openLoadDialog();
211         }
212
213         public Snapping getSnapping()
214         {
215                 return snapping;
216         }
217
218         public void setSnapping(Snapping snapping)
219         {
220                 this.snapping = snapping;
221         }
222 }