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.input.DoubleInput;
28 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
29 import net.mograsim.logic.core.LogicObserver;
30 import net.mograsim.logic.core.components.CoreClock;
31 import net.mograsim.logic.model.LogicExecuter;
32 import net.mograsim.logic.model.LogicUICanvas;
33 import net.mograsim.machine.Machine;
34 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
35 import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
36 import net.mograsim.plugin.nature.MachineContext;
37 import net.mograsim.plugin.nature.MachineContext.ActiveMachineListener;
38 import net.mograsim.plugin.nature.ProjectMachineContext;
39 import net.mograsim.plugin.tables.DisplaySettings;
40 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
41 import net.mograsim.plugin.tables.mi.InstructionTable;
42 import net.mograsim.preferences.Preferences;
44 //TODO what if we open multiple editors?
45 //TODO actually save / load register and latch states
46 public class SimulationViewEditor extends EditorPart
48 private static final int SIM_SPEED_SCALE_STEPS = 50;
49 private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
50 private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
52 private MachineContext context;
54 private LogicExecuter exec;
55 private Machine machine;
57 private Composite parent;
58 private Button resetButton;
59 private Button sbseButton;
60 private Button pauseButton;
61 private Scale simSpeedScale;
62 private DoubleInput simSpeedInput;
63 private Composite canvasParent;
64 private LogicUICanvas canvas;
65 private InstructionTable instPreview;
66 private Label noMachineLabel;
68 private ActiveMachineListener activeMachineListener;
69 private MemoryCellModifiedListener memCellListener;
70 private LogicObserver clockObserver;
72 public SimulationViewEditor()
74 activeMachineListener = m -> recreateContextDependentControls();
75 memCellListener = a -> instPreview.refresh();
78 if (((CoreClock) o).isOn())
80 exec.pauseLiveExecution();
81 if (!pauseButton.isDisposed())
82 Display.getDefault().asyncExec(() ->
84 if (!pauseButton.isDisposed())
85 pauseButton.setSelection(false);
86 setPauseText(pauseButton, false);
93 public void createPartControl(Composite parent)
97 parent.setLayout(new GridLayout());
99 noMachineLabel = new Label(parent, SWT.NONE);
100 noMachineLabel.setText("No machine present...");// TODO internationalize?
101 addSimulationControlWidgets(parent);
102 canvasParent = new Composite(parent, SWT.NONE);
103 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
104 canvasParent.setLayout(new FillLayout());
105 addInstructionPreviewControlWidgets(parent);
106 recreateContextDependentControls();
109 private void recreateContextDependentControls()
112 // createPartControls has not been called yet
118 stopExecAndDeregisterContextDependentListeners();
121 offX = canvas.getOffX();
122 offY = canvas.getOffY();
123 zoom = canvas.getZoom();
132 Optional<Machine> machineOptional;
133 if (context != null && (machineOptional = context.getActiveMachine()).isPresent())
135 noMachineLabel.setVisible(false);
136 resetButton.setEnabled(true);
137 sbseButton.setEnabled(true);
138 pauseButton.setEnabled(true);
139 simSpeedScale.setEnabled(true);
140 simSpeedInput.setEnabled(true);
142 machine = machineOptional.get();
143 canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
144 canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
145 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
146 userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
147 userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
148 userInput.enableUserInput();
151 canvas.moveTo(offX, offY, zoom);
152 canvas.commitTransform();
155 AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
156 instPreview.bindMicroInstructionMemory(mIMemory);
157 mIMemory.registerCellModifiedListener(memCellListener);
159 canvasParent.layout();
161 // initialize executer
162 exec = new LogicExecuter(machine.getTimeline());
163 updateSpeedFactorFromInput(simSpeedInput.getValue());
165 exec.startLiveExecution();
168 noMachineLabel.setVisible(true);
169 resetButton.setEnabled(false);
170 sbseButton.setEnabled(false);
171 pauseButton.setEnabled(false);
172 simSpeedScale.setEnabled(false);
173 simSpeedInput.setEnabled(false);
177 private void stopExecAndDeregisterContextDependentListeners()
180 exec.stopLiveExecution();
183 machine.getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
184 machine.getClock().deregisterObserver(clockObserver);
188 private void addSimulationControlWidgets(Composite parent)
190 Composite c = new Composite(parent, SWT.NONE);
191 c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
192 c.setLayout(new GridLayout(6, false));
194 resetButton = new Button(c, SWT.PUSH);
195 resetButton.setText("Reset machine");
196 resetButton.addListener(SWT.Selection, e -> context.getActiveMachine().get().reset());
198 sbseButton = new Button(c, SWT.CHECK);
199 pauseButton = new Button(c, SWT.TOGGLE);
201 sbseButton.setText("Step by step execution");
202 sbseButton.addListener(SWT.Selection, e ->
204 CoreClock cl = machine.getClock();
205 if (sbseButton.getSelection())
206 cl.registerObserver(clockObserver);
208 cl.deregisterObserver(clockObserver);
210 sbseButton.setSelection(false);
212 pauseButton.setSelection(true);
213 setPauseText(pauseButton, false);
215 pauseButton.addListener(SWT.Selection, e -> updatePausedState());
216 pauseButton.addMouseTrackListener(new MouseTrackListener()
219 public void mouseHover(MouseEvent e)
225 public void mouseExit(MouseEvent e)
227 setPauseText(pauseButton, false);
231 public void mouseEnter(MouseEvent e)
233 setPauseText(pauseButton, true);
237 new Label(c, SWT.NONE).setText("Simulation Speed: ");
239 simSpeedScale = new Scale(c, SWT.NONE);
240 simSpeedScale.setMinimum(0);
241 simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
242 simSpeedScale.setIncrement(1);
243 simSpeedScale.setSelection(0);
244 simSpeedScale.addListener(SWT.Selection, e -> updateSpeedFactorFromScale());
246 simSpeedInput = new DoubleInput(c, SWT.NONE);
247 simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
248 simSpeedInput.addChangeListener(this::updateSpeedFactorFromInput);
250 updateSpeedFactorFromScale();
255 private void updatePausedState()
257 setPauseText(pauseButton, false);
259 if (pauseButton.getSelection())
260 exec.unpauseLiveExecution();
262 exec.pauseLiveExecution();
265 private void updateSpeedFactorFromScale()
267 double factor = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
268 simSpeedInput.setValue(factor);
270 exec.setSpeedFactor(factor);
273 private void updateSpeedFactorFromInput(double factor)
275 double factorCheckedFor0;
277 factorCheckedFor0 = factor;
280 factorCheckedFor0 = Math.pow(10, -simSpeedInput.getPrecision());
281 simSpeedInput.setValue(factorCheckedFor0);
283 int closestScalePos = (int) Math.round(Math.log(factorCheckedFor0) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
284 simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
286 exec.setSpeedFactor(factorCheckedFor0);
289 private void addInstructionPreviewControlWidgets(Composite parent)
291 instPreview = new InstructionTable(parent, new DisplaySettings());
292 instPreview.getTableViewer().getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
293 instPreview.setContentProvider(new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer()));
296 private static void setPauseText(Button pauseButton, boolean hovered)
299 if (pauseButton.getSelection())
300 pauseButton.setText("Pause?");
302 pauseButton.setText("Resume?");
303 else if (pauseButton.getSelection())
304 pauseButton.setText("Running");
306 pauseButton.setText("Paused");
310 public void init(IEditorSite site, IEditorInput input) throws PartInitException
312 if (input instanceof IFileEditorInput)
314 IFileEditorInput fileInput = (IFileEditorInput) input;
315 context = ProjectMachineContext.getMachineContextOf(fileInput.getFile().getProject());
316 context.activateMachine();
317 context.addActiveMachineListener(activeMachineListener);
318 recreateContextDependentControls();
320 setPartName(fileInput.getName());
321 open(fileInput.getFile());
323 throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
330 public void doSave(IProgressMonitor monitor)
332 IEditorInput input = getEditorInput();
333 if (input instanceof IFileEditorInput)
334 SafeRunnable.getRunner().run(() -> save(((IFileEditorInput) input).getFile(), monitor));
336 throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
339 private void save(IFile file, IProgressMonitor monitor) throws CoreException
341 file.setContents(new ByteArrayInputStream("actual contents will go here".getBytes()), 0, monitor);
344 private void open(IFile file)
350 public void doSaveAs()
352 throw new UnsupportedOperationException();
356 public boolean isDirty()
362 public boolean isSaveAsAllowed()
368 public void setFocus()
374 public void dispose()
376 stopExecAndDeregisterContextDependentListeners();
377 context.removeActiveMachineListener(activeMachineListener);