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