Added option to switch off snapping in the Editor
authorFabian Stemmler <stemmler@in.tum.de>
Sun, 14 Jul 2019 16:08:35 +0000 (18:08 +0200)
committerFabian Stemmler <stemmler@in.tum.de>
Sun, 14 Jul 2019 16:08:35 +0000 (18:08 +0200)
Also moved all UI related classes into their own package

net.mograsim.logic.model.editor/META-INF/MANIFEST.MF
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/DialogManager.java [deleted file]
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/Editor.java
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/EditorCanvas.java [deleted file]
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/EditorGUI.java [deleted file]
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/EditorUserInput.java
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/SaveLoadManager.java
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/states/SelectionState.java
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/DialogManager.java [new file with mode: 0644]
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/EditorCanvas.java [new file with mode: 0644]
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/EditorGUI.java [new file with mode: 0644]

index 40d0654..a666cde 100644 (file)
@@ -5,7 +5,8 @@ Bundle-SymbolicName: net.mograsim.logic.model.editor
 Bundle-Version: 0.1.0.qualifier
 Export-Package: net.mograsim.logic.model.editor,
  net.mograsim.logic.model.editor.handles,
- net.mograsim.logic.model.editor.states
+ net.mograsim.logic.model.editor.states,
+ net.mograsim.logic.model.editor.ui
 Require-Bundle: net.mograsim.logic.model;bundle-version="0.1.0",
  net.mograsim.preferences;bundle-version="0.1.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-11
diff --git a/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/DialogManager.java b/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/DialogManager.java
deleted file mode 100644 (file)
index 347e622..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-package net.mograsim.logic.model.editor;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.MessageBox;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-public class DialogManager
-{
-       private Shell parent;
-       
-       public DialogManager(Shell parent)
-       {
-               this.parent = parent;
-       }
-
-       public void openWarningDialog(String title, String message)
-       {
-               MessageBox b = new MessageBox(parent, SWT.ICON_WARNING | SWT.OK);
-               b.setText(title);
-               b.setMessage(message);
-               b.open();
-       }
-       
-       public static class InteractiveDialog
-       {
-               private String[] finalInput;
-               private final Display display;
-               private final Shell shell;
-               private final Button b1, b2;
-               private Text[] textFields;
-               private InteractiveDialog.InteractiveDialogState state;
-
-               public InteractiveDialog(String title, String acceptLabel, String cancelLabel, String... inputs)
-               {
-                       display = Display.getDefault();
-                       shell = new Shell(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.ON_TOP | SWT.APPLICATION_MODAL);
-                       shell.setMinimumSize(500, 150);
-                       shell.setText(title);
-                       GridLayout layout = new GridLayout();
-                       layout.numColumns = 2;
-                       shell.setLayout(layout);
-
-                       this.textFields = new Text[inputs.length];
-                       for (int i = 0; i < inputs.length; i++)
-                       {
-                               Label textFieldName = new Label(shell, SWT.NONE);
-                               textFieldName.setText(inputs[i].concat(":"));
-                               GridData g = new GridData();
-                               g.grabExcessHorizontalSpace = true;
-                               g.horizontalAlignment = SWT.FILL;
-                               Text newTextField = new Text(shell, SWT.BORDER);
-                               newTextField.setLayoutData(g);
-                               textFields[i] = newTextField;
-                       }
-                       b1 = new Button(shell, SWT.PUSH);
-                       b1.addListener(SWT.Selection, e ->
-                       {
-                               state = InteractiveDialogState.ACCEPTED;
-                               buildFinalInput();
-                               dispose();
-                       });
-                       b1.setText(acceptLabel);
-                       b2 = new Button(shell, SWT.PUSH);
-                       b2.addListener(SWT.Selection, e ->
-                       {
-                               state = InteractiveDialogState.CANCELLED;
-                               buildFinalInput();
-                               dispose();
-                       });
-                       b2.setText(cancelLabel);
-
-                       state = InteractiveDialogState.ACTIVE;
-
-                       shell.pack();
-               }
-
-               public String getText()
-               {
-                       return getText(0);
-               }
-
-               public String getText(int index)
-               {
-                       if (!shell.isDisposed())
-                               return textFields[index].getText();
-                       else
-                               return finalInput[index];
-               }
-
-               public void open()
-               {
-                       shell.open();
-                       while (!shell.isDisposed())
-                               if (!display.readAndDispatch())
-                                       display.sleep();
-               }
-
-               public void dispose()
-               {
-                       shell.dispose();
-               }
-
-               public InteractiveDialog.InteractiveDialogState getState()
-               {
-                       return state;
-               }
-
-               private void buildFinalInput()
-               {
-                       finalInput = new String[textFields.length];
-                       for (int i = 0; i < textFields.length; i++)
-                               finalInput[i] = textFields[i].getText();
-               }
-
-               public static enum InteractiveDialogState
-               {
-                       ACTIVE, ACCEPTED, CANCELLED;
-               }
-       }
-       
-       public static void openAddPinDialog(Editor editor, double x, double y)
-       {
-               
-       }
-}
index 36dcbc7..e285574 100644 (file)
@@ -15,6 +15,8 @@ import net.mograsim.logic.model.editor.handles.Handle;
 import net.mograsim.logic.model.editor.handles.HandleManager;
 import net.mograsim.logic.model.editor.handles.PinHandle;
 import net.mograsim.logic.model.editor.states.StateManager;
