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