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