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.logic.model.serializing.IndirectModelComponentCreator;
34 import net.mograsim.machine.Machine;
35 import net.mograsim.machine.Memory.MemoryCellModifiedListener;
36 import net.mograsim.machine.mi.AssignableMicroInstructionMemory;
37 import net.mograsim.plugin.nature.MachineContext;
38 import net.mograsim.plugin.nature.MachineContext.ActiveMachineListener;
39 import net.mograsim.plugin.nature.ProjectMachineContext;
40 import net.mograsim.plugin.tables.DisplaySettings;
41 import net.mograsim.plugin.tables.mi.ActiveInstructionPreviewContentProvider;
42 import net.mograsim.plugin.tables.mi.InstructionTable;
43 import net.mograsim.preferences.Preferences;
45 //TODO what if we open multiple editors?
46 //TODO actually save / load register and latch states
47 public class SimulationViewEditor extends EditorPart
49 private static final int SIM_SPEED_SCALE_STEPS = 50;
50 private static final double SIM_SPEED_SCALE_STEP_FACTOR = 1.32;
51 private static final double SIM_SPEED_SCALE_STEP_FACTOR_LOG = Math.log(SIM_SPEED_SCALE_STEP_FACTOR);
53 private MachineContext context;
55 private LogicExecuter exec;
56 private Machine machine;
58 private Composite parent;
59 private Button resetButton;
60 private Button sbseButton;
61 private Button pauseButton;
62 private Scale simSpeedScale;
63 private DoubleInput simSpeedInput;
64 private Composite canvasParent;
65 private LogicUICanvas canvas;
66 private InstructionTable instPreview;
67 private Label noMachineLabel;
69 private ActiveMachineListener activeMachineListener;
70 private MemoryCellModifiedListener memCellListener;
71 private LogicObserver clockObserver;
73 public SimulationViewEditor()
75 activeMachineListener = (oldM, newM) -> recreateContextDependentControls();
76 memCellListener = a -> instPreview.refresh();
79 if (((CoreClock) o).isOn())
81 exec.pauseLiveExecution();
82 if (!pauseButton.isDisposed())
83 Display.getDefault().asyncExec(() ->
85 if (!pauseButton.isDisposed())
86 pauseButton.setSelection(false);
87 setPauseText(pauseButton, false);
94 public void createPartControl(Composite parent)
98 parent.setLayout(new GridLayout());
100 noMachineLabel = new Label(parent, SWT.NONE);
101 noMachineLabel.setText("No machine present...");// TODO internationalize?
102 addSimulationControlWidgets(parent);
103 canvasParent = new Composite(parent, SWT.NONE);
104 canvasParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
105 canvasParent.setLayout(new FillLayout());
106 addInstructionPreviewControlWidgets(parent);
107 recreateContextDependentControls();
110 private void recreateContextDependentControls()
113 // createPartControls has not been called yet
119 stopExecAndDeregisterContextDependentListeners();
122 offX = canvas.getOffX();
123 offY = canvas.getOffY();
124 zoom = canvas.getZoom();
133 Optional<Machine> machineOptional;
134 if (context != null && (machineOptional = context.getActiveMachine()).isPresent())
136 noMachineLabel.setVisible(false);
137 resetButton.setEnabled(true);
138 sbseButton.setEnabled(true);
139 pauseButton.setEnabled(true);
140 simSpeedScale.setEnabled(true);
141 simSpeedInput.setEnabled(true);
143 machine = machineOptional.get();
144 canvas = new LogicUICanvas(canvasParent, SWT.NONE, machine.getModel());
145 canvas.addListener(SWT.MouseDown, e -> canvas.setFocus());
146 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas);
147 userInput.buttonDrag = Preferences.current().getInt("net.mograsim.logic.model.button.drag");
148 userInput.buttonZoom = Preferences.current().getInt("net.mograsim.logic.model.button.zoom");
149 userInput.enableUserInput();
152 canvas.moveTo(offX, offY, zoom);
153 canvas.commitTransform();
156 AssignableMicroInstructionMemory mIMemory = machine.getMicroInstructionMemory();
157 instPreview.bindMicroInstructionMemory(mIMemory);
158 mIMemory.registerCellModifiedListener(memCellListener);
160 canvasParent.layout();
163 ((ActiveInstructionPreviewContentProvider) instPreview.getTableViewer().getContentProvider()).setMachine(machine);
165 // initialize executer
166 exec = new LogicExecuter(machine.getTimeline());
167 updateSpeedFactorFromInput(simSpeedInput.getValue());
169 exec.startLiveExecution();
172 noMachineLabel.setVisible(true);
173 resetButton.setEnabled(false);
174 sbseButton.setEnabled(false);
175 pauseButton.setEnabled(false);
176 simSpeedScale.setEnabled(false);
177 simSpeedInput.setEnabled(false);
181 private void stopExecAndDeregisterContextDependentListeners()
184 exec.stopLiveExecution();
187 machine.getMicroInstructionMemory().deregisterCellModifiedListener(memCellListener);
188 machine.getClock().deregisterObserver(clockObserver);
192 private void addSimulationControlWidgets(Composite parent)
194 Composite c = new Composite(parent, SWT.NONE);
195 c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
196 c.setLayout(new GridLayout(7, false));
198 resetButton = new Button(c, SWT.PUSH);
199 resetButton.setText("Reset machine");
200 resetButton.addListener(SWT.Selection, e -> context.getActiveMachine().get().reset());
202 // TODO do we want this button in the final product?
203 Button reloadMachineButton = new Button(c, SWT.PUSH);
204 reloadMachineButton.setText("Reload machine");
205 reloadMachineButton.addListener(SWT.Selection, e ->
207 IndirectModelComponentCreator.clearComponentCache();
208 context.setActiveMachine(context.getMachineDefinition().get().createNew());
211 sbseButton = new Button(c, SWT.CHECK);
212 pauseButton = new Button(c, SWT.TOGGLE);
214 sbseButton.setText("Step by step execution");
215 sbseButton.addListener(SWT.Selection, e ->
217 CoreClock cl = machine.getClock();
218 if (sbseButton.getSelection())
219 cl.registerObserver(clockObserver);
221 cl.deregisterObserver(clockObserver);
223 sbseButton.setSelection(false);
225 pauseButton.setSelection(true);
226 setPauseText(pauseButton, false);
228 pauseButton.addListener(SWT.Selection, e -> updatePausedState());
229 pauseButton.addMouseTrackListener(new MouseTrackListener()
232 public void mouseHover(MouseEvent e)
238 public void mouseExit(MouseEvent e)
240 setPauseText(pauseButton, false);
244 public void mouseEnter(MouseEvent e)
246 setPauseText(pauseButton, true);
250 new Label(c, SWT.NONE).setText("Simulation Speed: ");
252 simSpeedScale = new Scale(c, SWT.NONE);
253 simSpeedScale.setMinimum(0);
254 simSpeedScale.setMaximum(SIM_SPEED_SCALE_STEPS);
255 simSpeedScale.setIncrement(1);
256 simSpeedScale.setSelection(0);
257 simSpeedScale.addListener(SWT.Selection, e -> updateSpeedFactorFromScale());
259 simSpeedInput = new DoubleInput(c, SWT.NONE);
260 simSpeedInput.setPrecision(Preferences.current().getInt("net.mograsim.plugin.core.simspeedprecision"));
261 simSpeedInput.addChangeListener(this::updateSpeedFactorFromInput);
263 updateSpeedFactorFromScale();
268 private void updatePausedState()
270 setPauseText(pauseButton, false);
272 if (pauseButton.getSelection())
273 exec.unpauseLiveExecution();
275 exec.pauseLiveExecution();
278 private void updateSpeedFactorFromScale()
280 double factor = Math.pow(SIM_SPEED_SCALE_STEP_FACTOR, simSpeedScale.getSelection() - SIM_SPEED_SCALE_STEPS);
281 simSpeedInput.setValue(factor);
283 exec.setSpeedFactor(factor);
286 private void updateSpeedFactorFromInput(double factor)
288 double factorCheckedFor0;
290 factorCheckedFor0 = factor;
293 factorCheckedFor0 = Math.pow(10, -simSpeedInput.getPrecision());
294 simSpeedInput.setValue(factorCheckedFor0);
296 int closestScalePos = (int) Math.round(Math.log(factorCheckedFor0) / SIM_SPEED_SCALE_STEP_FACTOR_LOG + SIM_SPEED_SCALE_STEPS);
297 simSpeedScale.setSelection(Math.min(Math.max(closestScalePos, 0), SIM_SPEED_SCALE_STEPS));
299 exec.setSpeedFactor(factorCheckedFor0);
302 private void addInstructionPreviewControlWidgets(Composite parent)
304 instPreview = new InstructionTable(parent, new DisplaySettings(), getSite().getWorkbenchWindow().getWorkbench().getThemeManager());
305 instPreview.getTableViewer().getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
306 ActiveInstructionPreviewContentProvider cProv;
307 instPreview.setContentProvider(cProv = new ActiveInstructionPreviewContentProvider(instPreview.getTableViewer()));
308 cProv.setMachine(machine);
311 private static void setPauseText(Button pauseButton, boolean hovered)
314 if (pauseButton.getSelection())
315 pauseButton.setText("Pause?");
317 pauseButton.setText("Resume?");
318 else if (pauseButton.getSelection())
319 pauseButton.setText("Running");
321 pauseButton.setText("Paused");
325 public void init(IEditorSite site, IEditorInput input) throws PartInitException
327 if (input instanceof IFileEditorInput)
329 IFileEditorInput fileInput = (IFileEditorInput) input;
330 context = ProjectMachineContext.getMachineContextOf(fileInput.getFile().getProject());
331 context.activateMachine();
332 context.addActiveMachineListener(activeMachineListener);
333 recreateContextDependentControls();
335 setPartName(fileInput.getName());
336 open(fileInput.getFile());
338 throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
345 public void doSave(IProgressMonitor monitor)
347 IEditorInput input = getEditorInput();
348 if (input instanceof IFileEditorInput)
349 SafeRunnable.getRunner().run(() -> save(((IFileEditorInput) input).getFile(), monitor));
351 throw new IllegalArgumentException("SimulationViewEditor can only be used with Files");
354 private void save(IFile file, IProgressMonitor monitor) throws CoreException
356 file.setContents(new ByteArrayInputStream("actual contents will go here".getBytes()), 0, monitor);
359 private void open(IFile file)
365 public void doSaveAs()
367 throw new UnsupportedOperationException();
371 public boolean isDirty()
377 public boolean isSaveAsAllowed()
383 public void setFocus()
389 public void dispose()
391 stopExecAndDeregisterContextDependentListeners();
392 context.removeActiveMachineListener(activeMachineListener);