+import net.mograsim.logic.model.editor.ui.DialogManager;
+import net.mograsim.logic.model.editor.ui.EditorGUI;
 import net.mograsim.logic.model.model.ViewModelModifiable;
 import net.mograsim.logic.model.model.components.GUIComponent;
 import net.mograsim.logic.model.model.wires.GUIWire;
@@ -31,15 +33,17 @@ public final class Editor
        public final EditorGUI gui;
        public final StateManager stateManager;
        private final SaveLoadManager saveManager;
-       Snapping snapping = Snapping.ABSOLUTE;
+       private Snapping snapping = Snapping.ABSOLUTE;
        private double snapX = 5, snapY = 5;
        public final DialogManager dialogManager;
+       public final EditorUserInput userInput;
 
        public Editor(DeserializedSubmodelComponent toBeEdited)
        {
                this.toBeEdited = toBeEdited;
                handleManager = new HandleManager(this);
                gui = new EditorGUI(this);
+               userInput = new EditorUserInput(this);
                stateManager = new StateManager(this);
                handleManager.init();
                saveManager = new SaveLoadManager(this);
@@ -185,19 +189,6 @@ public final class Editor
                }
        }
 
-       public Point getCanvasMousePosition()
-       {
-               //TODO
-               org.eclipse.swt.graphics.Point canvasLoc = gui.logicCanvas.getLocation(),
-                               mouseLoc = gui.display.getCursorLocation(), shellLoc = gui.shell.getLocation();
-               return new Point(mouseLoc.x - shellLoc.x - canvasLoc.x, mouseLoc.y - shellLoc.y - canvasLoc.y);
-       }
-
-       public Point getWorldMousePosition()
-       {
-               return gui.logicCanvas.canvasToWorldCoords(getCanvasMousePosition());
-       }
-
        public void addWire(PinHandle a, PinHandle b)
        {
                new GUIWire(toBeEdited.getSubmodelModifiable(), a.getPin(), b.getPin(), new Point[0]);
@@ -206,10 +197,26 @@ public final class Editor
        public static enum Snapping
        {
                OFF, ABSOLUTE;
+               
+               @Override
+               public String toString()
+               {
+                       return super.toString().toLowerCase();
+               }
        }
        
        public static void main(String[] args)
        {
                SaveLoadManager.openLoadDialog();
        }
+
+       public Snapping getSnapping()
+       {
+               return snapping;
+       }
+
+       public void setSnapping(Snapping snapping)
+       {
+               this.snapping = snapping;
+       }
 }
