Made SimulationView(Editor) a View again
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 30 Sep 2019 16:34:57 +0000 (18:34 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 30 Sep 2019 16:35:29 +0000 (18:35 +0200)
plugins/net.mograsim.plugin.core/META-INF/MANIFEST.MF
plugins/net.mograsim.plugin.core/plugin.xml
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/editors/SimulationViewEditor.java [deleted file]
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/util/OverlappingFillLayout.java [new file with mode: 0644]
plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/views/SimulationView.java [new file with mode: 0644]

index d12f07c..a5add49 100644 (file)
@@ -15,6 +15,7 @@ Export-Package: net.mograsim.plugin;uses:="org.eclipse.ui.themes,org.eclipse.swt
  net.mograsim.plugin.tables.memory,
  net.mograsim.plugin.tables.mi,
  net.mograsim.plugin.util,
+ net.mograsim.plugin.views,
  net.mograsim.plugin.wizards.newWizards
 Require-Bundle: org.eclipse.core.runtime,
  org.eclipse.ui,
index 7d7e5e1..bb298a2 100644 (file)
                id="net.mograsim.plugin.tables.mi.InstructionView">
                <contentTypeBinding contentTypeId="net.mograsim.plugin.mpm"/>
       </editor>
-      <editor
-            class="net.mograsim.plugin.editors.SimulationViewEditor"
-            icon="icons/mograsim/blue-orange/icon_blue-orange_16.png"
-            id="net.mograsim.plugin.editors.simulationvieweditor"
-            name="Simulation View Editor">
-               <contentTypeBinding contentTypeId="net.mograsim.plugin.regs"/>
-      </editor>
       <editor
             class="net.mograsim.plugin.editors.MemoryEditor"
             icon="icons/mograsim/blue-orange/icon_blue-orange_16.png"
             inject="true"
             name="%view.name">
       </view>
+      <view
+            category="net.mograsim.plugin"
+            class="net.mograsim.plugin.views.SimulationView"
+            icon="icons/mograsim/blue-orange/icon_blue-orange_16.png"
+            id="net.mograsim.plugin.simulationview"
+            name="Simulation View"
+            restorable="true">
+      </view>
    </extension>
    <extension
          id="net.mograsim.plugin.nature.mograsimBuilder"
diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/editors/SimulationViewEditor.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/editors/SimulationViewEditor.java
deleted file mode 100644 (file)
index 651852e..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-package net.mograsim.plugin.editors;
-
-import java.io.ByteArrayInputStream;
-import java.util.Optional;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.util.SafeRunnable;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseTrackListener;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Scale;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.IFileEditorInput;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.part.EditorPart;
-
-import net.haspamelodica.swt.helper.input.DoubleInput;
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
-import net.mograsim.logic.core.LogicObserver;
-import net.mograsim.logic.core.components.CoreClock;
-import net.mograsim.logic.model.LogicExecuter;
-import net.mograsim.logic.model.LogicUICanvas;
-import net.mograsim.logic.model.serializing.IndirectModelComponentCreator;
-import net.mograsim.machine.Machine;
-import net.mograsim.machine.Memory.MemoryCellModifiedListener;
-import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
-import net.mograsim.plugin.nature.MachineContext;
-import net.mograsim.plugin.nature.MachineContext.ActiveMachineListener;
-import net.mograsim.plugin.nature.ProjectMachineContext;
-import net.mograsim.plugin.tables.DisplaySettings;
-import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
-import net.mograsim.plugin.tables.mi.InstructionTable;
-import net.mograsim.preferences.Preferences;
-
-//TODO what if we open multiple editors?
-//TODO actually save / load register and latch states
-public class SimulationViewEditor extends EditorPart
-{
-       private static final int SIM_SPEED_SCALE_STEPS = 50;
-       private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
-       private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
-
-       private MachineContext context;
-
-       private LogicExecuter exec;
-       private Machine machine;
-
-       private Composite parent;
-       private Button resetButton;
-       private Button sbseButton;
-       private Button pauseButton;
-       private Scale simSpeedScale;
-       private DoubleInput simSpeedInput;
-       private Composite canvasParent;
-       private LogicUICanvas canvas;
-       private InstructionTable instPreview;
-       private Label noMachineLabel;
-
-       private ActiveMachineListener activeMachineListener;
-       private MemoryCellModifiedListener memCellListener;
-       private LogicObserver clockObserver;
-
-       public SimulationViewEditor()
-       {
-               activeMachineListener = (oldM, newM) -> recreateContextDependentControls();
-               memCellListener = a -> instPreview.refresh();
-               clockObserver = o ->
-               {
-                       if (((CoreClock) o).isOn())
-                       {
-                               exec.pauseLiveExecution();
-                               if (!pauseButton.isDisposed())
-                                       Display.getDefault().asyncExec(() ->
-                                       {
-                                               if (!pauseButton.isDisposed())
-                                                       pauseButton.setSelection(false);
-                                               setPauseText(pauseButton, false);
-                                       });
-                       }
-               };
-       }
-
-       @Override
-       public void createPartControl(Composite parent)
-       {
-               this.parent = parent;
-               // initialize UI
-               parent.setLayout(new GridLayout());
-
-               noMachineLabel = new Label(parent, SWT.NONE);
-               noMachineLabel.setText("No machine present...");// TODO internationalize?
-               addSimulationControlWidgets(parent);
-               canvasParent = new Composite(parent, SWT.NONE);
-               canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               canvasParent.setLayout(new FillLayout());
-               addInstructionPreviewControlWidgets(parent);
-               recreateContextDependentControls();
-       }
-
-       private void recreateContextDependentControls()
-       {
-               if (parent == null)
-                       // createPartControls has not been called yet
-                       return;
-
-               double offX;
-               double offY;
-               double zoom;
-               stopExecAndDeregisterContextDependentListeners();
-               if (canvas != null)
-               {
-                       offX = canvas.getOffX();
-                       offY = canvas.getOffY();
-                       zoom = canvas.getZoom();
-                       canvas.dispose();
-               } else
-               {
-                       offX = 0;
-                       offY = 0;
-                       zoom = -1;
-               }
-
-               Optional<Machine> machineOptional;
-               if (context != null && (machineOptional = context.getActiveMachine()).isPresent())
-               {
-                       noMachineLabel.setVisible(false);
-                       resetButton.setEnabled(true);
-                       sbseButton.setEnabled(true);
-                       pauseButton.setEnabled(true);
-                       simSpeedScale.setEnabled(true);
-                       simSpeedInput.setEnabled(true);
-
-                       machine = machineOptional.get();
-                       canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
-                       canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
-                       ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
-                       userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
-                       userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
-                       userInput.enableUserInput();
-                       if (zoom > 0)
-                       {
-                               canvas.moveTo(offX, offY, zoom);
-                               canvas.commitTransform();
-                       }
-
-                       AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
-                       instPreview.bindMicroInstructionMemory(mIMemory);
-                       mIMemory.registerCellModifiedListener(memCellListener);
-
-                       canvasParent.layout();
-
-                       // update preview
-                       ((ActiveInstructionPreviewContentProvider) instPreview.getTableViewer().getContentProvider()).setMachine(machine);
-
-                       // initialize executer
-                       exec = new LogicExecuter(machine.getTimeline());
-                       updateSpeedFactorFromInput(simSpeedInput.getValue());
-                       updatePausedState();
-                       exec.startLiveExecution();
-               } else
-               {
-                       noMachineLabel.setVisible(true);
-                       resetButton.setEnabled(false);
-                       sbseButton.setEnabled(false);
-                       pauseButton.setEnabled(false);
-                       simSpeedScale.setEnabled(false);
-                       simSpeedInput.setEnabled(false);
-               }
-       }
-
-       private void stopExecAndDeregisterContextDependentListeners()
-       {
-               if (exec != null)
-                       exec.stopLiveExecution();
-               if (machine != null)
-               {
-                       machine.getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
-                       machine.getClock().deregisterObserver(clockObserver);
-               }
-       }
-
-       private void addSimulationControlWidgets(Composite parent)
-       {
-               Composite c = new Composite(parent, SWT.NONE);
-               c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               c.setLayout(new GridLayout(7, false));
-
-               resetButton = new Button(c, SWT.PUSH);
-               resetButton.setText("Reset machine");
-               resetButton.addListener(SWT.Selection, e -> context.getActiveMachine().get().reset());
-
-               // TODO do we want this button in the final product?
-               Button reloadMachineButton = new Button(c, SWT.PUSH);
-               reloadMachineButton.setText("Reload machine");
-               reloadMachineButton.addListener(SWT.Selection, e ->
-               {
-                       IndirectModelComponentCreator.clearComponentCache();
-                       context.setActiveMachine(context.getMachineDefinition().get().createNew());
-               });
-
-               sbseButton = new Button(c, SWT.CHECK);
-               pauseButton = new Button(c, SWT.TOGGLE);
-
-               sbseButton.setText("Step by step execution");
-               sbseButton.addListener(SWT.Selection, e ->
-               {
-                       CoreClock cl = machine.getClock();
-                       if (sbseButton.getSelection())
-                               cl.registerObserver(clockObserver);
-                       else
-                               cl.deregisterObserver(clockObserver);
-               });
-               sbseButton.setSelection(false);
-
-               pauseButton.setSelection(true);
-               setPauseText(pauseButton, false);
-
-               pauseButton.addListener(SWT.Selection, e -> updatePausedState());
-               pauseButton.addMouseTrackListener(new MouseTrackListener()
-               {
-                       @Override
-                       public void mouseHover(MouseEvent e)
-                       {
-                               // nothing
-                       }
-
-                       @Override
-                       public void mouseExit(MouseEvent e)
-                       {
-                               setPauseText(pauseButton, false);
-                       }
-
-                       @Override
-                       public void mouseEnter(MouseEvent e)
-                       {
-                               setPauseText(pauseButton, true);
-                       }
-               });
-
-               new Label(c, SWT.NONE).setText("Simulation Speed: ");
-
-               simSpeedScale = new Scale(c, SWT.NONE);
-               simSpeedScale.setMinimum(0);
-               simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
-               simSpeedScale.setIncrement(1);
-               simSpeedScale.setSelection(0);
-               simSpeedScale.addListener(SWT.Selection, e -> updateSpeedFactorFromScale());
-
-               simSpeedInput = new DoubleInput(c, SWT.NONE);
-               simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
-               simSpeedInput.addChangeListener(this::updateSpeedFactorFromInput);
-
-               updateSpeedFactorFromScale();
-
-               c.layout();
-       }
-
-       private void updatePausedState()
-       {
-               setPauseText(pauseButton, false);
-               if (exec != null)
-                       if (pauseButton.getSelection())
-                               exec.unpauseLiveExecution();
-                       else
-                               exec.pauseLiveExecution();
-       }
-
-       private void updateSpeedFactorFromScale()
-       {
-               double factor = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
-               simSpeedInput.setValue(factor);
-               if (exec != null)
-                       exec.setSpeedFactor(factor);
-       }
-
-       private void updateSpeedFactorFromInput(double factor)
-       {
-               double factorCheckedFor0;
-               if (factor != 0)
-                       factorCheckedFor0 = factor;
-               else
-               {
-                       factorCheckedFor0 = Math.pow(10, -simSpeedInput.getPrecision());
-                       simSpeedInput.setValue(factorCheckedFor0);
-               }
-               int closestScalePos = (int) Math.round(Math.log(factorCheckedFor0) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
-               simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
-               if (exec != null)
-                       exec.setSpeedFactor(factorCheckedFor0);
-       }
-
-       private void addInstructionPreviewControlWidgets(Composite parent)
-       {
-               instPreview = new InstructionTable(parent, new DisplaySettings(), getSite().getWorkbenchWindow().getWorkbench().getThemeManager());
-               instPreview.getTableViewer().getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               ActiveInstructionPreviewContentProvider cProv;
-               instPreview.setContentProvider(cProv = new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer()));
-               cProv.setMachine(machine);
-       }
-
-       private static void setPauseText(Button pauseButton, boolean hovered)
-       {
-               if (hovered)
-                       if (pauseButton.getSelection())
-                               pauseButton.setText("Pause?");
-                       else
-                               pauseButton.setText("Resume?");
-               else if (pauseButton.getSelection())
-                       pauseButton.setText("Running");
-               else
-                       pauseButton.setText("Paused");
-       }
-
-       @Override
-       public void init(IEditorSite site, IEditorInput input) throws PartInitException
-       {
-               if (input instanceof IFileEditorInput)
-               {
-                       IFileEditorInput fileInput = (IFileEditorInput) input;
-                       context = ProjectMachineContext.getMachineContextOf(fileInput.getFile().getProject());
-                       context.activateMachine();
-                       context.addActiveMachineListener(activeMachineListener);
-                       recreateContextDependentControls();
-
-                       setPartName(fileInput.getName());
-                       open(fileInput.getFile());
-               } else
-                       throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
-
-               setSite(site);
-               setInput(input);
-       }
-
-       @Override
-       public void doSave(IProgressMonitor monitor)
-       {
-               IEditorInput input = getEditorInput();
-               if (input instanceof IFileEditorInput)
-                       SafeRunnable.getRunner().run(() -> save(((IFileEditorInput) input).getFile(), monitor));
-               else
-                       throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
-       }
-
-       private void save(IFile file, IProgressMonitor monitor) throws CoreException
-       {
-               file.setContents(new ByteArrayInputStream("actual contents will go here".getBytes()), 0, monitor);
-       }
-
-       private void open(IFile file)
-       {
-               // do nothing yet
-       }
-
-       @Override
-       public void doSaveAs()
-       {
-               throw new UnsupportedOperationException();
-       }
-
-       @Override
-       public boolean isDirty()
-       {
-               return false;
-       }
-
-       @Override
-       public boolean isSaveAsAllowed()
-       {
-               return false;
-       }
-
-       @Override
-       public void setFocus()
-       {
-               canvas.setFocus();
-       }
-
-       @Override
-       public void dispose()
-       {
-               stopExecAndDeregisterContextDependentListeners();
-               context.removeActiveMachineListener(activeMachineListener);
-               super.dispose();
-       }
-}
\ No newline at end of file
diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/util/OverlappingFillLayout.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/util/OverlappingFillLayout.java
new file mode 100644 (file)
index 0000000..839ba71
--- /dev/null
@@ -0,0 +1,37 @@
+package net.mograsim.plugin.util;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Layout;
+
+public class OverlappingFillLayout extends Layout
+{
+       @Override
+       protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache)
+       {
+               Point size = new Point(wHint == SWT.DEFAULT ? 0 : wHint, hHint == SWT.DEFAULT ? 0 : hHint);
+
+               Control[] children = composite.getChildren();
+               for (Control child : children)
+               {
+                       Point childSize = child.computeSize(wHint, hHint, flushCache);
+                       size.x = Math.max(size.x, childSize.x);
+                       size.y = Math.max(size.y, childSize.y);
+               }
+
+               return size;
+       }
+
+       @Override
+       protected void layout(Composite composite, boolean flushCache)
+       {
+               Rectangle bounds = composite.getClientArea();
+
+               Control[] children = composite.getChildren();
+               for (Control child : children)
+                       child.setBounds(bounds);
+       }
+}
\ No newline at end of file
diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/views/SimulationView.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/views/SimulationView.java
new file mode 100644 (file)
index 0000000..4d118a9
--- /dev/null
@@ -0,0 +1,302 @@
+package net.mograsim.plugin.views;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.contexts.IDebugContextListener;
+import org.eclipse.debug.ui.contexts.IDebugContextManager;
+import org.eclipse.debug.ui.contexts.IDebugContextService;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Scale;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+import net.haspamelodica.swt.helper.input.DoubleInput;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
+import net.mograsim.logic.core.LogicObserver;
+import net.mograsim.logic.core.components.CoreClock;
+import net.mograsim.logic.model.LogicUICanvas;
+import net.mograsim.machine.Machine;
+import net.mograsim.machine.Memory.MemoryCellModifiedListener;
+import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
+import net.mograsim.plugin.launch.MachineDebugTarget;
+import net.mograsim.plugin.tables.DisplaySettings;
+import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
+import net.mograsim.plugin.tables.mi.InstructionTable;
+import net.mograsim.plugin.util.OverlappingFillLayout;
+import net.mograsim.preferences.Preferences;
+
+public class SimulationView extends ViewPart
+{
+       private static final int SIM_SPEED_SCALE_STEPS = 50;
+       private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
+       private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
+
+       private final Set<Control> controlsToDisableWhenNoMachinePresent;
+       private Scale simSpeedScale;
+       private DoubleInput simSpeedInput;
+       private Composite contextDependentControlsParent;
+       private Composite canvasParent;
+       private InstructionTable instPreview;
+       private ActiveInstructionPreviewContentProvider contentProvider;
+       private Label noRunningMachineLabel;
+
+       private MachineDebugTarget debugTarget;
+       private LogicUICanvas canvas;
+
+       private final MemoryCellModifiedListener memCellListener;
+       private final LogicObserver clockObserver;
+       private final IDebugContextListener debugContextListener;
+       private final Consumer<Double> executionSpeedListener;
+
+       public SimulationView()
+       {
+               controlsToDisableWhenNoMachinePresent = new HashSet<>();
+               memCellListener = a -> instPreview.refresh();
+               // TODO could this be a breakpoint?
+               clockObserver = o ->
+               {
+                       if (((CoreClock) o).isOn())
+                               SafeRunner.run(() -> debugTarget.suspend());
+               };
+               debugContextListener = e -> debugContextChanged(e.getContext());
+               executionSpeedListener = this::speedFactorChanged;
+       }
+
+       @Override
+       public void createPartControl(Composite parent)
+       {
+               // initialize UI
+               parent.setLayout(new GridLayout());
+
+               addSimulationControlWidgets(parent);
+
+               Composite contextDependentControlsParentParent = new Composite(parent, SWT.NONE);
+               contextDependentControlsParentParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               contextDependentControlsParentParent.setLayout(new OverlappingFillLayout());
+
+               noRunningMachineLabel = new Label(contextDependentControlsParentParent, SWT.NONE);
+               noRunningMachineLabel.setText("No machine running && selected in the Debug view...");
+
+               contextDependentControlsParent = new Composite(contextDependentControlsParentParent, SWT.NONE);
+               GridLayout contexDependentControlsLayout = new GridLayout();
+               contexDependentControlsLayout.marginWidth = 0;
+               contexDependentControlsLayout.marginHeight = 0;
+               contextDependentControlsParent.setLayout(contexDependentControlsLayout);
+
+               canvasParent = new Composite(contextDependentControlsParent, SWT.NONE);
+               canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               canvasParent.setLayout(new FillLayout());
+
+               addInstructionPreviewControlWidgets(contextDependentControlsParent);
+
+               IDebugContextManager debugCManager = DebugUITools.getDebugContextManager();
+               IDebugContextService contextService = debugCManager.getContextService(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+               contextService.addDebugContextListener(debugContextListener);
+               debugContextChanged(contextService.getActiveContext());
+       }
+
+       private void addSimulationControlWidgets(Composite parent)
+       {
+               Composite c = new Composite(parent, SWT.NONE);
+               c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               c.setLayout(new GridLayout(7, false));
+
+               Button sbseButton = new Button(c, SWT.CHECK);
+               controlsToDisableWhenNoMachinePresent.add(sbseButton);
+
+               sbseButton.setText("Step by step execution");
+               sbseButton.addListener(SWT.Selection, e ->
+               {
+                       CoreClock cl = debugTarget.getMachine().getClock();
+                       if (sbseButton.getSelection())
+                               cl.registerObserver(clockObserver);
+                       else
+                               cl.deregisterObserver(clockObserver);
+               });
+               sbseButton.setSelection(false);
+
+               Label simSpeedLabel = new Label(c, SWT.NONE);
+               controlsToDisableWhenNoMachinePresent.add(simSpeedLabel);
+               simSpeedLabel.setText("Simulation Speed: ");
+
+               simSpeedScale = new Scale(c, SWT.NONE);
+               controlsToDisableWhenNoMachinePresent.add(simSpeedScale);
+               simSpeedScale.setMinimum(0);
+               simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
+               simSpeedScale.setIncrement(1);
+               simSpeedScale.setSelection(0);
+               simSpeedScale.addListener(SWT.Selection, e ->
+               {
+                       double speed = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
+                       debugTarget.setExecutionSpeed(speed);
+               });
+
+               simSpeedInput = new DoubleInput(c, SWT.NONE);
+               controlsToDisableWhenNoMachinePresent.add(simSpeedInput);
+               simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
+               simSpeedInput.addChangeListener(speed ->
+               {
+                       if (speed != 0)
+                               debugTarget.setExecutionSpeed(speed);
+                       else
+                               debugTarget.setExecutionSpeed(Math.pow(10, -simSpeedInput.getPrecision()));
+               });
+
+               c.layout();
+       }
+
+       private void speedFactorChanged(double speed)
+       {
+               simSpeedInput.setValue(speed);
+               int closestScalePos = (int) Math.round(Math.log(speed) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
+               simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
+       }
+
+       private void addInstructionPreviewControlWidgets(Composite parent)
+       {
+               instPreview = new InstructionTable(parent, new DisplaySettings(), getSite().getWorkbenchWindow().getWorkbench().getThemeManager());
+               instPreview.getTableViewer().getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               contentProvider = new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer());
+               instPreview.setContentProvider(contentProvider);
+       }
+
+       private void debugContextChanged(ISelection selection)
+       {
+               if (selection != null && selection instanceof TreeSelection)
+               {
+                       TreeSelection treeSelection = (TreeSelection) selection;
+                       Object[] selectedElements = treeSelection.toArray();
+                       for (Object selectedElement : selectedElements)
+                       {
+                               MachineDebugTarget debugTarget;
+                               if (selectedElement instanceof MachineDebugTarget)
+                                       debugTarget = (MachineDebugTarget) selectedElement;
+                               else if (selectedElement instanceof ILaunch)
+                               {
+                                       ILaunch launch = (ILaunch) selectedElement;
+                                       IDebugTarget genericDebugTarget = launch.getDebugTarget();
+                                       if (genericDebugTarget instanceof MachineDebugTarget)
+                                               debugTarget = (MachineDebugTarget) genericDebugTarget;
+                                       else
+                                               continue;
+                               } else
+                                       continue;
+                               if (debugTarget.isTerminated())
+                                       continue;
+                               // we found a selected MachineDebugTarget
+                               if (this.debugTarget != debugTarget)
+                                       bindToDebugTarget(debugTarget);
+                               return;
+                       }
+               }
+               // we didn't find a selected MachineDebugTarget
+               // call binToDebugTarget even if this.debugTarget==null
+               bindToDebugTarget(null);
+       }
+
+       private void bindToDebugTarget(MachineDebugTarget debugTarget)
+       {
+               this.debugTarget = debugTarget;
+
+               if (canvasParent == null)
+                       // createPartControls has not been called yet
+                       return;
+
+               double offX;
+               double offY;
+               double zoom;
+               deregisterMachineDependentListeners();
+               if (canvas != null)
+               {
+                       offX = canvas.getOffX();
+                       offY = canvas.getOffY();
+                       zoom = canvas.getZoom();
+                       canvas.dispose();
+               } else
+               {
+                       offX = 0;
+                       offY = 0;
+                       zoom = -1;
+               }
+
+               if (debugTarget != null)
+               {
+                       noRunningMachineLabel.setVisible(false);
+                       contextDependentControlsParent.setVisible(true);
+                       controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(true));
+
+                       Machine machine = debugTarget.getMachine();
+
+                       canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
+                       canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
+                       ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
+                       userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
+                       userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
+                       userInput.enableUserInput();
+                       if (zoom > 0)
+                       {
+                               canvas.moveTo(offX, offY, zoom);
+                               canvas.commitTransform();
+                       }
+
+                       AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
+                       instPreview.bindMicroInstructionMemory(mIMemory);
+                       mIMemory.registerCellModifiedListener(memCellListener);
+
+                       canvasParent.layout();
+
+                       // update preview
+                       contentProvider.setMachine(machine);
+
+                       // initialize executer
+                       debugTarget.addExecutionSpeedListener(executionSpeedListener);
+                       speedFactorChanged(debugTarget.getExecutionSpeed());
+               } else
+               {
+                       noRunningMachineLabel.setVisible(true);
+                       contextDependentControlsParent.setVisible(false);
+                       controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(false));
+                       contentProvider.setMachine(null);
+               }
+       }
+
+       private void deregisterMachineDependentListeners()
+       {
+               if (debugTarget != null)
+               {
+                       debugTarget.removeExecutionSpeedListener(executionSpeedListener);
+                       debugTarget.getMachine().getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
+                       debugTarget.getMachine().getClock().deregisterObserver(clockObserver);
+               }
+       }
+
+       @Override
+       public void setFocus()
+       {
+               if (canvas != null && !canvas.isDisposed())
+                       canvas.setFocus();
+       }
+
+       @Override
+       public void dispose()
+       {
+               deregisterMachineDependentListeners();
+               DebugUITools.getDebugContextManager().removeDebugContextListener(debugContextListener);
+               super.dispose();
+       }
+}
\ No newline at end of file