From: Daniel Kirschten Date: Wed, 29 May 2019 19:49:54 +0000 (+0200) Subject: Class hierarchy cleanup: X-Git-Url: https://mograsim.net/gitweb/?a=commitdiff_plain;ds=sidebyside;h=29cfa7eb267542506beb197e54af8aa3f642c3fb;p=Mograsim.git Class hierarchy cleanup: -Splitted LogicUIStandalone into LogicUIStandaloneGUI and LogicExecuter -Created SimpleLogicUIStandalone -Renamed Playground to RSLatchExample -Removed old example --- diff --git a/LogicUI/src/era/mi/gui/LogicExecuter.java b/LogicUI/src/era/mi/gui/LogicExecuter.java new file mode 100644 index 00000000..d5ffd862 --- /dev/null +++ b/LogicUI/src/era/mi/gui/LogicExecuter.java @@ -0,0 +1,83 @@ +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 diff --git a/LogicUI/src/era/mi/gui/LogicUIStandalone.java b/LogicUI/src/era/mi/gui/LogicUIStandalone.java deleted file mode 100644 index 3312308d..00000000 --- a/LogicUI/src/era/mi/gui/LogicUIStandalone.java +++ /dev/null @@ -1,98 +0,0 @@ -package era.mi.gui; - -import java.util.concurrent.atomic.AtomicBoolean; - -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 era.mi.gui.modeladapter.ViewLogicModelAdapter; -import era.mi.logic.timeline.Timeline; -import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay; -import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput; - -/** - * Standalone simulation visualizer. - * - * @author Daniel Kirschten - */ -public class LogicUIStandalone -{ - private ViewModel model; - private Timeline timeline; - - private final Display display; - private final Shell shell; - private final LogicUICanvas ui; - - public LogicUIStandalone(ViewModel model) - { - this.model = 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; - } - - /** - * Start the simulation timeline, and open the UI shell. Returns when the shell is closed. - */ - public void run() - { - AtomicBoolean running = new AtomicBoolean(true); - Thread simulationThread = new Thread(() -> - { - while (running.get()) - { - // always execute to keep timeline from "hanging behind" for too long - timeline.executeUntil(timeline.laterThan(System.currentTimeMillis()), System.currentTimeMillis() + 10); - long sleepTime; - if (timeline.hasNext()) - sleepTime = timeline.nextEventTime() - System.currentTimeMillis(); - else - sleepTime = 10; - try - { - if (sleepTime > 0) - Thread.sleep(sleepTime); - } - catch (InterruptedException e) - { - } // it is normal execution flow to be interrupted - } - }); - simulationThread.start(); - timeline.addEventAddedListener(event -> - { - if (event.getTiming() <= System.currentTimeMillis()) - simulationThread.interrupt(); - }); - - shell.open(); - while (!shell.isDisposed()) - if (!display.readAndDispatch()) - display.sleep(); - running.set(false); -// simulationThread.interrupt(); - } -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/LogicUIStandaloneGUI.java b/LogicUI/src/era/mi/gui/LogicUIStandaloneGUI.java new file mode 100644 index 00000000..55931cfb --- /dev/null +++ b/LogicUI/src/era/mi/gui/LogicUIStandaloneGUI.java @@ -0,0 +1,59 @@ +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 diff --git a/LogicUI/src/era/mi/gui/SimpleLogicUIStandalone.java b/LogicUI/src/era/mi/gui/SimpleLogicUIStandalone.java new file mode 100644 index 00000000..0573aa90 --- /dev/null +++ b/LogicUI/src/era/mi/gui/SimpleLogicUIStandalone.java @@ -0,0 +1,38 @@ +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 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 diff --git a/LogicUI/src/era/mi/gui/examples/Playground.java b/LogicUI/src/era/mi/gui/examples/Playground.java deleted file mode 100644 index 9309eefe..00000000 --- a/LogicUI/src/era/mi/gui/examples/Playground.java +++ /dev/null @@ -1,87 +0,0 @@ -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 diff --git a/LogicUI/src/era/mi/gui/examples/RSLatchExample.java b/LogicUI/src/era/mi/gui/examples/RSLatchExample.java new file mode 100644 index 00000000..91b2d0e5 --- /dev/null +++ b/LogicUI/src/era/mi/gui/examples/RSLatchExample.java @@ -0,0 +1,60 @@ +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 diff --git a/LogicUI/src/era/mi/gui/model/components/GUIManualSwitch.java b/LogicUI/src/era/mi/gui/model/components/GUIManualSwitch.java index c45224ab..b2a8b018 100644 --- a/LogicUI/src/era/mi/gui/model/components/GUIManualSwitch.java +++ b/LogicUI/src/era/mi/gui/model/components/GUIManualSwitch.java @@ -55,7 +55,8 @@ public class GUIManualSwitch extends GUIComponent @Override public boolean clicked(double x, double y) { - logicSwitch.toggle(); + if (logicSwitch != null) + logicSwitch.toggle(); return true; }