diff --git a/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/EditorCanvas.java b/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/EditorCanvas.java
deleted file mode 100644 (file)
index df6b913..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.mograsim.logic.model.editor;
-
-import java.util.Collection;
-
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.widgets.Composite;
-
-import net.haspamelodica.swt.helper.gcs.TranslatedGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-import net.mograsim.logic.model.LogicUICanvas;
-import net.mograsim.logic.model.editor.handles.Handle;
-import net.mograsim.preferences.Preferences;
-
-public class EditorCanvas extends LogicUICanvas
-{
-       private Collection<Handle> handles;
-
-       public EditorCanvas(Composite parent, int style, Editor editor)
-       {
-               super(parent, style, editor.toBeEdited.submodel);
-
-               handles = editor.handleManager.getHandles();
-               editor.handleManager.addHandleAddedListener(h -> 
-               h.addRedrawListener(this::redrawThreadsafe));
-               //Is this even necessary? The Handle should be finalized by the gc
-               editor.handleManager.addHandleRemovedListener(h -> h.removeRedrawListener(this::redrawThreadsafe));
-
-               addZoomedRenderer(gc ->
-               {
-                       Rectangle visibleRegion = new Rectangle(-offX / zoom, -offY / zoom, gW / zoom, gH / zoom);
-                       Color background = Preferences.current().getColor("net.mograsim.logic.ui.color.background");
-                       if (background != null)
-                               setBackground(background);// this.setBackground, not gc.setBackground to have the background fill the
-                                                                                       // canvas
-                       
-                       TranslatedGC tgc = new TranslatedGC(gc, 0.0d, 0.0d, 1 / editor.toBeEdited.getSubmodelScale(), false);
-                       editor.toBeEdited.outlineRenderer.render(tgc, new Rectangle(-offX / zoom, -offY / zoom, gW / zoom, gH / zoom));
-                       
-                       handles.forEach(h -> h.render(gc, visibleRegion));
-               });
-       }
-}
diff --git a/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/EditorGUI.java b/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/EditorGUI.java
deleted file mode 100644 (file)
index 2627d3c..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-package net.mograsim.logic.model.editor;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.List;
-import org.eclipse.swt.widgets.Shell;
-
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
-import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
-
-public class EditorGUI
-{
-       final Display display;
-       final Shell shell;
-       public final EditorCanvas logicCanvas;
-       private final List addList;
-
-       public EditorGUI(Editor editor)
-       {
-               display = Display.getDefault();
-               shell = new Shell(display);
-               
-               //Layout
-               GridLayout layout = new GridLayout();
-               shell.setLayout(layout);
-               layout.numColumns = 2;
-               
-               GridData d = new GridData();
-               d.grabExcessVerticalSpace = true;
-               d.verticalAlignment = SWT.FILL;
-               addList = new List(shell, SWT.FILL);
-               addList.setLayoutData(d);
-               refreshAddList();
-               
-               d = new GridData();
-               d.grabExcessHorizontalSpace = true;
-               d.horizontalAlignment = SWT.FILL;
-               d.grabExcessVerticalSpace = true;
-               d.verticalAlignment = SWT.FILL;
-               
-               logicCanvas = new EditorCanvas(shell, SWT.TRAIL, editor);
-               logicCanvas.setLayoutData(d);
-               
-               
-               new EditorUserInput(editor, this);
-               ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(logicCanvas);
-               userInput.buttonDrag = 3;
-               userInput.buttonZoom = 2;
-               userInput.enableUserInput();
-               new ZoomableCanvasOverlay(logicCanvas, null).enableScale();
-       }
-       
-       public void refreshAddList()
-       {
-               addList.setItems(IndirectGUIComponentCreator.getStandardComponentIDs().toArray(String[]::new));
-               addList.select(0);
-       }
-       
-       public String getAddListSelected()
-       {
-               String[] selection = addList.getSelection();
-               if(selection.length == 0)
-                       throw new IllegalStateException("Selection in the Add Component List may never be empty!");
-               return selection[0];
-       }
-
-       public void open()
-       {
-               shell.open();
-               while (!shell.isDisposed())
-                       if (!display.readAndDispatch())
-                               display.sleep();
-       }
-
-}
index cb66e94..441360d 100644 (file)
@@ -7,11 +7,15 @@ import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
 
 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.mograsim.logic.model.editor.ui.EditorGUI;
 
 public class EditorUserInput
 {
-       public EditorUserInput(Editor editor, EditorGUI gui)
+       private final EditorGUI gui;
+       
+       public EditorUserInput(Editor editor)
        {
+               this.gui = editor.gui;
                gui.logicCanvas.addMouseListener(new MouseListener()
                {
                        @Override
@@ -92,4 +96,14 @@ public class EditorUserInput
                        }
                });
        }
