Restructured the Preferences system
[Mograsim.git] / plugins / 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.HashSet;
4 import java.util.Map;
5 import java.util.Optional;
6 import java.util.Set;
7
8 import com.google.gson.JsonElement;
9 import com.google.gson.JsonNull;
10 import com.google.gson.JsonParser;
11 import com.google.gson.JsonSyntaxException;
12
13 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
14 import net.mograsim.logic.model.am2900.Am2900Loader;
15 import net.mograsim.logic.model.editor.handles.ComponentHandle;
16 import net.mograsim.logic.model.editor.handles.Handle;
17 import net.mograsim.logic.model.editor.handles.HandleManager;
18 import net.mograsim.logic.model.editor.handles.PinHandle;
19 import net.mograsim.logic.model.editor.states.StateManager;
20 import net.mograsim.logic.model.editor.ui.DialogManager;
21 import net.mograsim.logic.model.editor.ui.EditorGUI;
22 import net.mograsim.logic.model.model.LogicModelModifiable;
23 import net.mograsim.logic.model.model.components.ModelComponent;
24 import net.mograsim.logic.model.model.wires.ModelWire;
25 import net.mograsim.logic.model.preferences.DefaultRenderPreferences;
26 import net.mograsim.logic.model.preferences.RenderPreferences;
27 import net.mograsim.logic.model.serializing.DeserializedSubmodelComponent;
28 import net.mograsim.logic.model.serializing.IndirectModelComponentCreator;
29 import net.mograsim.logic.model.snippets.highlevelstatehandlers.DefaultHighLevelStateHandler;
30 import net.mograsim.logic.model.snippets.outlinerenderers.DefaultOutlineRenderer;
31 import net.mograsim.logic.model.snippets.symbolrenderers.DefaultSymbolRenderer;
32
33 public final class Editor
34 {
35         final Selection selection = new Selection();
36         final Set<ComponentInfo> copyBuffer = new HashSet<>();
37         public final DeserializedSubmodelComponent toBeEdited;
38         public final HandleManager handleManager;
39         public final EditorGUI gui;
40         public final RenderPreferences renderPrefs;
41         public final StateManager stateManager;
42         private final SaveLoadManager saveManager;
43         private Snapping snapping = Snapping.ABSOLUTE;
44         private double snapX = 5, snapY = 5;
45         public final DialogManager dialogManager;
46         public final EditorUserInput userInput;
47
48         public Editor(DeserializedSubmodelComponent toBeEdited)
49         {
50                 this.toBeEdited = toBeEdited;
51                 handleManager = new HandleManager(this);
52                 renderPrefs = new DefaultRenderPreferences();
53                 gui = new EditorGUI(this);
54                 userInput = new EditorUserInput(this);
55                 stateManager = new StateManager(this);
56                 handleManager.init();
57                 saveManager = new SaveLoadManager(this);
58                 dialogManager = new DialogManager(gui.shell);
59
60                 gui.open();
61         }
62
63         public LogicModelModifiable getSubmodel()
64         {
65                 return toBeEdited.getSubmodelModifiable();
66         }
67
68         public Selection getSelection()
69         {
70                 return selection;
71         }
72
73         // TODO: Remove this error prone method: Relative offset may change between multiple moves,
74         // because Handles have different ways of responding to reqMove(...), causing strange behaviour
75         @Deprecated
76         public void moveSelection(double x, double y)
77         {
78                 Point ref = selection.getTopLeft();
79                 Point snapped = new Point(x, y);
80                 applySnapping(snapped);
81
82                 for (Handle c : selection)
83                 {
84                         double newX, newY;
85                         newX = snapped.x + c.getPosX() - ref.x;
86                         newY = snapped.y + c.getPosY() - ref.y;
87                         c.reqMove(newX, newY);
88                 }
89         }
90
91         public void moveHandles(double x, double y, Map<Handle, Point> handleOffsetMap)
92         {
93                 Point snapped = new Point(x, y);
94                 applySnapping(snapped);
95
96                 for (Handle c : handleOffsetMap.keySet())
97                 {
98                         Point offset = handleOffsetMap.get(c);
99                         double newX, newY;
100                         newX = snapped.x + offset.x;
101                         newY = snapped.y + offset.y;
102                         c.reqMove(newX, newY);
103                 }
104         }
105
106         public void deleteSelection()
107         {
108                 selection.forEach(h -> h.reqDelete());
109                 selection.clear();
110         }
111
112         public void copy()
113         {
114                 copyBuffer.clear();
115                 Point refPoint = selection.getTopLeft();
116                 for (Handle h : selection)
117                 {
118                         Optional<ComponentInfo> cInfo = h.reqCopy(refPoint);
119                         if (cInfo.isPresent())
120                                 copyBuffer.add(cInfo.get());
121                 }
122         }
123
124         public void paste(double x, double y)
125         {
126                 selection.clear();
127                 for (ComponentInfo info : copyBuffer)
128                 {
129                         ModelComponent comp = addComponent(info.identifier, info.params);
130                         ComponentHandle h = handleManager.getHandle(comp);
131                         h.reqMove(info.relX, info.relY);
132                         selection.add(h);
133                 }
134                 moveSelection(x, y);
135         }
136
137         public void save()
138         {
139                 saveManager.save();
140         }
141
142         public void saveAs()
143         {
144                 saveManager.openSaveAsDialog();
145         }
146
147         public void addComponent(double x, double y)
148         {
149                 boolean successful = false;
150                 JsonElement params = JsonNull.INSTANCE;
151                 outer: while (!successful)
152                 {
153                         String selected = gui.getAddListSelected();
154                         try
155                         {
156                                 ModelComponent c = addComponent(selected, params);
157                                 selection.clear();
158                                 selection.add(handleManager.getHandle(c));
159                                 moveSelection(x, y);
160                                 successful = true;
161                         }
162                         catch (@SuppressWarnings("unused") UnsupportedOperationException | JsonSyntaxException | NumberFormatException
163                                         | NullPointerException e)
164                         {
165                                 String result = DialogManager.openMultiLineTextDialog("Add component", "Create", "Cancel", "Parameters:");
166                                 if (result == null)
167                                         break outer;
168                                 params = new JsonParser().parse(result);
169                         }
170                 }
171         }
172
173         private ModelComponent addComponent(String identifier, JsonElement params)
174         {
175                 return IndirectModelComponentCreator.createComponent(toBeEdited.getSubmodelModifiable(), identifier, params);
176         }
177
178         public void duplicate()
179         {
180                 copy();
181                 Point origin = selection.getTopLeft();
182                 paste(origin.x + 20, origin.y + 20);
183         }
184
185         private void applySnapping(Point newP)
186         {
187                 switch (snapping)
188                 {
189                 case OFF:
190                         break;
191                 case ABSOLUTE:
192                         newP.x = (int) (newP.x / snapX + .5) * snapX;
193                         newP.y = (int) (newP.y / snapY + .5) * snapY;
194                         break;
195                 default:
196                         break;
197                 }
198         }
199
200         public static class ComponentInfo
201         {
202                 public final double relX, relY;
203                 public final String identifier;
204                 public final JsonElement params;
205
206                 public ComponentInfo(double relX, double relY, String identifier, JsonElement params)
207                 {
208                         this.relX = relX;
209                         this.relY = relY;
210                         this.identifier = identifier;
211                         this.params = params;
212                 }
213         }
214
215         @SuppressWarnings("unused")
216         public void addWire(PinHandle a, PinHandle b)
217         {
218                 new ModelWire(toBeEdited.getSubmodelModifiable(), a.getPin(), b.getPin(), new Point[0]);
219         }
220
221         public static enum Snapping
222         {
223                 OFF, ABSOLUTE;
224
225                 @Override
226                 public String toString()
227                 {
228                         return super.toString().toLowerCase();
229                 }
230         }
231
232         public static void main(String[] args)
233         {
234                 Am2900Loader.setup();
235                 openNewEditor();
236 //              SaveLoadManager.openLoadDialog();
237         }
238
239         @SuppressWarnings("unused") // Editor
240         public static void openNewEditor()
241         {
242                 DeserializedSubmodelComponent toBeEdited = new DeserializedSubmodelComponent(new LogicModelModifiable(), null, null, null);
243                 toBeEdited.setOutlineRenderer(new DefaultOutlineRenderer(toBeEdited));
244                 toBeEdited.setSymbolRenderer(new DefaultSymbolRenderer(toBeEdited));
245                 toBeEdited.setHighLevelStateHandler(new DefaultHighLevelStateHandler());
246                 new Editor(toBeEdited);
247         }
248
249         public Snapping getSnapping()
250         {
251                 return snapping;
252         }
253
254         public void setSnapping(Snapping snapping)
255         {
256                 this.snapping = snapping;
257         }
258 }