The selection of the SBSEButton now follows the actual state
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / views / SimulationView.java
1 package net.mograsim.plugin.views;
2
3 import java.util.HashSet;
4 import java.util.Set;
5 import java.util.function.Consumer;
6
7 import org.eclipse.core.runtime.SafeRunner;
8 import org.eclipse.debug.core.ILaunch;
9 import org.eclipse.debug.core.model.IDebugTarget;
10 import org.eclipse.debug.ui.DebugUITools;
11 import org.eclipse.debug.ui.contexts.IDebugContextListener;
12 import org.eclipse.debug.ui.contexts.IDebugContextManager;
13 import org.eclipse.debug.ui.contexts.IDebugContextService;
14 import org.eclipse.jface.viewers.ISelection;
15 import org.eclipse.jface.viewers.TreeSelection;
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.layout.FillLayout;
18 import org.eclipse.swt.layout.GridData;
19 import org.eclipse.swt.layout.GridLayout;
20 import org.eclipse.swt.widgets.Button;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Control;
23 import org.eclipse.swt.widgets.Label;
24 import org.eclipse.swt.widgets.Scale;
25 import org.eclipse.ui.PlatformUI;
26 import org.eclipse.ui.part.ViewPart;
27
28 import net.haspamelodica.swt.helper.input.DoubleInput;
29 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
30 import net.mograsim.logic.core.LogicObserver;
31 import net.mograsim.logic.core.components.CoreClock;
32 import net.mograsim.logic.model.LogicUICanvas;
33 import net.mograsim.machine.Machine;
34 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
35 import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
36 import net.mograsim.plugin.launch.MachineDebugTarget;
37 import net.mograsim.plugin.tables.DisplaySettings;
38 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
39 import net.mograsim.plugin.tables.mi.InstructionTable;
40 import net.mograsim.plugin.util.OverlappingFillLayout;
41 import net.mograsim.preferences.Preferences;
42
43 public class SimulationView extends ViewPart
44 {
45         private static final int SIM_SPEED_SCALE_STEPS = 50;
46         private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
47         private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
48
49         private final Set<Control> controlsToDisableWhenNoMachinePresent;
50         private Button sbseButton;
51         private Scale simSpeedScale;
52         private DoubleInput simSpeedInput;
53         private Composite contextDependentControlsParent;
54         private Composite canvasParent;
55         private InstructionTable instPreview;
56         private ActiveInstructionPreviewContentProvider contentProvider;
57         private Label noRunningMachineLabel;
58
59         private MachineDebugTarget debugTarget;
60         private LogicUICanvas canvas;
61
62         private final MemoryCellModifiedListener memCellListener;
63         private final LogicObserver clockObserver;
64         private final IDebugContextListener debugContextListener;
65         private final Consumer<Double> executionSpeedListener;
66
67         public SimulationView()
68         {
69                 controlsToDisableWhenNoMachinePresent = new HashSet<>();
70                 memCellListener = a -> instPreview.refresh();
71                 // TODO could this be a breakpoint?
72                 clockObserver = o ->
73                 {
74                         if (((CoreClock) o).isOn())
75                                 SafeRunner.run(() -> debugTarget.suspend());
76                 };
77                 debugContextListener = e -> debugContextChanged(e.getContext());
78                 executionSpeedListener = this::speedFactorChanged;
79         }
80
81         @Override
82         public void createPartControl(Composite parent)
83         {
84                 // initialize UI
85                 parent.setLayout(new GridLayout());
86
87                 addSimulationControlWidgets(parent);
88
89                 Composite contextDependentControlsParentParent = new Composite(parent, SWT.NONE);
90                 contextDependentControlsParentParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
91                 contextDependentControlsParentParent.setLayout(new OverlappingFillLayout());
92
93                 noRunningMachineLabel = new Label(contextDependentControlsParentParent, SWT.NONE);
94                 noRunningMachineLabel.setText("No machine running && selected in the Debug view...");
95
96                 contextDependentControlsParent = new Composite(contextDependentControlsParentParent, SWT.NONE);
97                 GridLayout contexDependentControlsLayout = new GridLayout();
98                 contexDependentControlsLayout.marginWidth = 0;
99                 contexDependentControlsLayout.marginHeight = 0;
100                 contextDependentControlsParent.setLayout(contexDependentControlsLayout);
101
102                 canvasParent = new Composite(contextDependentControlsParent, SWT.NONE);
103                 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
104                 canvasParent.setLayout(new FillLayout());
105
106                 addInstructionPreviewControlWidgets(contextDependentControlsParent);
107
108                 IDebugContextManager debugCManager = DebugUITools.getDebugContextManager();
109                 IDebugContextService contextService = debugCManager.getContextService(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
110                 contextService.addDebugContextListener(debugContextListener);
111                 debugContextChanged(contextService.getActiveContext());
112         }
113
114         private void addSimulationControlWidgets(Composite parent)
115         {
116                 Composite c = new Composite(parent, SWT.NONE);
117                 c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
118                 c.setLayout(new GridLayout(7, false));
119
120                 sbseButton = new Button(c, SWT.CHECK);
121                 controlsToDisableWhenNoMachinePresent.add(sbseButton);
122
123                 sbseButton.setText("Step by step execution");
124                 sbseButton.addListener(SWT.Selection, e ->
125                 {
126                         CoreClock cl = debugTarget.getMachine().getClock();
127                         if (sbseButton.getSelection())
128                                 cl.registerObserver(clockObserver);
129                         else
130                                 cl.deregisterObserver(clockObserver);
131                 });
132                 sbseButton.setSelection(false);
133
134                 Label simSpeedLabel = new Label(c, SWT.NONE);
135                 controlsToDisableWhenNoMachinePresent.add(simSpeedLabel);
136                 simSpeedLabel.setText("Simulation Speed: ");
137
138                 simSpeedScale = new Scale(c, SWT.NONE);
139                 controlsToDisableWhenNoMachinePresent.add(simSpeedScale);
140                 simSpeedScale.setMinimum(0);
141                 simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
142                 simSpeedScale.setIncrement(1);
143                 simSpeedScale.setSelection(0);
144                 simSpeedScale.addListener(SWT.Selection, e ->
145                 {
146                         double speed = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
147                         debugTarget.setExecutionSpeed(speed);
148                 });
149
150                 simSpeedInput = new DoubleInput(c, SWT.NONE);
151                 controlsToDisableWhenNoMachinePresent.add(simSpeedInput);
152                 simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
153                 simSpeedInput.addChangeListener(speed ->
154                 {
155                         if (speed != 0)
156                                 debugTarget.setExecutionSpeed(speed);
157                         else
158                                 debugTarget.setExecutionSpeed(Math.pow(10, -simSpeedInput.getPrecision()));
159                 });
160
161                 c.layout();
162         }
163
164         private void speedFactorChanged(double speed)
165         {
166                 simSpeedInput.setValue(speed);
167                 int closestScalePos = (int) Math.round(Math.log(speed) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
168                 simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
169         }
170
171         private void addInstructionPreviewControlWidgets(Composite parent)
172         {
173                 instPreview = new InstructionTable(parent, new DisplaySettings(), getSite().getWorkbenchWindow().getWorkbench().getThemeManager());
174                 instPreview.getTableViewer().getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
175                 contentProvider = new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer());
176                 instPreview.setContentProvider(contentProvider);
177         }
178
179         private void debugContextChanged(ISelection selection)
180         {
181                 if (selection != null && selection instanceof TreeSelection)
182                 {
183                         TreeSelection treeSelection = (TreeSelection) selection;
184                         Object[] selectedElements = treeSelection.toArray();
185                         for (Object selectedElement : selectedElements)
186                         {
187                                 MachineDebugTarget debugTarget;
188                                 if (selectedElement instanceof MachineDebugTarget)
189                                         debugTarget = (MachineDebugTarget) selectedElement;
190                                 else if (selectedElement instanceof ILaunch)
191                                 {
192                                         ILaunch launch = (ILaunch) selectedElement;
193                                         IDebugTarget genericDebugTarget = launch.getDebugTarget();
194                                         if (genericDebugTarget instanceof MachineDebugTarget)
195                                                 debugTarget = (MachineDebugTarget) genericDebugTarget;
196                                         else
197                                                 continue;
198                                 } else
199                                         continue;
200                                 if (debugTarget.isTerminated())
201                                         continue;
202                                 // we found a selected MachineDebugTarget
203                                 if (this.debugTarget != debugTarget)
204                                         bindToDebugTarget(debugTarget);
205                                 return;
206                         }
207                 }
208                 // we didn't find a selected MachineDebugTarget
209                 // call binToDebugTarget even if this.debugTarget==null
210                 bindToDebugTarget(null);
211         }
212
213         private void bindToDebugTarget(MachineDebugTarget debugTarget)
214         {
215                 this.debugTarget = debugTarget;
216
217                 if (canvasParent == null)
218                         // createPartControls has not been called yet
219                         return;
220
221                 double offX;
222                 double offY;
223                 double zoom;
224                 deregisterMachineDependentListeners();
225                 if (canvas != null)
226                 {
227                         offX = canvas.getOffX();
228                         offY = canvas.getOffY();
229                         zoom = canvas.getZoom();
230                         canvas.dispose();
231                 } else
232                 {
233                         offX = 0;
234                         offY = 0;
235                         zoom = -1;
236                 }
237
238                 if (debugTarget != null)
239                 {
240                         noRunningMachineLabel.setVisible(false);
241                         contextDependentControlsParent.setVisible(true);
242                         controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(true));
243
244                         Machine machine = debugTarget.getMachine();
245
246                         canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
247                         canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
248                         ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
249                         userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
250                         userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
251                         userInput.enableUserInput();
252                         if (zoom > 0)
253                         {
254                                 canvas.moveTo(offX, offY, zoom);
255                                 canvas.commitTransform();
256                         }
257
258                         AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
259                         instPreview.bindMicroInstructionMemory(mIMemory);
260                         mIMemory.registerCellModifiedListener(memCellListener);
261
262                         canvasParent.layout();
263
264                         // update preview
265                         contentProvider.setMachine(machine);
266
267                         // initialize executer
268                         debugTarget.addExecutionSpeedListener(executionSpeedListener);
269                         speedFactorChanged(debugTarget.getExecutionSpeed());
270                 } else
271                 {
272                         noRunningMachineLabel.setVisible(true);
273                         contextDependentControlsParent.setVisible(false);
274                         controlsToDisableWhenNoMachinePresent.forEach(c -> c.setEnabled(false));
275                         contentProvider.setMachine(null);
276                 }
277         }
278
279         private void deregisterMachineDependentListeners()
280         {
281                 if (debugTarget != null)
282                 {
283                         debugTarget.removeExecutionSpeedListener(executionSpeedListener);
284                         debugTarget.getMachine().getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
285                         debugTarget.getMachine().getClock().deregisterObserver(clockObserver);
286                         if (sbseButton != null && !sbseButton.isDisposed())
287                                 sbseButton.setSelection(false);
288                 }
289         }
290
291         @Override
292         public void setFocus()
293         {
294                 if (canvas != null && !canvas.isDisposed())
295                         canvas.setFocus();
296         }
297
298         @Override
299         public void dispose()
300         {
301                 deregisterMachineDependentListeners();
302                 contentProvider.setMachine(null);
303                 DebugUITools.getDebugContextManager().removeDebugContextListener(debugContextListener);
304                 super.dispose();
305         }
306 }