+       
+       public Point getCanvasMousePosition()
+       {
+               return new Point(gui.logicCanvas.toControl(gui.display.getCursorLocation()));
+       }
+
+       public Point getWorldMousePosition()
+       {
+               return gui.logicCanvas.canvasToWorldCoords(getCanvasMousePosition());
+       }
 }
\ No newline at end of file
index 848227b..1ba1d25 100644 (file)
@@ -2,7 +2,7 @@ package net.mograsim.logic.model.editor;
 
 import java.io.IOException;
 
-import net.mograsim.logic.model.editor.DialogManager.InteractiveDialog;
+import net.mograsim.logic.model.editor.ui.DialogManager.InteractiveDialog;
 import net.mograsim.logic.model.model.ViewModelModifiable;
 import net.mograsim.logic.model.serializing.DeserializedSubmodelComponent;
 import net.mograsim.logic.model.serializing.SubmodelComponentDeserializer;
index 446635e..2a66e47 100644 (file)
@@ -7,12 +7,12 @@ import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
 import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas.ZoomedRenderer;
 import net.mograsim.logic.model.editor.Editor;
 import net.mograsim.logic.model.editor.Selection;
-import net.mograsim.logic.model.editor.DialogManager.InteractiveDialog;
 import net.mograsim.logic.model.editor.handles.Handle;
 import net.mograsim.logic.model.editor.handles.PinHandle;
 import net.mograsim.logic.model.editor.handles.WireHandle;
 import net.mograsim.logic.model.editor.handles.Handle.HandleClickInfo;
 import net.mograsim.logic.model.editor.handles.WireHandle.WireHandleClickInfo;
+import net.mograsim.logic.model.editor.ui.DialogManager.InteractiveDialog;
 import net.mograsim.logic.model.model.wires.MovablePin;
 import net.mograsim.logic.model.model.wires.Pin;
 
@@ -36,7 +36,7 @@ public class SelectionState extends EditorState
        @Override
        public void add()
        {
-               Point curserPos = editor.getWorldMousePosition();
+               Point curserPos = editor.userInput.getWorldMousePosition();
                editor.addComponent(curserPos.x, curserPos.y);
        }
 
@@ -55,7 +55,7 @@ public class SelectionState extends EditorState
        @Override
        public void paste()
        {
-               Point curserPos = editor.getWorldMousePosition();
+               Point curserPos = editor.userInput.getWorldMousePosition();
                editor.paste(curserPos.x, curserPos.y);
        }
 
