--- /dev/null
+package era.mi.gui;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import era.mi.logic.timeline.Timeline;
+
+public class LogicExecuter
+{
+ // TODO replace with LogicModel when it exists
+ private final Timeline timeline;
+
+ private final AtomicBoolean shouldBeRunningLive;
+ private final AtomicBoolean isRunningLive;
+ private final AtomicLong nextExecSimulTime;
+ private final Thread simulationThread;
+
+ public LogicExecuter(Timeline timeline)
+ {
+ this.timeline = timeline;
+
+ timeline.setTimeFunction(System::currentTimeMillis);
+ shouldBeRunningLive = new AtomicBoolean();
+ isRunningLive = new AtomicBoolean();
+ nextExecSimulTime = new AtomicLong();
+ simulationThread = new Thread(() ->
+ {
+ isRunningLive.set(true);
+ while (shouldBeRunningLive.get())
+ {
+ // always execute to keep timeline from "hanging behind" for too long
+ long current = System.currentTimeMillis();
+ timeline.executeUntil(timeline.laterThan(current), current + 10);
+ long sleepTime;
+ if (timeline.hasNext())
+ sleepTime = timeline.nextEventTime() - current;
+ else
+ sleepTime = 10000;
+ try
+ {
+ nextExecSimulTime.set(current + sleepTime);
+ if (sleepTime > 0)
+ Thread.sleep(sleepTime);
+ }
+ catch (InterruptedException e)
+ {// do nothing; it is normal execution flow to be interrupted
+ }
+ }
+ isRunningLive.set(false);
+ });
+ timeline.addEventAddedListener(event ->
+ {
+ if (isRunningLive.get())
+ if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
+ simulationThread.interrupt();
+ });
+ }
+
+ public void executeNextStep()
+ {
+ timeline.executeNext();
+ }
+
+ public synchronized void startLiveExecution()
+ {
+ if (shouldBeRunningLive.get())
+ return;
+ shouldBeRunningLive.set(true);
+ simulationThread.start();
+ while (!isRunningLive.get())
+ ;
+ }
+
+ public synchronized void stopLiveExecution()
+ {
+ if (!shouldBeRunningLive.get())
+ return;
+ shouldBeRunningLive.set(false);
+ simulationThread.interrupt();
+ while (isRunningLive.get())
+ ;
+ }
+}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui;\r
-\r
-import java.util.concurrent.atomic.AtomicBoolean;\r
-\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.layout.FillLayout;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Shell;\r
-\r
-import era.mi.gui.model.ViewModel;\r
-import era.mi.gui.modeladapter.LogicModelParameters;\r
-import era.mi.gui.modeladapter.ViewLogicModelAdapter;\r
-import era.mi.logic.timeline.Timeline;\r
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;\r
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;\r
-\r
-/**\r
- * Standalone simulation visualizer.\r
- * \r
- * @author Daniel Kirschten\r
- */\r
-public class LogicUIStandalone\r
-{\r
- private ViewModel model;\r
- private Timeline timeline;\r
-\r
- private final Display display;\r
- private final Shell shell;\r
- private final LogicUICanvas ui;\r
-\r
- public LogicUIStandalone(ViewModel model)\r
- {\r
- this.model = model;\r
- display = new Display();\r
- shell = new Shell(display);\r
- shell.setLayout(new FillLayout());\r
- ui = new LogicUICanvas(shell, SWT.NONE, model);\r
-\r
- ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);\r
- userInput.buttonDrag = 3;\r
- userInput.buttonZoom = 2;\r
- userInput.enableUserInput();\r
- new ZoomableCanvasOverlay(ui, null).enableScale();\r
-\r
- // TODO don't do this here\r
- LogicModelParameters params = new LogicModelParameters();\r
- params.gateProcessTime = 50;\r
- params.wireTravelTime = 10;\r
- timeline = ViewLogicModelAdapter.convert(model, params);\r
- }\r
-\r
- public LogicUICanvas getLogicUICanvas()\r
- {\r
- return ui;\r
- }\r
-\r
- /**\r
- * Start the simulation timeline, and open the UI shell. Returns when the shell is closed.\r
- */\r
- public void run()\r
- {\r
- AtomicBoolean running = new AtomicBoolean(true);\r
- Thread simulationThread = new Thread(() ->\r
- {\r
- while (running.get())\r
- {\r
- // always execute to keep timeline from "hanging behind" for too long\r
- timeline.executeUntil(timeline.laterThan(System.currentTimeMillis()), System.currentTimeMillis() + 10);\r
- long sleepTime;\r
- if (timeline.hasNext())\r
- sleepTime = timeline.nextEventTime() - System.currentTimeMillis();\r
- else\r
- sleepTime = 10;\r
- try\r
- {\r
- if (sleepTime > 0)\r
- Thread.sleep(sleepTime);\r
- }\r
- catch (InterruptedException e)\r
- {\r
- } // it is normal execution flow to be interrupted\r
- }\r
- });\r
- simulationThread.start();\r
- timeline.addEventAddedListener(event ->\r
- {\r
- if (event.getTiming() <= System.currentTimeMillis())\r
- simulationThread.interrupt();\r
- });\r
-\r
- shell.open();\r
- while (!shell.isDisposed())\r
- if (!display.readAndDispatch())\r
- display.sleep();\r
- running.set(false);\r
-// simulationThread.interrupt();\r
- }\r
-}
\ No newline at end of file
--- /dev/null
+package era.mi.gui;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import era.mi.gui.model.ViewModel;
+import era.mi.gui.modeladapter.LogicModelParameters;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
+
+/**
+ * Standalone simulation visualizer graphical user interface.
+ *
+ * @author Daniel Kirschten
+ */
+public class LogicUIStandaloneGUI
+{
+ private final Display display;
+ private final Shell shell;
+ private final LogicUICanvas ui;
+
+ public LogicUIStandaloneGUI(ViewModel model)
+ {
+ display = new Display();
+ shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+ ui = new LogicUICanvas(shell, SWT.NONE, model);
+
+ ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
+ userInput.buttonDrag = 3;
+ userInput.buttonZoom = 2;
+ userInput.enableUserInput();
+ new ZoomableCanvasOverlay(ui, null).enableScale();
+
+ // TODO don't do this here
+ LogicModelParameters params = new LogicModelParameters();
+ params.gateProcessTime = 50;
+ params.wireTravelTime = 10;
+// timeline = ViewLogicModelAdapter.convert(model, params);
+ }
+
+ public LogicUICanvas getLogicUICanvas()
+ {
+ return ui;
+ }
+
+ /**
+ * Opens the UI shell. Returns when the shell is closed.
+ */
+ public void run()
+ {
+ shell.open();
+ while (!shell.isDisposed())
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+}
\ No newline at end of file
--- /dev/null
+package era.mi.gui;
+
+import java.util.function.Consumer;
+
+import era.mi.gui.model.ViewModel;
+import era.mi.gui.modeladapter.LogicModelParameters;
+import era.mi.gui.modeladapter.ViewLogicModelAdapter;
+import era.mi.logic.timeline.Timeline;
+
+public class SimpleLogicUIStandalone
+{
+ public static void executeVisualisation(Consumer<ViewModel> setupViewModel)
+ {
+ // setup view model
+ ViewModel viewModel = new ViewModel();
+ setupViewModel.accept(viewModel);
+
+ // convert to logic model
+ LogicModelParameters params = new LogicModelParameters();
+ params.gateProcessTime = 50;
+ params.wireTravelTime = 10;
+ Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
+
+ // initialize UI and executer
+ LogicUIStandaloneGUI ui = new LogicUIStandaloneGUI(viewModel);
+ LogicExecuter exec = new LogicExecuter(timeline);
+
+ // run it
+ exec.startLiveExecution();
+ ui.run();
+ exec.stopLiveExecution();
+ }
+
+ private SimpleLogicUIStandalone()
+ {
+ throw new UnsupportedOperationException("No SimpleLogicUIStandalone instances");
+ }
+}
\ No newline at end of file
+++ /dev/null
-package era.mi.gui.examples;
-
-import era.mi.gui.LogicUIStandalone;
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.components.GUIAndGate;
-import era.mi.gui.model.components.GUIManualSwitch;
-import era.mi.gui.model.components.GUINotGate;
-import era.mi.gui.model.components.GUIOrGate;
-import era.mi.gui.model.wires.GUIWire;
-import era.mi.gui.model.wires.WireCrossPoint;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-
-public class Playground
-{
- public static void main(String[] args)
- {
- ViewModel model = new ViewModel();
- createRSLatchExample(model);
- LogicUIStandalone ui = new LogicUIStandalone(model);
- ui.run();
- }
-
- private static void createRSLatchExample(ViewModel model)
- {
- GUIManualSwitch rIn = new GUIManualSwitch(model);
- rIn.moveTo(100, 100);
- GUIManualSwitch sIn = new GUIManualSwitch(model);
- sIn.moveTo(100, 200);
-
- GUIOrGate or1 = new GUIOrGate(model, 1);
- or1.moveTo(160, 102.5);
- new GUIWire(model, rIn.getOutputPin(), or1.getInputPins().get(0));
-
- GUIOrGate or2 = new GUIOrGate(model, 1);
- or2.moveTo(160, 192.5);
- new GUIWire(model, sIn.getOutputPin(), or2.getInputPins().get(1));
-
- GUINotGate not1 = new GUINotGate(model, 1);
- not1.moveTo(200, 107.5);
- new GUIWire(model, or1.getOutputPin(), not1.getInputPins().get(0));
-
- GUINotGate not2 = new GUINotGate(model, 1);
- not2.moveTo(200, 197.5);
- new GUIWire(model, or2.getOutputPin(), not2.getInputPins().get(0));
-
- WireCrossPoint p1 = new WireCrossPoint(model, 1);
- p1.moveTo(250, 112.5);
- new GUIWire(model, not1.getOutputPin(), p1.getPin());
- new GUIWire(model, p1.getPin(), or2.getInputPins().get(0), new Point(250, 130), new Point(140, 185), new Point(140, 197.5));
-
- WireCrossPoint p2 = new WireCrossPoint(model, 1);
- p2.moveTo(250, 202.5);
- new GUIWire(model, not2.getOutputPin(), p2.getPin());
- new GUIWire(model, p2.getPin(), or1.getInputPins().get(1), new Point(250, 185), new Point(140, 130), new Point(140, 117.5));
-
- WireCrossPoint o1 = new WireCrossPoint(model, 1);
- o1.moveTo(270, 112.5);
- new GUIWire(model, p1.getPin(), o1.getPin());
-
- WireCrossPoint o2 = new WireCrossPoint(model, 1);
- o2.moveTo(270, 202.5);
- new GUIWire(model, p2.getPin(), o2.getPin());
- }
-
- @SuppressWarnings("unused")
- private static void createBasicExample(ViewModel model)
- {
- GUIAndGate andGate = new GUIAndGate(model, 1);
- andGate.moveTo(10, 10);
- GUINotGate notGate = new GUINotGate(model, 1);
- notGate.moveTo(10, 40);
-
- WireCrossPoint wcp1 = new WireCrossPoint(model, 1);
- wcp1.moveTo(150, 10);
-
- new GUIWire(model, andGate.getOutputPin(), notGate.getInputPins().get(0), new Point(60, 50));
- new GUIWire(model, notGate.getOutputPin(), wcp1.getPin());
-
- GUIManualSwitch sw1 = new GUIManualSwitch(model);
- sw1.moveTo(-20, 0);
- GUIManualSwitch sw2 = new GUIManualSwitch(model);
- sw2.moveTo(-20, 50);
-
- new GUIWire(model, sw1.getOutputPin(), andGate.getInputPins().get(0));
- new GUIWire(model, sw2.getOutputPin(), andGate.getInputPins().get(1));
- }
-}
\ No newline at end of file
--- /dev/null
+package era.mi.gui.examples;
+
+import era.mi.gui.SimpleLogicUIStandalone;
+import era.mi.gui.model.ViewModel;
+import era.mi.gui.model.components.GUIManualSwitch;
+import era.mi.gui.model.components.GUINotGate;
+import era.mi.gui.model.components.GUIOrGate;
+import era.mi.gui.model.wires.GUIWire;
+import era.mi.gui.model.wires.WireCrossPoint;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+
+public class RSLatchExample
+{
+ public static void main(String[] args)
+ {
+ SimpleLogicUIStandalone.executeVisualisation(RSLatchExample::createRSLatchExample);
+ }
+
+ private static void createRSLatchExample(ViewModel model)
+ {
+ GUIManualSwitch rIn = new GUIManualSwitch(model);
+ rIn.moveTo(100, 100);
+ GUIManualSwitch sIn = new GUIManualSwitch(model);
+ sIn.moveTo(100, 200);
+
+ GUIOrGate or1 = new GUIOrGate(model, 1);
+ or1.moveTo(160, 102.5);
+ new GUIWire(model, rIn.getOutputPin(), or1.getInputPins().get(0));
+
+ GUIOrGate or2 = new GUIOrGate(model, 1);
+ or2.moveTo(160, 192.5);
+ new GUIWire(model, sIn.getOutputPin(), or2.getInputPins().get(1));
+
+ GUINotGate not1 = new GUINotGate(model, 1);
+ not1.moveTo(200, 107.5);
+ new GUIWire(model, or1.getOutputPin(), not1.getInputPins().get(0));
+
+ GUINotGate not2 = new GUINotGate(model, 1);
+ not2.moveTo(200, 197.5);
+ new GUIWire(model, or2.getOutputPin(), not2.getInputPins().get(0));
+
+ WireCrossPoint p1 = new WireCrossPoint(model, 1);
+ p1.moveTo(250, 112.5);
+ new GUIWire(model, not1.getOutputPin(), p1.getPin());
+ new GUIWire(model, p1.getPin(), or2.getInputPins().get(0), new Point(250, 130), new Point(140, 185), new Point(140, 197.5));
+
+ WireCrossPoint p2 = new WireCrossPoint(model, 1);
+ p2.moveTo(250, 202.5);
+ new GUIWire(model, not2.getOutputPin(), p2.getPin());
+ new GUIWire(model, p2.getPin(), or1.getInputPins().get(1), new Point(250, 185), new Point(140, 130), new Point(140, 117.5));
+
+ WireCrossPoint o1 = new WireCrossPoint(model, 1);
+ o1.moveTo(270, 112.5);
+ new GUIWire(model, p1.getPin(), o1.getPin());
+
+ WireCrossPoint o2 = new WireCrossPoint(model, 1);
+ o2.moveTo(270, 202.5);
+ new GUIWire(model, p2.getPin(), o2.getPin());
+ }
+}
\ No newline at end of file
@Override
public boolean clicked(double x, double y)
{
- logicSwitch.toggle();
+ if (logicSwitch != null)
+ logicSwitch.toggle();
return true;
}