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