1 package net.mograsim.plugin.editors;
3 import java.io.ByteArrayInputStream;
4 import java.util.Optional;
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.Scale;
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;
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.MachineContext.ActiveMachineListener;
37 import net.mograsim.plugin.nature.ProjectMachineContext;
38 import net.mograsim.plugin.tables.DisplaySettings;
39 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
40 import net.mograsim.plugin.tables.mi.InstructionTable;
41 import net.mograsim.preferences.Preferences;
43 //TODO what if we open multiple editors?
44 //TODO actually save / load register and latch states
45 public class SimulationViewEditor extends EditorPart
47 private MachineContext context;
49 private LogicExecuter exec;
50 private Machine machine;
52 private Composite parent;
53 private Button resetButton;
54 private Button sbseButton;
55 private Button pauseButton;
56 private Label speedFactorLabel;
57 private Scale simSpeedScale;
58 private Composite canvasParent;
59 private LogicUICanvas canvas;
60 private InstructionTable instPreview;
61 private Label noMachineLabel;
63 private ActiveMachineListener activeMachineListener;
64 private MemoryCellModifiedListener memCellListener;
65 private LogicObserver clockObserver;
67 public SimulationViewEditor()
69 activeMachineListener = m -> recreateContextDependentControls();
70 memCellListener = a -> instPreview.refresh();
73 if (((CoreClock) o).isOn())
75 exec.pauseLiveExecution();
76 if (!pauseButton.isDisposed())
77 Display.getDefault().asyncExec(() ->
79 if (!pauseButton.isDisposed())
80 pauseButton.setSelection(false);
81 setPauseText(pauseButton, false);
88 public void createPartControl(Composite parent)
92 parent.setLayout(new GridLayout());
94 noMachineLabel = new Label(parent, SWT.NONE);
95 noMachineLabel.setText("No machine present...");// TODO internationalize?
96 addSimulationControlWidgets(parent);
97 canvasParent = new Composite(parent, SWT.NONE);
98 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
99 canvasParent.setLayout(new FillLayout());
100 addInstructionPreviewControlWidgets(parent);
101 recreateContextDependentControls();
104 private void recreateContextDependentControls()
107 // createPartControls has not been called yet
113 stopExecAndDeregisterContextDependentListeners();
116 offX = canvas.getOffX();
117 offY = canvas.getOffY();
118 zoom = canvas.getZoom();
127 Optional<Machine> machineOptional;
128 if (context != null && (machineOptional = context.getActiveMachine()).isPresent())
130 noMachineLabel.setVisible(false);
131 resetButton.setEnabled(true);
132 sbseButton.setEnabled(true);
133 pauseButton.setEnabled(true);
134 simSpeedScale.setEnabled(true);
136 machine = machineOptional.get();
137 canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
138 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
139 userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
140 userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
141 userInput.enableUserInput();
144 canvas.moveTo(offX, offY, zoom);
145 canvas.commitTransform();
148 AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
149 instPreview.bindMicroInstructionMemory(mIMemory);
150 mIMemory.registerCellModifiedListener(memCellListener);
152 canvasParent.layout();
154 // initialize executer
155 exec = new LogicExecuter(machine.getTimeline());
158 exec.startLiveExecution();
161 noMachineLabel.setVisible(true);
162 resetButton.setEnabled(false);
163 sbseButton.setEnabled(false);
164 pauseButton.setEnabled(false);
165 simSpeedScale.setEnabled(false);
169 private void stopExecAndDeregisterContextDependentListeners()
172 exec.stopLiveExecution();
175 machine.getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
176 machine.getClock().deregisterObserver(clockObserver);
180 private void addSimulationControlWidgets(Composite parent)
182 Composite c = new Composite(parent, SWT.NONE);
183 c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
184 c.setLayout(new GridLayout(7, false));
186 resetButton = new Button(c, SWT.PUSH);
187 resetButton.setText("Reset machine");
188 resetButton.addListener(SWT.Selection, e -> context.getActiveMachine().get().reset());
190 sbseButton = new Button(c, SWT.CHECK);
191 pauseButton = new Button(c, SWT.TOGGLE);
193 sbseButton.setText("Step by step execution");
194 sbseButton.addListener(SWT.Selection, e ->
196 CoreClock cl = machine.getClock();
197 if (sbseButton.getSelection())
198 cl.registerObserver(clockObserver);
200 cl.deregisterObserver(clockObserver);
202 sbseButton.setSelection(false);
204 pauseButton.setSelection(true);
205 setPauseText(pauseButton, false);
207 pauseButton.addListener(SWT.Selection, e -> updatePausedState());
208 pauseButton.addMouseTrackListener(new MouseTrackListener()
211 public void mouseHover(MouseEvent e)
217 public void mouseExit(MouseEvent e)
219 setPauseText(pauseButton, false);
223 public void mouseEnter(MouseEvent e)
225 setPauseText(pauseButton, true);
229 new Label(c, SWT.NONE).setText("Simulation Speed: ");
231 simSpeedScale = new Scale(c, SWT.NONE);
232 simSpeedScale.setMinimum(0);
233 simSpeedScale.setMaximum(50);
234 simSpeedScale.setIncrement(1);
235 simSpeedScale.setSelection(0);
237 speedFactorLabel = new Label(c, SWT.NONE);
238 speedFactorLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
240 simSpeedScale.addListener(SWT.Selection, e -> updateSpeedFactor());
246 private void updatePausedState()
248 setPauseText(pauseButton, false);
250 if (pauseButton.getSelection())
251 exec.unpauseLiveExecution();
253 exec.pauseLiveExecution();
256 private void updateSpeedFactor()
258 double factor = Math.pow(1.32, simSpeedScale.getSelection() - 50);
259 speedFactorLabel.setText(String.format("%f", factor));
261 exec.setSpeedFactor(factor);
264 private void addInstructionPreviewControlWidgets(Composite parent)
266 instPreview = new InstructionTable(parent, new DisplaySettings());
267 instPreview.getTableViewer().getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
268 instPreview.setContentProvider(new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer()));
271 private static void setPauseText(Button pauseButton, boolean hovered)
274 if (pauseButton.getSelection())
275 pauseButton.setText("Pause?");
277 pauseButton.setText("Resume?");
278 else if (pauseButton.getSelection())
279 pauseButton.setText("Running");
281 pauseButton.setText("Paused");
285 public void init(IEditorSite site, IEditorInput input) throws PartInitException
287 if (input instanceof IFileEditorInput)
289 IFileEditorInput fileInput = (IFileEditorInput) input;
290 context = ProjectMachineContext.getMachineContextOf(fileInput.getFile().getProject());
291 context.activateMachine();
292 context.addActiveMachineListener(activeMachineListener);
293 recreateContextDependentControls();
295 setPartName(fileInput.getName());
296 open(fileInput.getFile());
298 throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
305 public void doSave(IProgressMonitor monitor)
307 IEditorInput input = getEditorInput();
308 if (input instanceof IFileEditorInput)
309 SafeRunnable.getRunner().run(() -> save(((IFileEditorInput) input).getFile(), monitor));
311 throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
314 private void save(IFile file, IProgressMonitor monitor) throws CoreException
316 file.setContents(new ByteArrayInputStream("actual contents will go here".getBytes()), 0, monitor);
319 private void open(IFile file)
325 public void doSaveAs()
327 throw new UnsupportedOperationException();
331 public boolean isDirty()
337 public boolean isSaveAsAllowed()
343 public void setFocus()
349 public void dispose()
351 stopExecAndDeregisterContextDependentListeners();
352 context.removeActiveMachineListener(activeMachineListener);