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