From da0a4b7d0619283bb4384091356ce3f105c84e78 Mon Sep 17 00:00:00 2001 From: Daniel Kirschten Date: Thu, 23 May 2019 12:48:54 +0200 Subject: [PATCH] Splitted LogicUI into LogicUICanvas and LogicUIStandalone --- LogicUI/src/era/mi/gui/LogicUI.java | 148 ------------------ LogicUI/src/era/mi/gui/LogicUICanvas.java | 89 +++++++++++ LogicUI/src/era/mi/gui/LogicUIStandalone.java | 85 ++++++++++ .../mi/gui/examples/RSLatchGUIExample.java | 9 +- 4 files changed, 179 insertions(+), 152 deletions(-) delete mode 100644 LogicUI/src/era/mi/gui/LogicUI.java create mode 100644 LogicUI/src/era/mi/gui/LogicUICanvas.java create mode 100644 LogicUI/src/era/mi/gui/LogicUIStandalone.java diff --git a/LogicUI/src/era/mi/gui/LogicUI.java b/LogicUI/src/era/mi/gui/LogicUI.java deleted file mode 100644 index 45a8fa2a..00000000 --- a/LogicUI/src/era/mi/gui/LogicUI.java +++ /dev/null @@ -1,148 +0,0 @@ -package era.mi.gui; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -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.Event; -import org.eclipse.swt.widgets.Shell; - -import era.mi.gui.components.BasicGUIComponent; -import era.mi.gui.wires.GUIWire; -import era.mi.logic.Simulation; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.gcs.TranslatedGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas; -import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay; -import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput; - -/** - * Standalone simulation visualizer. - * - * @author Daniel Kirschten - */ -public class LogicUI -{ - private final Display display; - private final Shell shell; - private final ZoomableCanvas canvas; - private final Set components; - private final Map componentPositions; - private final Set wires; - - public LogicUI() - { - display = new Display(); - shell = new Shell(display); - shell.setLayout(new FillLayout()); - canvas = new ZoomableCanvas(shell, SWT.NONE); - - components = new HashSet<>(); - componentPositions = new HashMap<>(); - wires = new HashSet<>(); - - canvas.addZoomedRenderer(gc -> components.forEach(c -> drawComponent(gc, c))); - canvas.addZoomedRenderer(gc -> wires.forEach(w -> w.render(gc))); - ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(canvas); - userInput.buttonDrag = 3; - userInput.buttonZoom = 2; - userInput.enableUserInput(); - new ZoomableCanvasOverlay(canvas, null).enableScale(); - canvas.addListener(SWT.MouseDown, this::mouseDown); - } - - /** - * Add a component to be drawn. Returns the given component for convenience. - * - * @author Daniel Kirschten - */ - public C addComponent(C component, double x, double y) - { - components.add(component); - componentPositions.put(component, new Point(x, y)); - return component; - } - - /** - * Add a graphical wire between the given connection points of the given components. The given components have to be added and the given - * connection points have to be connected logically first. - * - * @author Daniel Kirschten - */ - public void addWire(BasicGUIComponent component1, int component1ConnectionIndex, BasicGUIComponent component2, - int component2ConnectionIndex, Point... path) - { - wires.add(new GUIWire(canvas::redrawThreadsafe, component1, component1ConnectionIndex, componentPositions.get(component1), - component2, component2ConnectionIndex, componentPositions.get(component2), path)); - } - - private void drawComponent(GeneralGC gc, BasicGUIComponent component) - { - TranslatedGC tgc = new TranslatedGC(gc, componentPositions.get(component)); - component.render(tgc); - tgc.setBackground(display.getSystemColor(SWT.COLOR_BLUE)); - } - - private void mouseDown(Event e) - { - if (e.button == 1) - { - Point click = canvas.displayToWorldCoords(e.x, e.y); - for (BasicGUIComponent component : components) - if (component.getBounds().translate(componentPositions.get(component)).contains(click)) - { - if (component.clicked(click.x, click.y)) - canvas.redraw(); - break; - } - } - } - - /** - * 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 - Simulation.TIMELINE.executeUpTo(System.currentTimeMillis(), System.currentTimeMillis() + 10); - long sleepTime; - if (Simulation.TIMELINE.hasNext()) - sleepTime = Simulation.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(); - Simulation.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/LogicUICanvas.java b/LogicUI/src/era/mi/gui/LogicUICanvas.java new file mode 100644 index 00000000..fd6d4daa --- /dev/null +++ b/LogicUI/src/era/mi/gui/LogicUICanvas.java @@ -0,0 +1,89 @@ +package era.mi.gui; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; + +import era.mi.gui.components.BasicGUIComponent; +import era.mi.gui.wires.GUIWire; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.gcs.TranslatedGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; +import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas; + +/** + * Simulation visualizer canvas. + * + * @author Daniel Kirschten + */ +public class LogicUICanvas extends ZoomableCanvas +{ + private final Set components; + private final Map componentPositions; + private final Set wires; + + public LogicUICanvas(Composite parent, int style) + { + super(parent, style); + + components = new HashSet<>(); + componentPositions = new HashMap<>(); + wires = new HashSet<>(); + + addZoomedRenderer(gc -> components.forEach(c -> drawComponent(gc, c))); + addZoomedRenderer(gc -> wires.forEach(w -> w.render(gc))); + addListener(SWT.MouseDown, this::mouseDown); + } + + /** + * Add a component to be drawn. Returns the given component for convenience. + * + * @author Daniel Kirschten + */ + public C addComponent(C component, double x, double y) + { + components.add(component); + componentPositions.put(component, new Point(x, y)); + return component; + } + + /** + * Add a graphical wire between the given connection points of the given components. The given components have to be added and the given + * connection points have to be connected logically first. + * + * @author Daniel Kirschten + */ + public void addWire(BasicGUIComponent component1, int component1ConnectionIndex, BasicGUIComponent component2, + int component2ConnectionIndex, Point... path) + { + wires.add(new GUIWire(this::redrawThreadsafe, component1, component1ConnectionIndex, componentPositions.get(component1), component2, + component2ConnectionIndex, componentPositions.get(component2), path)); + } + + private void drawComponent(GeneralGC gc, BasicGUIComponent component) + { + TranslatedGC tgc = new TranslatedGC(gc, componentPositions.get(component)); + component.render(tgc); + tgc.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLUE)); + } + + private void mouseDown(Event e) + { + if (e.button == 1) + { + Point click = displayToWorldCoords(e.x, e.y); + for (BasicGUIComponent component : components) + if (component.getBounds().translate(componentPositions.get(component)).contains(click)) + { + if (component.clicked(click.x, click.y)) + redraw(); + break; + } + } + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/LogicUIStandalone.java b/LogicUI/src/era/mi/gui/LogicUIStandalone.java new file mode 100644 index 00000000..fea7e184 --- /dev/null +++ b/LogicUI/src/era/mi/gui/LogicUIStandalone.java @@ -0,0 +1,85 @@ +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.logic.Simulation; +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 final Display display; + private final Shell shell; + private final LogicUICanvas ui; + + public LogicUIStandalone() + { + display = new Display(); + shell = new Shell(display); + shell.setLayout(new FillLayout()); + ui = new LogicUICanvas(shell, SWT.NONE); + + ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui); + userInput.buttonDrag = 3; + userInput.buttonZoom = 2; + userInput.enableUserInput(); + new ZoomableCanvasOverlay(ui, null).enableScale(); + } + + 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 + Simulation.TIMELINE.executeUpTo(System.currentTimeMillis(), System.currentTimeMillis() + 10); + long sleepTime; + if (Simulation.TIMELINE.hasNext()) + sleepTime = Simulation.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(); + Simulation.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/examples/RSLatchGUIExample.java b/LogicUI/src/era/mi/gui/examples/RSLatchGUIExample.java index 0f2e8f29..4aec4cd8 100644 --- a/LogicUI/src/era/mi/gui/examples/RSLatchGUIExample.java +++ b/LogicUI/src/era/mi/gui/examples/RSLatchGUIExample.java @@ -1,6 +1,7 @@ package era.mi.gui.examples; -import era.mi.gui.LogicUI; +import era.mi.gui.LogicUICanvas; +import era.mi.gui.LogicUIStandalone; import era.mi.gui.components.GUIManualSwitch; import era.mi.gui.components.GUINotGate; import era.mi.gui.components.GUIOrGate; @@ -17,12 +18,12 @@ public class RSLatchGUIExample public static void main(String[] args) { - LogicUI ui = new LogicUI(); - initComponents(ui); + LogicUIStandalone ui = new LogicUIStandalone(); + initComponents(ui.getLogicUICanvas()); ui.run(); } - private static void initComponents(LogicUI ui) + private static void initComponents(LogicUICanvas ui) { Simulation.TIMELINE.reset(); Wire r = new Wire(1, WIRE_DELAY); -- 2.17.1