Added a reset button to SimulationViewEditor
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / editors / SimulationViewEditor.java
1 package net.mograsim.plugin.editors;
2
3 import java.io.ByteArrayInputStream;
4 import java.util.Optional;
5
6 import org.eclipse.core.resources.IFile;
7 import org.eclipse.core.runtime.CoreException;
8 import org.eclipse.core.runtime.IProgressMonitor;
9 import org.eclipse.jface.util.SafeRunnable;
10 import org.eclipse.swt.SWT;
11 import org.eclipse.swt.events.MouseEvent;
12 import org.eclipse.swt.events.MouseTrackListener;
13 import org.eclipse.swt.layout.FillLayout;
14 import org.eclipse.swt.layout.GridData;
15 import org.eclipse.swt.layout.GridLayout;
16 import org.eclipse.swt.widgets.Button;
17 import org.eclipse.swt.widgets.Composite;
18 import org.eclipse.swt.widgets.Display;
19 import org.eclipse.swt.widgets.Label;
20 import org.eclipse.swt.widgets.Slider;
21 import org.eclipse.ui.IEditorInput;
22 import org.eclipse.ui.IEditorSite;
23 import org.eclipse.ui.IFileEditorInput;
24 import org.eclipse.ui.PartInitException;
25 import org.eclipse.ui.part.EditorPart;
26
27 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
28 import net.mograsim.logic.core.LogicObserver;
29 import net.mograsim.logic.core.components.CoreClock;
30 import net.mograsim.logic.model.LogicExecuter;
31 import net.mograsim.logic.model.LogicUICanvas;
32 import net.mograsim.machine.Machine;
33 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
34 import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
35 import net.mograsim.plugin.nature.MachineContext;
36 import net.mograsim.plugin.nature.MachineContext.ActiveMachineListener;
37 import net.mograsim.plugin.nature.ProjectMachineContext;
38 import net.mograsim.plugin.tables.DisplaySettings;
39 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
40 import net.mograsim.plugin.tables.mi.InstructionTable;
41
42 //TODO what if we open multiple editors?
43 //TODO actually save / load register and latch states
44 public class SimulationViewEditor extends EditorPart
45 {
46         private MachineContext context;
47
48         private LogicExecuter exec;
49         private Machine machine;
50
51         private Composite parent;
52         private Button resetButton;
53         private Button sbseButton;
54         private Button pauseButton;
55         private Slider simSpeedSlider;
56         private Composite canvasParent;
57         private LogicUICanvas canvas;
58         private InstructionTable instPreview;
59         private Label noMachineLabel;
60
61         private ActiveMachineListener activeMNachineListener;
62         private MemoryCellModifiedListener memCellListener;
63         private LogicObserver clockObserver;
64
65         public SimulationViewEditor()
66         {
67                 activeMNachineListener = m -> recreateContextDependentControls();
68                 memCellListener = a -> instPreview.refresh();
69                 clockObserver = o ->
70                 {
71                         if (((CoreClock) o).isOn())
72                         {
73                                 exec.pauseLiveExecution();
74                                 if (!pauseButton.isDisposed())
75                                         Display.getDefault().asyncExec(() ->
76                                         {
77                                                 if (!pauseButton.isDisposed())
78                                                         pauseButton.setSelection(false);
79                                                 setPauseText(pauseButton, false);
80                                         });
81                         }
82                 };
83         }
84
85         @Override
86         public void createPartControl(Composite parent)
87         {
88                 this.parent = parent;
89                 // initialize UI
90                 parent.setLayout(new GridLayout());
91
92                 noMachineLabel = new Label(parent, SWT.NONE);
93                 noMachineLabel.setText("No machine present...");// TODO internationalize?
94                 addSimulationControlWidgets(parent);
95                 canvasParent = new Composite(parent, SWT.NONE);
96                 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
97                 canvasParent.setLayout(new FillLayout());
98                 addInstructionPreviewControlWidgets(parent);
99                 recreateContextDependentControls();
100         }
101
102         private void recreateContextDependentControls()
103         {
104                 if (parent == null)
105                         // createPartControls has not been called yet
106                         return;
107
108                 double offX;
109                 double offY;
110                 double zoom;
111                 stopExecAndDeregisterContextDependentListeners();
112                 if (canvas != null)
113                 {
114                         offX = canvas.getOffX();
115                         offY = canvas.getOffY();
116                         zoom = canvas.getZoom();
117                         canvas.dispose();
118                 } else
119                 {
120                         offX = 0;
121                         offY = 0;
122                         zoom = -1;
123                 }
124
125                 Optional<Machine> machineOptional;
126                 if (context != null && (machineOptional = context.getActiveMachine()).isPresent())
127                 {
128                         noMachineLabel.setVisible(false);
129                         resetButton.setEnabled(true);
130                         sbseButton.setEnabled(true);
131                         pauseButton.setEnabled(true);
132                         simSpeedSlider.setEnabled(true);
133
134                         machine = machineOptional.get();
135                         canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
136                         ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
137                         userInput.buttonDrag = 3;
138                         userInput.buttonZoom = 2;
139                         userInput.enableUserInput();
140                         if (zoom > 0)
141                         {
142                                 canvas.moveTo(offX, offY, zoom);
143                                 canvas.commitTransform();
144                         }
145
146                         AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
147                         instPreview.bindMicroInstructionMemory(mIMemory);
148                         mIMemory.registerCellModifiedListener(memCellListener);
149
150                         canvasParent.layout();
151
152                         // initialize executer
153                         exec = new LogicExecuter(machine.getTimeline());
154                         exec.startLiveExecution();
155                 } else
156                 {
157                         noMachineLabel.setVisible(true);
158                         resetButton.setEnabled(false);
159                         sbseButton.setEnabled(false);
160                         pauseButton.setEnabled(false);
161                         simSpeedSlider.setEnabled(false);
162                 }
163         }
164
165         private void stopExecAndDeregisterContextDependentListeners()
166         {
167                 if (exec != null)
168                         exec.stopLiveExecution();
169                 if (machine != null)
170                 {
171                         machine.getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
172                         machine.getClock().deregisterObserver(clockObserver);
173                 }
174         }
175
176         private void addSimulationControlWidgets(Composite parent)
177         {
178                 Composite c = new Composite(parent, SWT.NONE);
179                 c.setLayout(new GridLayout(7, false));
180
181                 resetButton = new Button(c, SWT.PUSH);
182                 resetButton.setText("Reset machine");
183                 resetButton.addListener(SWT.Selection, e -> context.getActiveMachine().get().reset());
184
185                 sbseButton = new Button(c, SWT.CHECK);
186                 pauseButton = new Button(c, SWT.TOGGLE);
187
188                 sbseButton.setText("Step by step execution");
189                 sbseButton.addListener(SWT.Selection, e ->
190                 {
191                         CoreClock cl = machine.getClock();
192                         if (sbseButton.getSelection())
193                                 cl.registerObserver(clockObserver);
194                         else
195                                 cl.deregisterObserver(clockObserver);
196                 });
197                 sbseButton.setSelection(false);
198
199                 pauseButton.setSelection(true);
200                 setPauseText(pauseButton, false);
201
202                 pauseButton.addListener(SWT.Selection, e ->
203                 {
204                         setPauseText(pauseButton, false);
205                         if (pauseButton.getSelection())
206                         {
207                                 exec.unpauseLiveExecution();
208                         } else
209                         {
210                                 exec.pauseLiveExecution();
211                         }
212                 });
213                 pauseButton.addMouseTrackListener(new MouseTrackListener()
214                 {
215                         @Override
216                         public void mouseHover(MouseEvent e)
217                         {
218                                 // nothing
219                         }
220
221                         @Override
222                         public void mouseExit(MouseEvent e)
223                         {
224                                 setPauseText(pauseButton, false);
225                         }
226
227                         @Override
228                         public void mouseEnter(MouseEvent e)
229                         {
230                                 setPauseText(pauseButton, true);
231                         }
232                 });
233
234                 Label speedLabel = new Label(c, SWT.NONE);
235                 speedLabel.setText("Simulation Speed: ");
236
237                 simSpeedSlider = new Slider(c, SWT.NONE);
238                 simSpeedSlider.setMinimum(1);
239                 simSpeedSlider.setMaximum(100 + simSpeedSlider.getThumb());
240                 simSpeedSlider.setIncrement(1);
241
242                 Label speedPercentageLabel = new Label(c, SWT.NONE);
243                 speedPercentageLabel.setText("100%");
244
245                 simSpeedSlider.addListener(SWT.Selection, e ->
246                 {
247                         int selection = simSpeedSlider.getSelection();
248                         speedPercentageLabel.setText(selection + "%");
249
250                         exec.setSpeedPercentage(simSpeedSlider.getSelection());
251                 });
252                 simSpeedSlider.setSelection(100);
253
254                 c.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL_HORIZONTAL));
255                 c.pack();
256         }
257
258         private void addInstructionPreviewControlWidgets(Composite parent)
259         {
260                 instPreview = new InstructionTable(parent, new DisplaySettings());
261                 instPreview.getTableViewer().getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
262                 instPreview.setContentProvider(new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer()));
263         }
264
265         private static void setPauseText(Button pauseButton, boolean hovered)
266         {
267                 if (hovered)
268                         if (pauseButton.getSelection())
269                                 pauseButton.setText("Pause?");
270                         else
271                                 pauseButton.setText("Resume?");
272                 else if (pauseButton.getSelection())
273                         pauseButton.setText("Running");
274                 else
275                         pauseButton.setText("Paused");
276         }
277
278         @Override
279         public void init(IEditorSite site, IEditorInput input) throws PartInitException
280         {
281                 if (input instanceof IFileEditorInput)
282                 {
283                         IFileEditorInput fileInput = (IFileEditorInput) input;
284                         context = ProjectMachineContext.getMachineContextOf(fileInput.getFile().getProject());
285                         context.activateMachine();
286                         context.addActiveMachineListener(activeMNachineListener);
287                         recreateContextDependentControls();
288
289                         setPartName(fileInput.getName());
290                         open(fileInput.getFile());
291                 } else
292                         throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
293
294                 setSite(site);
295                 setInput(input);
296         }
297
298         @Override
299         public void doSave(IProgressMonitor monitor)
300         {
301                 IEditorInput input = getEditorInput();
302                 if (input instanceof IFileEditorInput)
303                         SafeRunnable.getRunner().run(() -> save(((IFileEditorInput) input).getFile(), monitor));
304                 else
305                         throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
306         }
307
308         private void save(IFile file, IProgressMonitor monitor) throws CoreException
309         {
310                 file.setContents(new ByteArrayInputStream("actual contents will go here".getBytes()), 0, monitor);
311         }
312
313         private void open(IFile file)
314         {
315                 // do nothing yet
316         }
317
318         @Override
319         public void doSaveAs()
320         {
321                 throw new UnsupportedOperationException();
322         }
323
324         @Override
325         public boolean isDirty()
326         {
327                 return false;
328         }
329
330         @Override
331         public boolean isSaveAsAllowed()
332         {
333                 return false;
334         }
335
336         @Override
337         public void setFocus()
338         {
339                 canvas.setFocus();
340         }
341
342         @Override
343         public void dispose()
344         {
345                 stopExecAndDeregisterContextDependentListeners();
346                 context.removeActiveMachineListener(activeMNachineListener);
347                 super.dispose();
348         }
349 }