diff --git a/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/DialogManager.java b/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/DialogManager.java
new file mode 100644 (file)
index 0000000..7d982e0
--- /dev/null
@@ -0,0 +1,133 @@
+package net.mograsim.logic.model.editor.ui;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import net.mograsim.logic.model.editor.Editor;
+
+public class DialogManager
+{
+       private Shell parent;
+       
+       public DialogManager(Shell parent)
+       {
+               this.parent = parent;
+       }
+
+       public void openWarningDialog(String title, String message)
+       {
+               MessageBox b = new MessageBox(parent, SWT.ICON_WARNING | SWT.OK);
+               b.setText(title);
+               b.setMessage(message);
+               b.open();
+       }
+       
+       public static class InteractiveDialog
+       {
+               private String[] finalInput;
+               private final Display display;
+               private final Shell shell;
+               private final Button b1, b2;
+               private Text[] textFields;
+               private InteractiveDialog.InteractiveDialogState state;
+
+               public InteractiveDialog(String title, String acceptLabel, String cancelLabel, String... inputs)
+               {
+                       display = Display.getDefault();
+                       shell = new Shell(SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.ON_TOP | SWT.APPLICATION_MODAL);
+                       shell.setMinimumSize(500, 150);
+                       shell.setText(title);
+                       GridLayout layout = new GridLayout();
+                       layout.numColumns = 2;
+                       shell.setLayout(layout);
+
+                       this.textFields = new Text[inputs.length];
+                       for (int i = 0; i < inputs.length; i++)
+                       {
+                               Label textFieldName = new Label(shell, SWT.NONE);
+                               textFieldName.setText(inputs[i].concat(":"));
+                               GridData g = new GridData();
+                               g.grabExcessHorizontalSpace = true;
+                               g.horizontalAlignment = SWT.FILL;
+                               Text newTextField = new Text(shell, SWT.BORDER);
+                               newTextField.setLayoutData(g);
+                               textFields[i] = newTextField;
+                       }
+                       b1 = new Button(shell, SWT.PUSH);
+                       b1.addListener(SWT.Selection, e ->
+                       {
+                               state = InteractiveDialogState.ACCEPTED;
+                               buildFinalInput();
+                               dispose();
+                       });
+                       b1.setText(acceptLabel);
+                       b2 = new Button(shell, SWT.PUSH);
+                       b2.addListener(SWT.Selection, e ->
+                       {
+                               state = InteractiveDialogState.CANCELLED;
+                               buildFinalInput();
+                               dispose();
+                       });
+                       b2.setText(cancelLabel);
+
+                       state = InteractiveDialogState.ACTIVE;
+
+                       shell.pack();
+               }
+
+               public String getText()
+               {
+                       return getText(0);
+               }
+
+               public String getText(int index)
+               {
+                       if (!shell.isDisposed())
+                               return textFields[index].getText();
+                       else
+                               return finalInput[index];
+               }
+
+               public void open()
+               {
+                       shell.open();
+                       while (!shell.isDisposed())
+                               if (!display.readAndDispatch())
+                                       display.sleep();
+               }
+
+               public void dispose()
+               {
+                       shell.dispose();
+               }
+
+               public InteractiveDialog.InteractiveDialogState getState()
+               {
+                       return state;
+               }
+
+               private void buildFinalInput()
+               {
+                       finalInput = new String[textFields.length];
+                       for (int i = 0; i < textFields.length; i++)
+                               finalInput[i] = textFields[i].getText();
+               }
+
+               public static enum InteractiveDialogState
+               {
+                       ACTIVE, ACCEPTED, CANCELLED;
+               }
+       }
+       
+       public static void openAddPinDialog(Editor editor, double x, double y)
+       {
+               
+       }
+}
diff --git a/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/EditorCanvas.java b/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/EditorCanvas.java
new file mode 100644 (file)
index 0000000..357e88f
--- /dev/null
@@ -0,0 +1,44 @@
+package net.mograsim.logic.model.editor.ui;
+
+import java.util.Collection;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Composite;
+
+import net.haspamelodica.swt.helper.gcs.TranslatedGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.mograsim.logic.model.LogicUICanvas;
+import net.mograsim.logic.model.editor.Editor;
+import net.mograsim.logic.model.editor.handles.Handle;
+import net.mograsim.preferences.Preferences;
+
+//TODO: Remove Inheritance 
+public class EditorCanvas extends LogicUICanvas
+{
+       private Collection<Handle> handles;
+
+       public EditorCanvas(Composite parent, int style, Editor editor)
+       {
+               super(parent, style, editor.toBeEdited.submodel);
+
+               handles = editor.handleManager.getHandles();
+               editor.handleManager.addHandleAddedListener(h -> 
+               h.addRedrawListener(this::redrawThreadsafe));
+               //TODO: Is this even necessary? The Handle should be finalized by the gc
+               editor.handleManager.addHandleRemovedListener(h -> h.removeRedrawListener(this::redrawThreadsafe));
+
+               addZoomedRenderer(gc ->
+               {
+                       Rectangle visibleRegion = new Rectangle(-offX / zoom, -offY / zoom, gW / zoom, gH / zoom);
+                       Color background = Preferences.current().getColor("net.mograsim.logic.ui.color.background");
+                       if (background != null)
+                               setBackground(background);// this.setBackground, not gc.setBackground to have the background fill the
+                                                                                       // canvas
+                       
+                       TranslatedGC tgc = new TranslatedGC(gc, 0.0d, 0.0d, 1 / editor.toBeEdited.getSubmodelScale(), false);
+                       editor.toBeEdited.outlineRenderer.render(tgc, new Rectangle(-offX / zoom, -offY / zoom, gW / zoom, gH / zoom));
+                       
+                       handles.forEach(h -> h.render(gc, visibleRegion));
+               });
+       }
+}
diff --git a/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/EditorGUI.java b/net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/ui/EditorGUI.java
new file mode 100644 (file)
index 0000000..4d5236f
--- /dev/null
@@ -0,0 +1,147 @@
+package net.mograsim.logic.model.editor.ui;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
+import net.mograsim.logic.model.editor.Editor;
+import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
+
+public class EditorGUI
+{
+       public final Display display;
+       public final Shell shell;
+       public final EditorCanvas logicCanvas;
+       private final List addList;
+       private final Editor editor;
+
+       public EditorGUI(Editor editor)
+       {
+               this.editor = editor;
+               display = Display.getDefault();
+               shell = new Shell(display);
+
+               // Layout
+               GridLayout layout = new GridLayout();
+               shell.setLayout(layout);
+               layout.numColumns = 2;
+
+               GridData d = new GridData();
+               d.grabExcessVerticalSpace = true;
+               d.verticalAlignment = SWT.FILL;
+               d.verticalSpan = 2;
+               addList = new List(shell, SWT.FILL);
+               addList.setLayoutData(d);
+               refreshAddList();
+
+               d = new GridData();
+               d.grabExcessHorizontalSpace = true;
+               d.horizontalAlignment = SWT.FILL;
+               d.grabExcessVerticalSpace = true;
+               d.verticalAlignment = SWT.FILL;
+
+               logicCanvas = new EditorCanvas(shell, SWT.TRAIL, editor);
+               logicCanvas.setLayoutData(d);
+
+               setupToolBar();
+
+               ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(logicCanvas);
+               userInput.buttonDrag = 3;
+               userInput.buttonZoom = 2;
+               userInput.enableUserInput();
+               new ZoomableCanvasOverlay(logicCanvas, null).enableScale();
+       }
+
+       private ToolBar setupToolBar()
+       {
+               GridData d = new GridData();
+               d.grabExcessHorizontalSpace = true;
+               d.horizontalAlignment = SWT.FILL;
+
+               ToolBar toolBar = new ToolBar(shell, SWT.BORDER);
+               toolBar.setLayoutData(d);
+
+               ToolItem snappingLabel = new ToolItem(toolBar, SWT.NONE);
+               snappingLabel.setText("Snapping:");
+               
+               Menu menu = new Menu(shell, SWT.POP_UP);
+               ToolItem snappSelect = new ToolItem(toolBar, SWT.DROP_DOWN);
+               for (Editor.Snapping sn : Editor.Snapping.values())
+               {
+                       MenuItem item = new MenuItem(menu, SWT.PUSH);
+                       item.addSelectionListener(new SelectionListener()
+                       {
+                               @Override
+                               public void widgetSelected(SelectionEvent arg0)
+                               {
+                                       editor.setSnapping(sn);
+                                       snappSelect.setText(sn.toString());
+                               }
+                               
+                               @Override
+                               public void widgetDefaultSelected(SelectionEvent arg0) {}
+                       });
+                       item.setText(sn.toString());
+               }
+               
+               snappSelect.setText(editor.getSnapping().toString());
+               snappSelect.addListener(SWT.Selection, new Listener()
+               {
+                       public void handleEvent(Event event)
+                       {
+                               if (event.detail == SWT.ARROW)
+                               {
+                                       Rectangle rect = snappSelect.getBounds();
+                                       Point pt = new Point(rect.x, rect.y + rect.height);
+                                       pt = toolBar.toDisplay(pt);
+                                       menu.setLocation(pt.x, pt.y);
+                                       menu.setVisible(true);
+                               }
+                       }
+               });
+               
+               new ToolItem(toolBar, SWT.SEPARATOR);
+               
+               toolBar.pack();
+
+               return toolBar;
+       }
+
+       public void refreshAddList()
+       {
+               addList.setItems(IndirectGUIComponentCreator.getStandardComponentIDs().toArray(String[]::new));
+               addList.select(0);
+       }
+
+       public String getAddListSelected()
+       {
+               String[] selection = addList.getSelection();
+               if (selection.length == 0)
+                       throw new IllegalStateException("Selection in the Add Component List may never be empty!");
+               return selection[0];
+       }
+
+       public void open()
+       {
+               shell.open();
+               while (!shell.isDisposed())
+                       if (!display.readAndDispatch())
+                               display.sleep();
+       }
+
+}