From: Fabian Stemmler Date: Wed, 29 May 2019 10:42:50 +0000 (+0200) Subject: Merge branch 'development' of X-Git-Url: https://mograsim.net/gitweb/?a=commitdiff_plain;h=50082bc2126d3f408acbdf4103bb4fdf29ac1d4f;hp=a37db10f5372ec09624b2ad9b60587e498991cbd;p=Mograsim.git Merge branch 'development' of https://gitlab.lrz.de/lrr-tum/students/eragp-misim-2019 into development # Conflicts: # LogicUI/oldsrc/RSLatchGUIExample.java # LogicUI/src/era/mi/gui/LogicUIStandalone.java # LogicUI/src/era/mi/gui/components/GUIManualSwitch.java # SampleERCP/src/sampleercp/parts/LogicUIPart.java --- diff --git a/LogicUI/oldsrc/GUIMerger.java b/LogicUI/oldsrc/GUIMerger.java new file mode 100644 index 00000000..64fd0aa9 --- /dev/null +++ b/LogicUI/oldsrc/GUIMerger.java @@ -0,0 +1,79 @@ +package era.mi.gui.components; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import era.mi.logic.components.Merger; +import era.mi.logic.wires.Wire.ReadEnd; +import era.mi.logic.wires.Wire.ReadWriteEnd; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; + +public class GUIMerger extends Merger implements GUIComponent +{ + private final int inputCount; + private final double height; + private final List connectedWireEnds; + private final List WireEndConnectionPoints; + + public GUIMerger(ReadWriteEnd union, ReadEnd... inputs) + { + super(union, inputs); + + List connectedWireEndsModifiable = new ArrayList<>(); + List WireEndConnectionPointsModifiable = new ArrayList<>(); + + this.inputCount = inputs.length; + this.height = (inputCount - 1) * 10; + + { + connectedWireEndsModifiable.addAll(Arrays.asList(inputs)); + double inputHeight = 0; + for (int i = 0; i < inputCount; i++, inputHeight += 10) + WireEndConnectionPointsModifiable.add(new Point(0, inputHeight)); + } + + connectedWireEndsModifiable.add(union); + WireEndConnectionPointsModifiable.add(new Point(20, height / 2)); + + this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); + this.WireEndConnectionPoints = Collections.unmodifiableList(WireEndConnectionPointsModifiable); + } + + @Override + public Rectangle getBounds() + { + return new Rectangle(0, 0, 20, height); + } + + @Override + public void render(GeneralGC gc) + { + double inputHeight = 0; + for (int i = 0; i < inputCount; i++, inputHeight += 10) + gc.drawLine(0, inputHeight, 10, inputHeight); + gc.drawLine(10, 0, 10, height); + gc.drawLine(10, height / 2, 20, height / 2); + } + + @Override + public int getConnectedWireEndsCount() + { + return connectedWireEnds.size(); + } + + @Override + public ReadEnd getConnectedWireEnd(int connectionIndex) + { + return connectedWireEnds.get(connectionIndex); + } + + @Override + public Point getWireEndConnectionPoint(int connectionI) + { + return WireEndConnectionPoints.get(connectionI); + } +} \ No newline at end of file diff --git a/LogicUI/oldsrc/GUIMux.java b/LogicUI/oldsrc/GUIMux.java new file mode 100644 index 00000000..d004d90f --- /dev/null +++ b/LogicUI/oldsrc/GUIMux.java @@ -0,0 +1,80 @@ +package era.mi.gui.components; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import era.mi.logic.components.Mux; +import era.mi.logic.wires.Wire.ReadEnd; +import era.mi.logic.wires.Wire.ReadWriteEnd; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; + +public class GUIMux extends Mux implements GUIComponent +{ + private final double height; + private final List connectedWireEnds; + private final List WireEndConnectionPoints; + + public GUIMux(int processTime, ReadWriteEnd out, ReadEnd select, ReadEnd... inputs) + { + super(processTime, out, select, inputs); + + double height = inputs.length * 5; + if (height < 10) + height = 10; + this.height = height; + + List connectedWireEndsModifiable = new ArrayList<>(); + List WireEndConnectionPointsModifiable = new ArrayList<>(); + + connectedWireEndsModifiable.add(out); + WireEndConnectionPointsModifiable.add(new Point(20, 10 + height / 2)); + + connectedWireEndsModifiable.add(select); + WireEndConnectionPointsModifiable.add(new Point(10, 5)); + + { + connectedWireEndsModifiable.addAll(Arrays.asList(inputs)); + double inputHeightIncrement = (height + 20) / inputs.length; + double inputHeight = inputHeightIncrement / 2; + for (int i = 0; i < inputs.length; i++, inputHeight += inputHeightIncrement) + WireEndConnectionPointsModifiable.add(new Point(0, inputHeight)); + } + + this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); + this.WireEndConnectionPoints = Collections.unmodifiableList(WireEndConnectionPointsModifiable); + } + + @Override + public Rectangle getBounds() + { + return new Rectangle(0, 0, 20, height + 20); + } + + @Override + public void render(GeneralGC gc) + { + gc.drawPolygon(new double[] { 0, 0, 20, 10, 20, height + 10, 0, height + 20 }); + } + + @Override + public int getConnectedWireEndsCount() + { + return connectedWireEnds.size(); + } + + @Override + public ReadEnd getConnectedWireEnd(int connectionIndex) + { + return connectedWireEnds.get(connectionIndex); + } + + @Override + public Point getWireEndConnectionPoint(int connectionI) + { + return WireEndConnectionPoints.get(connectionI); + } +} \ No newline at end of file diff --git a/LogicUI/oldsrc/GUISplitter.java b/LogicUI/oldsrc/GUISplitter.java new file mode 100644 index 00000000..1bff4247 --- /dev/null +++ b/LogicUI/oldsrc/GUISplitter.java @@ -0,0 +1,72 @@ +package era.mi.gui.components; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import era.mi.gui.ViewModel; +import era.mi.logic.components.Splitter; +import era.mi.logic.wires.Wire.ReadEnd; +import era.mi.logic.wires.Wire.ReadWriteEnd; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; + +public class GUISplitter extends GUIComponent +{ + public GUISplitter(ViewModel model) + { + super(model); + + this.outputCount = outputs.length; + this.height = (outputCount - 1) * 10; + + connectedWireEndsModifiable.add(input); + WireEndConnectionPointsModifiable.add(new Point(0, height / 2)); + + { + connectedWireEndsModifiable.addAll(Arrays.asList(outputs)); + double outputHeight = 0; + for (int i = 0; i < outputCount; i++, outputHeight += 10) + WireEndConnectionPointsModifiable.add(new Point(20, outputHeight)); + } + + this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); + this.WireEndConnectionPoints = Collections.unmodifiableList(WireEndConnectionPointsModifiable); + } + + @Override + public Rectangle getBounds() + { + return new Rectangle(0, 0, 20, height); + } + + @Override + public void render(GeneralGC gc) + { + gc.drawLine(0, height / 2, 10, height / 2); + gc.drawLine(10, 0, 10, height); + double outputHeight = 0; + for (int i = 0; i < outputCount; i++, outputHeight += 10) + gc.drawLine(10, outputHeight, 20, outputHeight); + } + + @Override + public int getConnectedWireEndsCount() + { + return connectedWireEnds.size(); + } + + @Override + public ReadEnd getConnectedWireEnd(int connectionIndex) + { + return connectedWireEnds.get(connectionIndex); + } + + @Override + public Point getWireEndConnectionPoint(int connectionI) + { + return WireEndConnectionPoints.get(connectionI); + } +} \ No newline at end of file diff --git a/LogicUI/oldsrc/RSLatchGUIExample.java b/LogicUI/oldsrc/RSLatchGUIExample.java new file mode 100644 index 00000000..413525bf --- /dev/null +++ b/LogicUI/oldsrc/RSLatchGUIExample.java @@ -0,0 +1,62 @@ +package era.mi.gui.examples; + +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.GUIOrGateOld; +import era.mi.gui.wires.WireConnectionPoint; +import era.mi.logic.timeline.Timeline; +import era.mi.logic.wires.Wire; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; + +public class RSLatchGUIExample +{ + private static final int WIRE_DELAY = 10; + private static final int OR_DELAY = 50; + private static final int NOT_DELAY = 50; + + public static void main(String[] args) + { + Timeline t = new Timeline(11); + t.setTimeFunction(() -> System.currentTimeMillis()); // real time simulation + LogicUIStandalone ui = new LogicUIStandalone(t); + addComponentsAndWires(ui.getLogicUICanvas(), t); + ui.run(); + } + + public static void addComponentsAndWires(LogicUICanvas ui, Timeline t) + { + Wire r = new Wire(t, 1, WIRE_DELAY); + Wire s = new Wire(t, 1, WIRE_DELAY); + Wire t2 = new Wire(t, 1, WIRE_DELAY); + Wire t1 = new Wire(t, 1, WIRE_DELAY); + Wire q = new Wire(t, 1, WIRE_DELAY); + Wire nq = new Wire(t, 1, WIRE_DELAY); + + GUIManualSwitch rIn = ui.addComponent(new GUIManualSwitch(t, r.createReadWriteEnd()), 100, 100); + GUIManualSwitch sIn = ui.addComponent(new GUIManualSwitch(t, s.createReadWriteEnd()), 100, 200); + GUIOrGateOld or1 = ui.addComponent(new GUIOrGateOld(t, OR_DELAY, t1.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd()), + 160, 102.5); + GUIOrGateOld or2 = ui.addComponent(new GUIOrGateOld(t, OR_DELAY, t2.createReadWriteEnd(), q.createReadOnlyEnd(), s.createReadOnlyEnd()), + 160, 192.5); + GUINotGate not1 = ui.addComponent(new GUINotGate(t, NOT_DELAY, t1.createReadOnlyEnd(), q.createReadWriteEnd()), 200, 107.5); + GUINotGate not2 = ui.addComponent(new GUINotGate(t, NOT_DELAY, t2.createReadOnlyEnd(), nq.createReadWriteEnd()), 200, 197.5); + + WireConnectionPoint p1 = ui.addComponent(new WireConnectionPoint(q, 3), 250, 112.5); + WireConnectionPoint p2 = ui.addComponent(new WireConnectionPoint(nq, 3), 250, 202.5); + WireConnectionPoint o1 = ui.addComponent(new WireConnectionPoint(q, 1), 270, 112.5); + WireConnectionPoint o2 = ui.addComponent(new WireConnectionPoint(nq, 1), 270, 202.5); + + ui.addWire(rIn, 0, or1, 0); + ui.addWire(sIn, 0, or2, 1); + ui.addWire(or1, 2, not1, 0); + ui.addWire(or2, 2, not2, 0); + ui.addWire(not1, 1, p1, 0); + ui.addWire(not2, 1, p2, 0); + ui.addWire(p1, 1, or2, 0, new Point(250, 130), new Point(140, 185), new Point(140, 197.5)); + ui.addWire(p2, 1, or1, 1, new Point(250, 185), new Point(140, 130), new Point(140, 117.5)); + ui.addWire(p1, 2, o1, 0); + ui.addWire(p2, 2, o2, 0); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/ColorHelper.java b/LogicUI/src/era/mi/gui/ColorHelper.java new file mode 100644 index 00000000..ff6a4950 --- /dev/null +++ b/LogicUI/src/era/mi/gui/ColorHelper.java @@ -0,0 +1,91 @@ +package era.mi.gui; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Device; + +import era.mi.logic.types.ColorDefinition; +import era.mi.logic.types.ColorDefinition.BuiltInColor; +import net.haspamelodica.swt.helper.gcs.GeneralGC; + +//TODO replace with a proper ColorManager +public class ColorHelper +{ + public static void executeWithDifferentForeground(GeneralGC gc, ColorDefinition col, Runnable exec) + { + executeWithDifferentColor(gc.getDevice(), col, gc::getForeground, gc::setForeground, exec); + } + + public static void executeWithDifferentBackground(GeneralGC gc, ColorDefinition col, Runnable exec) + { + executeWithDifferentColor(gc.getDevice(), col, gc::getBackground, gc::setBackground, exec); + } + + private static void executeWithDifferentColor(Device device, ColorDefinition col, Supplier getColor, Consumer setColor, + Runnable exec) + { + Color oldColor = getColor.get(); + boolean isNoSystemColor = col.builtInColor == null; + Color newColor; + if (isNoSystemColor) + newColor = new Color(device, col.r, col.g, col.b); + else + newColor = device.getSystemColor(ColorHelper.toSWTColorConstant(col.builtInColor)); + setColor.accept(newColor); + + exec.run(); + + setColor.accept(oldColor); + if (isNoSystemColor) + newColor.dispose(); + } + + public static int toSWTColorConstant(BuiltInColor col) + { + switch (col) + { + case COLOR_BLACK: + return SWT.COLOR_BLACK; + case COLOR_BLUE: + return SWT.COLOR_BLUE; + case COLOR_CYAN: + return SWT.COLOR_CYAN; + case COLOR_DARK_BLUE: + return SWT.COLOR_DARK_BLUE; + case COLOR_DARK_CYAN: + return SWT.COLOR_DARK_CYAN; + case COLOR_DARK_GRAY: + return SWT.COLOR_DARK_GRAY; + case COLOR_DARK_GREEN: + return SWT.COLOR_DARK_GREEN; + case COLOR_DARK_MAGENTA: + return SWT.COLOR_DARK_MAGENTA; + case COLOR_DARK_RED: + return SWT.COLOR_DARK_RED; + case COLOR_DARK_YELLOW: + return SWT.COLOR_DARK_YELLOW; + case COLOR_GRAY: + return SWT.COLOR_GRAY; + case COLOR_GREEN: + return SWT.COLOR_GREEN; + case COLOR_MAGENTA: + return SWT.COLOR_MAGENTA; + case COLOR_RED: + return SWT.COLOR_RED; + case COLOR_WHITE: + return SWT.COLOR_WHITE; + case COLOR_YELLOW: + return SWT.COLOR_YELLOW; + default: + throw new IllegalArgumentException("Unknown enum constant: " + col); + } + } + + private ColorHelper() + { + throw new UnsupportedOperationException("No instances of ColorHelper"); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/LogicUICanvas.java b/LogicUI/src/era/mi/gui/LogicUICanvas.java index dadbae0e..2fbb45d1 100644 --- a/LogicUI/src/era/mi/gui/LogicUICanvas.java +++ b/LogicUI/src/era/mi/gui/LogicUICanvas.java @@ -1,19 +1,17 @@ package era.mi.gui; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.function.Consumer; 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 era.mi.gui.model.ViewModel; +import era.mi.gui.model.components.GUIComponent; +import era.mi.gui.model.wires.Pin; 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.swtobjectwrappers.Rectangle; import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas; /** @@ -23,53 +21,70 @@ import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas; */ public class LogicUICanvas extends ZoomableCanvas { - private final Set components; - private final Map componentPositions; - private final Set wires; + private final ViewModel model; - public LogicUICanvas(Composite parent, int style) + public LogicUICanvas(Composite parent, int style, ViewModel model) { super(parent, style); - components = new HashSet<>(); - componentPositions = new HashMap<>(); - wires = new HashSet<>(); + this.model = model; - 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; - } + Consumer redrawConsumer = o -> redrawThreadsafe(); + Consumer pinAddedListener = p -> + { + p.addPinMovedListener(redrawConsumer); + redrawThreadsafe(); + }; + Consumer pinRemovedListener = p -> + { + p.removePinMovedListener(redrawConsumer); + redrawThreadsafe(); + }; + model.addComponentAddedListener(c -> + { + c.addComponentChangedListener(redrawConsumer); + c.addComponentMovedListener(redrawConsumer); + c.addPinAddedListener(pinAddedListener); + c.addPinRemovedListener(pinRemovedListener); + redrawThreadsafe(); + }); + model.addComponentRemovedListener(c -> + { + c.removeComponentChangedListener(redrawConsumer); + c.removeComponentMovedListener(redrawConsumer); + c.removePinAddedListener(pinAddedListener); + c.removePinRemovedListener(pinRemovedListener); + redrawThreadsafe(); + }); + model.addWireAddedListener(w -> + { + w.addWireChangedListener(redrawConsumer); + redrawThreadsafe(); + }); + model.addWireRemovedListener(w -> + { + w.removeWireChangedListener(redrawConsumer); + redrawThreadsafe(); + }); - /** - * 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)); + addZoomedRenderer(gc -> + { + Rectangle visibleRegion = new Rectangle(offX, offY, gW / zoom, gH / zoom); + model.getComponents().forEach(c -> drawComponent(gc, c, visibleRegion)); + }); + addZoomedRenderer(gc -> model.getWires().forEach(w -> w.render(gc))); + addListener(SWT.MouseDown, this::mouseDown); } - private void drawComponent(GeneralGC gc, BasicGUIComponent component) + private void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion) { - TranslatedGC tgc = new TranslatedGC(gc, componentPositions.get(component)); - component.render(tgc); - tgc.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLUE)); + component.render(gc, visibleRegion); + gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_CYAN)); + for (Pin p : component.getPins()) + { + Point pos = p.getPos(); + gc.fillOval(pos.x - 1, pos.y - 1, 2, 2); + } } private void mouseDown(Event e) @@ -77,11 +92,10 @@ public class LogicUICanvas extends ZoomableCanvas if (e.button == 1) { Point click = displayToWorldCoords(e.x, e.y); - for (BasicGUIComponent component : components) - if (component.getBounds().translate(componentPositions.get(component)).contains(click)) + for (GUIComponent component : model.getComponents()) + if (component.getBounds().contains(click) && component.clicked(click.x, click.y)) { - if (component.clicked(click.x, click.y)) - redraw(); + redraw(); break; } } diff --git a/LogicUI/src/era/mi/gui/LogicUIStandalone.java b/LogicUI/src/era/mi/gui/LogicUIStandalone.java index db498ace..8bbfb1c5 100644 --- a/LogicUI/src/era/mi/gui/LogicUIStandalone.java +++ b/LogicUI/src/era/mi/gui/LogicUIStandalone.java @@ -7,7 +7,7 @@ import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; -import era.mi.logic.timeline.Timeline; +import era.mi.gui.model.ViewModel; import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay; import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput; @@ -18,18 +18,19 @@ import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInpu */ public class LogicUIStandalone { + private ViewModel model; + private final Display display; private final Shell shell; private final LogicUICanvas ui; - private Timeline timeline; - public LogicUIStandalone(Timeline timeline) + public LogicUIStandalone(ViewModel model) { - this.timeline = timeline; + this.model = model; display = new Display(); shell = new Shell(display); shell.setLayout(new FillLayout()); - ui = new LogicUICanvas(shell, SWT.NONE); + ui = new LogicUICanvas(shell, SWT.NONE, model); ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui); userInput.buttonDrag = 3; @@ -49,39 +50,40 @@ public class LogicUIStandalone 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(); - }); +// 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); +// model.timeline.executeUpTo(System.currentTimeMillis(), System.currentTimeMillis() + 10); +// long sleepTime; +// if (model.timeline.hasNext()) +// sleepTime = model.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(); +// model.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(); +// simulationThread.interrupt(); } } \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/components/BasicGUIComponent.java b/LogicUI/src/era/mi/gui/components/BasicGUIComponent.java deleted file mode 100644 index bf13d3e2..00000000 --- a/LogicUI/src/era/mi/gui/components/BasicGUIComponent.java +++ /dev/null @@ -1,44 +0,0 @@ -package era.mi.gui.components; - -import era.mi.logic.wires.Wire.ReadEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public interface BasicGUIComponent -{ - /** - * Render this component to the given gc, at coordinates (0, 0). - */ - public void render(GeneralGC gc); - - /** - * Returns the bounds of this component. Used for calculating which component is clicked. - */ - public Rectangle getBounds(); - - /** - * Called when this component is clicked. Relative coordinates of the click are given. Returns true if this component has to be redrawn. - */ - public default boolean clicked(double x, double y) - { - return false; - } - - // TODO this code will be replaced by code in BasicComponent. - /** - * Returns how many wire arrays are connected to this component. (Connections are static - they can't be removed and no new ones can be - * added) - */ - public int getConnectedWireEndsCount(); - - /** - * Returns the n-th wire array connected to this component. - */ - public ReadEnd getConnectedWireEnd(int connectionIndex); - - /** - * Returns relative coordinates where the n-th wire array is connected to this component. - */ - public Point getWireEndConnectionPoint(int connectionIndex); -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/components/GUIAndGate.java b/LogicUI/src/era/mi/gui/components/GUIAndGate.java deleted file mode 100644 index 27cefc0d..00000000 --- a/LogicUI/src/era/mi/gui/components/GUIAndGate.java +++ /dev/null @@ -1,85 +0,0 @@ -package era.mi.gui.components; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import era.mi.logic.components.gates.AndGate; -import era.mi.logic.timeline.Timeline; -import era.mi.logic.wires.Wire.ReadEnd; -import era.mi.logic.wires.Wire.ReadWriteEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Font; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public class GUIAndGate extends AndGate implements BasicGUIComponent -{ - private static final String LABEL = "&"; - - private final int inputCount; - private final double height; - private final List connectedWireEnds; - private final List wireEndConnectionPoints; - - public GUIAndGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in) - { - super(timeline, processTime, out, in); - - List connectedWireEndsModifiable = new ArrayList<>(); - List wireEndConnectionPointsModifiable = new ArrayList<>(); - - this.inputCount = in.length; - this.height = inputCount * 10; - - { - connectedWireEndsModifiable.addAll(Arrays.asList(in)); - double inputHeight = 5; - for (int i = 0; i < inputCount; i++, inputHeight += 10) - wireEndConnectionPointsModifiable.add(new Point(0, inputHeight)); - } - - connectedWireEndsModifiable.add(out); - wireEndConnectionPointsModifiable.add(new Point(20, height / 2)); - - this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); - this.wireEndConnectionPoints = Collections.unmodifiableList(wireEndConnectionPointsModifiable); - } - - @Override - public Rectangle getBounds() - { - return new Rectangle(0, 0, 20, height); - } - - @Override - public void render(GeneralGC gc) - { - gc.drawRectangle(0, 0, 20, height); - Font oldFont = gc.getFont(); - Font labelFont = new Font(oldFont.getName(), 5, oldFont.getStyle()); - gc.setFont(labelFont); - Point textExtent = gc.textExtent(LABEL); - gc.drawText(LABEL, 10 - textExtent.x / 2, (height - textExtent.y) / 2, true); - gc.setFont(oldFont); - } - - @Override - public int getConnectedWireEndsCount() - { - return connectedWireEnds.size(); - } - - @Override - public ReadEnd getConnectedWireEnd(int connectionIndex) - { - return connectedWireEnds.get(connectionIndex); - } - - @Override - public Point getWireEndConnectionPoint(int connectionI) - { - return wireEndConnectionPoints.get(connectionI); - } -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/components/GUIManualSwitch.java b/LogicUI/src/era/mi/gui/components/GUIManualSwitch.java index ff674c5c..7bec909e 100644 --- a/LogicUI/src/era/mi/gui/components/GUIManualSwitch.java +++ b/LogicUI/src/era/mi/gui/components/GUIManualSwitch.java @@ -1,96 +1,6 @@ package era.mi.gui.components; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import era.mi.logic.components.ManualSwitch; -import era.mi.logic.timeline.Timeline; -import era.mi.logic.types.Bit; -import era.mi.logic.wires.Wire.ReadEnd; -import era.mi.logic.wires.Wire.ReadWriteEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Font; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public class GUIManualSwitch extends ManualSwitch implements BasicGUIComponent +public class GUIManualSwitch { - private static final Map bitNames; - static - { - Map bitNamesModifiable = new HashMap<>(); - bitNamesModifiable.put(Bit.ONE, "1"); - bitNamesModifiable.put(Bit.ZERO, "0"); - bitNamesModifiable.put(Bit.Z, "Z"); - bitNamesModifiable.put(Bit.U, "U"); - bitNamesModifiable.put(Bit.X, "X"); - bitNames = Collections.unmodifiableMap(bitNamesModifiable); - } - - private final ReadEnd we; - private final List connectedWireEnds; - private final List wireEndConnectionPoints; - - public GUIManualSwitch(Timeline timeline, ReadWriteEnd output) - { - super(timeline, output); - - this.we = output; - - List connectedWireEndsModifiable = new ArrayList<>(); - List wireEndConnectionPointsModifiable = new ArrayList<>(); - - connectedWireEndsModifiable.add(output); - wireEndConnectionPointsModifiable.add(new Point(20, 7.5)); - - this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); - this.wireEndConnectionPoints = Collections.unmodifiableList(wireEndConnectionPointsModifiable); - } - - @Override - public Rectangle getBounds() - { - return new Rectangle(0, 0, 20, 15); - } - - @Override - public void render(GeneralGC gc) - { - gc.drawRectangle(0, 0, 20, 15); - String label = bitNames.get(we.getValue()); - Font oldFont = gc.getFont(); - Font labelFont = new Font(oldFont.getName(), 6, oldFont.getStyle()); - gc.setFont(labelFont); - Point textExtent = gc.textExtent(label); - gc.drawText(label, 10 - textExtent.x / 2, 7.5 - textExtent.y / 2, true); - gc.setFont(oldFont); - } - - @Override - public boolean clicked(double x, double y) - { - timeline.addEvent((e) -> toggle(), (int) (System.currentTimeMillis() - timeline.getSimulationTime())); - return true; - } - - @Override - public int getConnectedWireEndsCount() - { - return connectedWireEnds.size(); - } - - @Override - public ReadEnd getConnectedWireEnd(int connectionIndex) - { - return connectedWireEnds.get(connectionIndex); - } - @Override - public Point getWireEndConnectionPoint(int connectionI) - { - return wireEndConnectionPoints.get(connectionI); - } -} \ No newline at end of file +} diff --git a/LogicUI/src/era/mi/gui/components/GUIMerger.java b/LogicUI/src/era/mi/gui/components/GUIMerger.java deleted file mode 100644 index 1525d0b8..00000000 --- a/LogicUI/src/era/mi/gui/components/GUIMerger.java +++ /dev/null @@ -1,80 +0,0 @@ -package era.mi.gui.components; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import era.mi.logic.components.Merger; -import era.mi.logic.timeline.Timeline; -import era.mi.logic.wires.Wire.ReadEnd; -import era.mi.logic.wires.Wire.ReadWriteEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public class GUIMerger extends Merger implements BasicGUIComponent -{ - private final int inputCount; - private final double height; - private final List connectedWireEnds; - private final List WireEndConnectionPoints; - - public GUIMerger(Timeline timeline, ReadWriteEnd union, ReadEnd... inputs) - { - super(timeline, union, inputs); - - List connectedWireEndsModifiable = new ArrayList<>(); - List WireEndConnectionPointsModifiable = new ArrayList<>(); - - this.inputCount = inputs.length; - this.height = (inputCount - 1) * 10; - - { - connectedWireEndsModifiable.addAll(Arrays.asList(inputs)); - double inputHeight = 0; - for (int i = 0; i < inputCount; i++, inputHeight += 10) - WireEndConnectionPointsModifiable.add(new Point(0, inputHeight)); - } - - connectedWireEndsModifiable.add(union); - WireEndConnectionPointsModifiable.add(new Point(20, height / 2)); - - this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); - this.WireEndConnectionPoints = Collections.unmodifiableList(WireEndConnectionPointsModifiable); - } - - @Override - public Rectangle getBounds() - { - return new Rectangle(0, 0, 20, height); - } - - @Override - public void render(GeneralGC gc) - { - double inputHeight = 0; - for (int i = 0; i < inputCount; i++, inputHeight += 10) - gc.drawLine(0, inputHeight, 10, inputHeight); - gc.drawLine(10, 0, 10, height); - gc.drawLine(10, height / 2, 20, height / 2); - } - - @Override - public int getConnectedWireEndsCount() - { - return connectedWireEnds.size(); - } - - @Override - public ReadEnd getConnectedWireEnd(int connectionIndex) - { - return connectedWireEnds.get(connectionIndex); - } - - @Override - public Point getWireEndConnectionPoint(int connectionI) - { - return WireEndConnectionPoints.get(connectionI); - } -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/components/GUIMux.java b/LogicUI/src/era/mi/gui/components/GUIMux.java deleted file mode 100644 index 7fc1fa96..00000000 --- a/LogicUI/src/era/mi/gui/components/GUIMux.java +++ /dev/null @@ -1,81 +0,0 @@ -package era.mi.gui.components; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import era.mi.logic.components.Mux; -import era.mi.logic.timeline.Timeline; -import era.mi.logic.wires.Wire.ReadEnd; -import era.mi.logic.wires.Wire.ReadWriteEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public class GUIMux extends Mux implements BasicGUIComponent -{ - private final double height; - private final List connectedWireEnds; - private final List WireEndConnectionPoints; - - public GUIMux(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd select, ReadEnd... inputs) - { - super(timeline, processTime, out, select, inputs); - - double height = inputs.length * 5; - if (height < 10) - height = 10; - this.height = height; - - List connectedWireEndsModifiable = new ArrayList<>(); - List WireEndConnectionPointsModifiable = new ArrayList<>(); - - connectedWireEndsModifiable.add(out); - WireEndConnectionPointsModifiable.add(new Point(20, 10 + height / 2)); - - connectedWireEndsModifiable.add(select); - WireEndConnectionPointsModifiable.add(new Point(10, 5)); - - { - connectedWireEndsModifiable.addAll(Arrays.asList(inputs)); - double inputHeightIncrement = (height + 20) / inputs.length; - double inputHeight = inputHeightIncrement / 2; - for (int i = 0; i < inputs.length; i++, inputHeight += inputHeightIncrement) - WireEndConnectionPointsModifiable.add(new Point(0, inputHeight)); - } - - this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); - this.WireEndConnectionPoints = Collections.unmodifiableList(WireEndConnectionPointsModifiable); - } - - @Override - public Rectangle getBounds() - { - return new Rectangle(0, 0, 20, height + 20); - } - - @Override - public void render(GeneralGC gc) - { - gc.drawPolygon(new double[] { 0, 0, 20, 10, 20, height + 10, 0, height + 20 }); - } - - @Override - public int getConnectedWireEndsCount() - { - return connectedWireEnds.size(); - } - - @Override - public ReadEnd getConnectedWireEnd(int connectionIndex) - { - return connectedWireEnds.get(connectionIndex); - } - - @Override - public Point getWireEndConnectionPoint(int connectionI) - { - return WireEndConnectionPoints.get(connectionI); - } -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/components/GUINotGate.java b/LogicUI/src/era/mi/gui/components/GUINotGate.java deleted file mode 100644 index e860d9b9..00000000 --- a/LogicUI/src/era/mi/gui/components/GUINotGate.java +++ /dev/null @@ -1,76 +0,0 @@ -package era.mi.gui.components; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import era.mi.logic.components.gates.NotGate; -import era.mi.logic.timeline.Timeline; -import era.mi.logic.wires.Wire.ReadEnd; -import era.mi.logic.wires.Wire.ReadWriteEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Font; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public class GUINotGate extends NotGate implements BasicGUIComponent -{ - private static final String LABEL = "\u22651";// >=1 - - private final List connectedWireEnds; - private final List WireEndConnectionPoints; - - public GUINotGate(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out) - { - super(timeline, processTime, in, out); - - List connectedWireEndsModifiable = new ArrayList<>(); - List WireEndConnectionPointsModifiable = new ArrayList<>(); - - connectedWireEndsModifiable.add(in); - WireEndConnectionPointsModifiable.add(new Point(0, 5)); - - connectedWireEndsModifiable.add(out); - WireEndConnectionPointsModifiable.add(new Point(20, 5)); - - this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); - this.WireEndConnectionPoints = Collections.unmodifiableList(WireEndConnectionPointsModifiable); - } - - @Override - public Rectangle getBounds() - { - return new Rectangle(0, 0, 20, 10); - } - - @Override - public void render(GeneralGC gc) - { - gc.drawRectangle(0, 0, 17, 10); - Font oldFont = gc.getFont(); - Font labelFont = new Font(oldFont.getName(), 5, oldFont.getStyle()); - gc.setFont(labelFont); - Point textExtent = gc.textExtent(LABEL); - gc.drawText(LABEL, 8.5 - textExtent.x / 2, 5 - textExtent.y / 2, true); - gc.setFont(oldFont); - gc.drawOval(17, 3.5, 3, 3); - } - - @Override - public int getConnectedWireEndsCount() - { - return connectedWireEnds.size(); - } - - @Override - public ReadEnd getConnectedWireEnd(int connectionIndex) - { - return connectedWireEnds.get(connectionIndex); - } - - @Override - public Point getWireEndConnectionPoint(int connectionI) - { - return WireEndConnectionPoints.get(connectionI); - } -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/components/GUIOrGate.java b/LogicUI/src/era/mi/gui/components/GUIOrGate.java deleted file mode 100644 index 573c640a..00000000 --- a/LogicUI/src/era/mi/gui/components/GUIOrGate.java +++ /dev/null @@ -1,85 +0,0 @@ -package era.mi.gui.components; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import era.mi.logic.components.gates.OrGate; -import era.mi.logic.timeline.Timeline; -import era.mi.logic.wires.Wire.ReadEnd; -import era.mi.logic.wires.Wire.ReadWriteEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Font; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public class GUIOrGate extends OrGate implements BasicGUIComponent -{ - private static final String LABEL = "\u22651";// >=1 - - private final int inputCount; - private final double height; - private final List connectedWireEnds; - private final List WireEndConnectionPoints; - - public GUIOrGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in) - { - super(timeline, processTime, out, in); - - List connectedWireEndsModifiable = new ArrayList<>(); - List WireEndConnectionPointsModifiable = new ArrayList<>(); - - this.inputCount = in.length; - this.height = inputCount * 10; - - { - connectedWireEndsModifiable.addAll(Arrays.asList(in)); - double inputHeight = 5; - for (int i = 0; i < inputCount; i++, inputHeight += 10) - WireEndConnectionPointsModifiable.add(new Point(0, inputHeight)); - } - - connectedWireEndsModifiable.add(out); - WireEndConnectionPointsModifiable.add(new Point(20, height / 2)); - - this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); - this.WireEndConnectionPoints = Collections.unmodifiableList(WireEndConnectionPointsModifiable); - } - - @Override - public Rectangle getBounds() - { - return new Rectangle(0, 0, 20, height); - } - - @Override - public void render(GeneralGC gc) - { - gc.drawRectangle(0, 0, 20, height); - Font oldFont = gc.getFont(); - Font labelFont = new Font(oldFont.getName(), 5, oldFont.getStyle()); - gc.setFont(labelFont); - Point textExtent = gc.textExtent(LABEL); - gc.drawText(LABEL, 10 - textExtent.x / 2, (height - textExtent.y) / 2, true); - gc.setFont(oldFont); - } - - @Override - public int getConnectedWireEndsCount() - { - return connectedWireEnds.size(); - } - - @Override - public ReadEnd getConnectedWireEnd(int connectionIndex) - { - return connectedWireEnds.get(connectionIndex); - } - - @Override - public Point getWireEndConnectionPoint(int connectionI) - { - return WireEndConnectionPoints.get(connectionI); - } -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/components/GUISplitter.java b/LogicUI/src/era/mi/gui/components/GUISplitter.java deleted file mode 100644 index d229ac18..00000000 --- a/LogicUI/src/era/mi/gui/components/GUISplitter.java +++ /dev/null @@ -1,80 +0,0 @@ -package era.mi.gui.components; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import era.mi.logic.components.Splitter; -import era.mi.logic.timeline.Timeline; -import era.mi.logic.wires.Wire.ReadEnd; -import era.mi.logic.wires.Wire.ReadWriteEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public class GUISplitter extends Splitter implements BasicGUIComponent -{ - private final int outputCount; - private final double height; - private final List connectedWireEnds; - private final List WireEndConnectionPoints; - - public GUISplitter(Timeline timeline, ReadEnd input, ReadWriteEnd... outputs) - { - super(timeline, input, outputs); - - List connectedWireEndsModifiable = new ArrayList<>(); - List WireEndConnectionPointsModifiable = new ArrayList<>(); - - this.outputCount = outputs.length; - this.height = (outputCount - 1) * 10; - - connectedWireEndsModifiable.add(input); - WireEndConnectionPointsModifiable.add(new Point(0, height / 2)); - - { - connectedWireEndsModifiable.addAll(Arrays.asList(outputs)); - double outputHeight = 0; - for (int i = 0; i < outputCount; i++, outputHeight += 10) - WireEndConnectionPointsModifiable.add(new Point(20, outputHeight)); - } - - this.connectedWireEnds = Collections.unmodifiableList(connectedWireEndsModifiable); - this.WireEndConnectionPoints = Collections.unmodifiableList(WireEndConnectionPointsModifiable); - } - - @Override - public Rectangle getBounds() - { - return new Rectangle(0, 0, 20, height); - } - - @Override - public void render(GeneralGC gc) - { - gc.drawLine(0, height / 2, 10, height / 2); - gc.drawLine(10, 0, 10, height); - double outputHeight = 0; - for (int i = 0; i < outputCount; i++, outputHeight += 10) - gc.drawLine(10, outputHeight, 20, outputHeight); - } - - @Override - public int getConnectedWireEndsCount() - { - return connectedWireEnds.size(); - } - - @Override - public ReadEnd getConnectedWireEnd(int connectionIndex) - { - return connectedWireEnds.get(connectionIndex); - } - - @Override - public Point getWireEndConnectionPoint(int connectionI) - { - return WireEndConnectionPoints.get(connectionI); - } -} \ 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 new file mode 100644 index 00000000..78524b7d --- /dev/null +++ b/LogicUI/src/era/mi/gui/examples/Playground.java @@ -0,0 +1,37 @@ +package era.mi.gui.examples; + +import org.eclipse.swt.SWT; + +import era.mi.gui.LogicUIStandalone; +import era.mi.gui.model.ViewModel; +import era.mi.gui.model.components.GUIAndGate; +import era.mi.gui.model.components.GUINotGate; +import era.mi.gui.model.wires.GUIWire; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; + +public class Playground +{ + private static final int WIRE_DELAY = 10; + private static final int OR_DELAY = 50; + private static final int NOT_DELAY = 50; + + public static void main(String[] args) + { + ViewModel model = new ViewModel(); + LogicUIStandalone ui = new LogicUIStandalone(model); + addComponentsAndWires(ui, model); + ui.run(); + } + + public static void addComponentsAndWires(LogicUIStandalone ui, ViewModel model) + { + GUIAndGate andGate = new GUIAndGate(model); + andGate.moveTo(10, 10); + GUINotGate notGate = new GUINotGate(model); + notGate.moveTo(10, 40); + + new GUIWire(model, andGate.getPins().get(0), notGate.getPins().get(1), new Point(20, 50)); + + ui.getLogicUICanvas().addListener(SWT.KeyDown, e -> notGate.moveTo(150, 10)); + } +} \ 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 deleted file mode 100644 index 405088db..00000000 --- a/LogicUI/src/era/mi/gui/examples/RSLatchGUIExample.java +++ /dev/null @@ -1,62 +0,0 @@ -package era.mi.gui.examples; - -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; -import era.mi.gui.wires.WireConnectionPoint; -import era.mi.logic.timeline.Timeline; -import era.mi.logic.wires.Wire; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; - -public class RSLatchGUIExample -{ - private static final int WIRE_DELAY = 10; - private static final int OR_DELAY = 50; - private static final int NOT_DELAY = 50; - - public static void main(String[] args) - { - Timeline t = new Timeline(11); - t.setTimeFunction(() -> System.currentTimeMillis()); // real time simulation - LogicUIStandalone ui = new LogicUIStandalone(t); - addComponentsAndWires(ui.getLogicUICanvas(), t); - ui.run(); - } - - public static void addComponentsAndWires(LogicUICanvas ui, Timeline t) - { - Wire r = new Wire(t, 1, WIRE_DELAY); - Wire s = new Wire(t, 1, WIRE_DELAY); - Wire t2 = new Wire(t, 1, WIRE_DELAY); - Wire t1 = new Wire(t, 1, WIRE_DELAY); - Wire q = new Wire(t, 1, WIRE_DELAY); - Wire nq = new Wire(t, 1, WIRE_DELAY); - - GUIManualSwitch rIn = ui.addComponent(new GUIManualSwitch(t, r.createReadWriteEnd()), 100, 100); - GUIManualSwitch sIn = ui.addComponent(new GUIManualSwitch(t, s.createReadWriteEnd()), 100, 200); - GUIOrGate or1 = ui.addComponent(new GUIOrGate(t, OR_DELAY, t1.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd()), - 160, 102.5); - GUIOrGate or2 = ui.addComponent(new GUIOrGate(t, OR_DELAY, t2.createReadWriteEnd(), q.createReadOnlyEnd(), s.createReadOnlyEnd()), - 160, 192.5); - GUINotGate not1 = ui.addComponent(new GUINotGate(t, NOT_DELAY, t1.createReadOnlyEnd(), q.createReadWriteEnd()), 200, 107.5); - GUINotGate not2 = ui.addComponent(new GUINotGate(t, NOT_DELAY, t2.createReadOnlyEnd(), nq.createReadWriteEnd()), 200, 197.5); - - WireConnectionPoint p1 = ui.addComponent(new WireConnectionPoint(q, 3), 250, 112.5); - WireConnectionPoint p2 = ui.addComponent(new WireConnectionPoint(nq, 3), 250, 202.5); - WireConnectionPoint o1 = ui.addComponent(new WireConnectionPoint(q, 1), 270, 112.5); - WireConnectionPoint o2 = ui.addComponent(new WireConnectionPoint(nq, 1), 270, 202.5); - - ui.addWire(rIn, 0, or1, 0); - ui.addWire(sIn, 0, or2, 1); - ui.addWire(or1, 2, not1, 0); - ui.addWire(or2, 2, not2, 0); - ui.addWire(not1, 1, p1, 0); - ui.addWire(not2, 1, p2, 0); - ui.addWire(p1, 1, or2, 0, new Point(250, 130), new Point(140, 185), new Point(140, 197.5)); - ui.addWire(p2, 1, or1, 1, new Point(250, 185), new Point(140, 130), new Point(140, 117.5)); - ui.addWire(p1, 2, o1, 0); - ui.addWire(p2, 2, o2, 0); - } -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/ViewModel.java b/LogicUI/src/era/mi/gui/model/ViewModel.java new file mode 100644 index 00000000..7eb55c18 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/ViewModel.java @@ -0,0 +1,110 @@ +package era.mi.gui.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +import era.mi.gui.model.components.GUIComponent; +import era.mi.gui.model.wires.GUIWire; + +public class ViewModel +{ + private final List components; + private final List componentsUnmodifiable; + private final List wires; + private final List wiresUnmodifiable; + + private final List> componentAddedListeners; + private final List> componentRemovedListeners; + private final List> wireAddedListeners; + private final List> wireRemovedListeners; + + public ViewModel() + { + components = new ArrayList<>(); + componentsUnmodifiable = Collections.unmodifiableList(components); + wires = new ArrayList<>(); + wiresUnmodifiable = Collections.unmodifiableList(wires); + + componentAddedListeners = new ArrayList<>(); + componentRemovedListeners = new ArrayList<>(); + wireAddedListeners = new ArrayList<>(); + wireRemovedListeners = new ArrayList<>(); + } + + /** + * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application + * code as it is automatically called in GUIComponent::new. + */ + public void componentCreated(GUIComponent component) + { + if (components.contains(component)) + throw new IllegalStateException("Don't add the same component twice!"); + components.add(component); + callComponentAddedListeners(component); + } + + /** + * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from + * application code as it is automatically called in GUIComponent::destroy. + */ + public void componentDestroyed(GUIComponent component) + { + if (!components.contains(component)) + throw new IllegalStateException("Don't remove the same component twice!"); + components.remove(component); + callComponentRemovedListeners(component); + } + + /** + * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application + * code as it is automatically called in GUIComponent::new. + */ + public void wireCreated(GUIWire wire) + { + if (wires.contains(wire)) + throw new IllegalStateException("Don't add the same wire twice!"); + wires.add(wire); + callWireAddedListeners(wire); + } + + /** + * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from + * application code as it is automatically called in GUIComponent::destroy. + */ + public void wireDestroyed(GUIWire wire) + { + if (!wires.contains(wire)) + throw new IllegalStateException("Don't remove the same wire twice!"); + wires.remove(wire); + callWireRemovedListeners(wire); + } + + public List getComponents() + { + return componentsUnmodifiable; + } + + public List getWires() + { + return wiresUnmodifiable; + } + + // @formatter:off + public void addComponentAddedListener (Consumer listener){componentAddedListeners .add (listener);} + public void addComponentRemovedListener (Consumer listener){componentRemovedListeners.add (listener);} + public void addWireAddedListener (Consumer listener){wireAddedListeners .add (listener);} + public void addWireRemovedListener (Consumer listener){wireRemovedListeners .add (listener);} + + public void removeComponentAddedListener (Consumer listener){componentAddedListeners .remove(listener);} + public void removeComponentRemovedListener(Consumer listener){componentRemovedListeners.remove(listener);} + public void removeWireAddedListener (Consumer listener){wireAddedListeners .remove(listener);} + public void removeWireRemovedListener (Consumer listener){wireRemovedListeners .remove(listener);} + + private void callComponentAddedListeners (GUIComponent c) {componentAddedListeners .forEach(l -> l.accept(c));} + private void callComponentRemovedListeners(GUIComponent c) {componentRemovedListeners.forEach(l -> l.accept(c));} + private void callWireAddedListeners (GUIWire w ) {wireAddedListeners .forEach(l -> l.accept(w));} + private void callWireRemovedListeners (GUIWire w ) {wireRemovedListeners .forEach(l -> l.accept(w));} + // @formatter:on +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/components/GUIAndGate.java b/LogicUI/src/era/mi/gui/model/components/GUIAndGate.java new file mode 100644 index 00000000..4f69d36d --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/components/GUIAndGate.java @@ -0,0 +1,12 @@ +package era.mi.gui.model.components; + +import era.mi.gui.model.ViewModel; + +public class GUIAndGate extends RectangularShapedGUIGate +{ + public GUIAndGate(ViewModel model) + { + super(model, "&", false); + setInputCount(2); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/components/GUIComponent.java b/LogicUI/src/era/mi/gui/model/components/GUIComponent.java new file mode 100644 index 00000000..dc064617 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/components/GUIComponent.java @@ -0,0 +1,118 @@ +package era.mi.gui.model.components; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +import era.mi.gui.model.ViewModel; +import era.mi.gui.model.wires.Pin; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; + +public abstract class GUIComponent +{ + protected final ViewModel model; + private final Rectangle bounds; + private final List pins; + protected final List pinsUnmodifiable; + + private final List> componentChangedListeners; + private final List> componentMovedListeners; + private final List> pinAddedListeners; + private final List> pinRemovedListeners; + + public GUIComponent(ViewModel model) + { + this.model = model; + this.bounds = new Rectangle(0, 0, 0, 0); + this.pins = new ArrayList<>(); + this.pinsUnmodifiable = Collections.unmodifiableList(pins); + + this.componentChangedListeners = new ArrayList<>(); + this.componentMovedListeners = new ArrayList<>(); + this.pinAddedListeners = new ArrayList<>(); + this.pinRemovedListeners = new ArrayList<>(); + + model.componentCreated(this); + } + + public void destroy() + { + pins.forEach(p -> pinRemovedListeners.forEach(l -> l.accept(p))); + model.componentDestroyed(this); + } + + public void moveTo(double x, double y) + { + bounds.x = x; + bounds.y = y; + callComponentMovedListeners(); + } + + /** + * Returns the bounds of this component. Used for calculating which component is clicked. + */ + public Rectangle getBounds() + { + return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height); + } + + /** + * Called when this component is clicked. Absolute coordinates of the click are given. Returns true if this component consumed this + * click. + */ + public boolean clicked(double x, double y) + { + return false; + } + + /** + * Returns a list of pins of this component. + */ + public List getPins() + { + return pinsUnmodifiable; + } + + // @formatter:off + public void addComponentChangedListener (Consumer listener) {componentChangedListeners.add (listener);} + public void addComponentMovedListener (Consumer listener) {componentMovedListeners .add (listener);} + public void addPinAddedListener (Consumer listener) {pinAddedListeners .add (listener);} + public void addPinRemovedListener (Consumer listener) {pinRemovedListeners .add (listener);} + + public void removeComponentChangedListener(Consumer listener) {componentChangedListeners.remove(listener);} + public void removeComponentMovedListener (Consumer listener) {componentMovedListeners .remove(listener);} + public void removePinAddedListener (Consumer listener) {pinAddedListeners .remove(listener);} + public void removePinRemovedListener (Consumer listener) {pinRemovedListeners .remove(listener);} + + protected void callComponentChangedListeners( ) {componentChangedListeners.forEach(l -> l.accept(this));} + private void callComponentMovedListeners ( ) {componentMovedListeners .forEach(l -> l.accept(this));} + private void callPinAddedListeners (Pin p) {pinAddedListeners .forEach(l -> l.accept(p ));} + private void callPinRemovedListeners (Pin p) {pinRemovedListeners .forEach(l -> l.accept(p ));} + // @form atter:on + + /** + * Render this component to the given gc. + */ + public abstract void render(GeneralGC gc, Rectangle visibleRegion); + + protected void setSize(double width, double height) + { + bounds.width = width; + bounds.height = height; + callComponentChangedListeners(); + } + + protected void addPin(Pin pin) + { + pins.add(pin); + callPinAddedListeners(pin); + } + + protected void removePin(Pin pin) + { + pins.remove(pin); + callPinRemovedListeners(pin); + } +} \ 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 new file mode 100644 index 00000000..870a55a4 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/components/GUIManualSwitch.java @@ -0,0 +1,56 @@ +package era.mi.gui.model.components; + +import era.mi.gui.model.ViewModel; +import era.mi.gui.model.wires.Pin; +import era.mi.logic.components.ManualSwitch; +import era.mi.logic.types.BitVectorFormatter; +import era.mi.logic.wires.Wire.ReadEnd; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Font; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; + +public class GUIManualSwitch extends GUIComponent +{ + private static final double width = 20; + private static final double height = 15; + private static final double fontHeight = 5; + + private ManualSwitch logicSwitch; + private ReadEnd end; + + public GUIManualSwitch(ViewModel model) + { + super(model); + setSize(width, height); + addPin(new Pin(this, width, height / 2)); + } + + @Override + public void render(GeneralGC gc, Rectangle visibleRegion) + { + gc.drawRectangle(0, 0, width, height); + String label = BitVectorFormatter.formatValueAsString(end); + Font oldFont = gc.getFont(); + Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle()); + gc.setFont(labelFont); + Point textExtent = gc.textExtent(label); + gc.drawText(label, (width - textExtent.x) / 2, (height - textExtent.y) / 2, true); + gc.setFont(oldFont); + } + + public void setLogicModelBinding(ManualSwitch logicSwitch, ReadEnd end) + { + this.logicSwitch = logicSwitch; + this.end = end; + // TODO when ManualSwitch supports it, add listeners + end.addObserver((i, o) -> callComponentChangedListeners()); + } + + @Override + public boolean clicked(double x, double y) + { + logicSwitch.toggle(); + return true; + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/components/GUINotGate.java b/LogicUI/src/era/mi/gui/model/components/GUINotGate.java new file mode 100644 index 00000000..5f41592b --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/components/GUINotGate.java @@ -0,0 +1,12 @@ +package era.mi.gui.model.components; + +import era.mi.gui.model.ViewModel; + +public class GUINotGate extends RectangularShapedGUIGate +{ + public GUINotGate(ViewModel model) + { + super(model, "1", true); + setInputCount(1); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/components/GUIOrGate.java b/LogicUI/src/era/mi/gui/model/components/GUIOrGate.java new file mode 100644 index 00000000..df64bba1 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/components/GUIOrGate.java @@ -0,0 +1,12 @@ +package era.mi.gui.model.components; + +import era.mi.gui.model.ViewModel; + +public class GUIOrGate extends RectangularShapedGUIGate +{ + public GUIOrGate(ViewModel model) + { + super(model, "\u22651", false);// ">=1" + setInputCount(2); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/components/RectangularShapedGUIGate.java b/LogicUI/src/era/mi/gui/model/components/RectangularShapedGUIGate.java new file mode 100644 index 00000000..c7d0b346 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/components/RectangularShapedGUIGate.java @@ -0,0 +1,74 @@ +package era.mi.gui.model.components; + +import java.util.ArrayList; +import java.util.List; + +import era.mi.gui.model.ViewModel; +import era.mi.gui.model.wires.MovablePin; +import era.mi.gui.model.wires.Pin; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Font; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; + +public class RectangularShapedGUIGate extends GUIComponent +{ + private static final double width = 20; + private static final double pinDistance = 10; + private static final double fontHeight = 5; + private static final double invertedCircleDiam = 3.5; + + private final String label; + private final boolean isInverted; + private final double rectWidth; + + private MovablePin outputPin; + private final List inputPins; + + protected RectangularShapedGUIGate(ViewModel model, String label, boolean isInverted) + { + super(model); + this.label = label; + this.isInverted = isInverted; + this.rectWidth = width - (isInverted ? invertedCircleDiam : 0); + this.outputPin = new MovablePin(this, width, 0); + addPin(outputPin); + this.inputPins = new ArrayList<>(); + setInputCount(1); + } + + protected void setInputCount(int inputCount) + { + int oldInputCount = inputPins.size(); + setSize(width, inputCount * pinDistance); + if (oldInputCount > inputCount) + while (inputPins.size() > inputCount) + removePin(inputPins.get(inputCount)); + else if (oldInputCount < inputCount) + for (int i = oldInputCount; i < inputCount; i++) + { + Pin pin = new Pin(this, 0, pinDistance / 2 + i * pinDistance); + inputPins.add(pin); + addPin(pin); + } + outputPin.setRelPos(width, inputCount * pinDistance / 2); + } + + @Override + public void render(GeneralGC gc, Rectangle visibleRegion) + { + double posX = getBounds().x; + double posY = getBounds().y; + + double height = inputPins.size() * pinDistance; + gc.drawRectangle(posX, posY, rectWidth, height); + Font oldFont = gc.getFont(); + Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle()); + gc.setFont(labelFont); + Point textExtent = gc.textExtent(label); + gc.drawText(label, posX + (rectWidth - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true); + gc.setFont(oldFont); + if (isInverted) + gc.drawOval(posX + rectWidth, posY + (height - invertedCircleDiam) / 2, invertedCircleDiam, invertedCircleDiam); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/wires/GUIWire.java b/LogicUI/src/era/mi/gui/model/wires/GUIWire.java new file mode 100644 index 00000000..c2f03ee5 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/wires/GUIWire.java @@ -0,0 +1,86 @@ +package era.mi.gui.model.wires; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import era.mi.gui.ColorHelper; +import era.mi.gui.model.ViewModel; +import era.mi.logic.types.BitVectorFormatter; +import era.mi.logic.wires.Wire.ReadEnd; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; + +public class GUIWire +{ + private final ViewModel model; + private Pin pin1; + private Pin pin2; + private double[] path; + + private final List> wireChangedListeners; + + private ReadEnd end; + + public GUIWire(ViewModel model, Pin pin1, Pin pin2, Point... path) + { + this.model = model; + this.path = new double[path.length * 2 + 4]; + for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2) + { + this.path[dstI + 0] = path[srcI].x; + this.path[dstI + 1] = path[srcI].y; + } + + this.pin1 = pin1; + this.pin2 = pin2; + + wireChangedListeners = new ArrayList<>(); + + pin1.addPinMovedListener(p -> pin1Moved()); + pin2.addPinMovedListener(p -> pin2Moved()); + pin1Moved(); + pin2Moved(); + + model.wireCreated(this); + } + + private void pin1Moved() + { + Point pos = pin1.getPos(); + this.path[0] = pos.x; + this.path[1] = pos.y; + } + + private void pin2Moved() + { + Point pos = pin2.getPos(); + this.path[this.path.length - 2] = pos.x; + this.path[this.path.length - 1] = pos.y; + } + + public void destroy() + { + model.wireDestroyed(this); + } + + public void render(GeneralGC gc) + { + ColorHelper.executeWithDifferentForeground(gc, BitVectorFormatter.formatAsColor(end), () -> gc.drawPolyline(path)); + } + + public void setLogicModelBinding(ReadEnd end) + { + this.end = end; + end.addObserver((i, o) -> callWireChangedListeners()); + } + + // @formatter:off + public void addWireChangedListener (Consumer listener) {wireChangedListeners.add (listener);} + + public void removeWireChangedListener(Consumer listener) {wireChangedListeners.remove(listener);} + + private void callWireChangedListeners() {wireChangedListeners.forEach(l -> l.accept(this));} + // @formatter:on + +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/wires/MovablePin.java b/LogicUI/src/era/mi/gui/model/wires/MovablePin.java new file mode 100644 index 00000000..673b2578 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/wires/MovablePin.java @@ -0,0 +1,17 @@ +package era.mi.gui.model.wires; + +import era.mi.gui.model.components.GUIComponent; + +public class MovablePin extends Pin +{ + public MovablePin(GUIComponent component, double relX, double relY) + { + super(component, relX, relY); + } + + @Override + public void setRelPos(double relX, double relY) + { + super.setRelPos(relX, relY); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/wires/Pin.java b/LogicUI/src/era/mi/gui/model/wires/Pin.java new file mode 100644 index 00000000..44ea3742 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/wires/Pin.java @@ -0,0 +1,66 @@ +package era.mi.gui.model.wires; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +import era.mi.gui.model.components.GUIComponent; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; + +public class Pin +{ + public final GUIComponent component; + + protected double relX; + protected double relY; + + private final List> pinMovedListeners; + + public Pin(GUIComponent component, double relX, double relY) + { + this.component = component; + this.relX = relX; + this.relY = relY; + + this.pinMovedListeners = new ArrayList<>(); + + component.addComponentMovedListener(c -> callPinMovedListeners()); + } + + public double getRelX() + { + return relX; + } + + public double getRelY() + { + return relY; + } + + public Point getRelPos() + { + return new Point(relX, relY); + } + + public Point getPos() + { + Rectangle componentBounds = component.getBounds(); + return new Point(relX + componentBounds.x, relY + componentBounds.y); + } + + // @formatter:off + public void addPinMovedListener (Consumer listener){pinMovedListeners.add (listener);} + + public void removePinMovedListener(Consumer listener){pinMovedListeners.remove(listener);} + + private void callPinMovedListeners() {pinMovedListeners.forEach(l -> l.accept(this));} + // @formatter:on + + protected void setRelPos(double relX, double relY) + { + this.relX = relX; + this.relY = relY; + callPinMovedListeners(); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/model/wires/WireCrossPoint.java b/LogicUI/src/era/mi/gui/model/wires/WireCrossPoint.java new file mode 100644 index 00000000..ebe30c30 --- /dev/null +++ b/LogicUI/src/era/mi/gui/model/wires/WireCrossPoint.java @@ -0,0 +1,33 @@ +package era.mi.gui.model.wires; + +import era.mi.gui.ColorHelper; +import era.mi.gui.model.ViewModel; +import era.mi.gui.model.components.GUIComponent; +import era.mi.logic.types.BitVectorFormatter; +import era.mi.logic.wires.Wire.ReadEnd; +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; + +public class WireCrossPoint extends GUIComponent +{ + private ReadEnd end; + + public WireCrossPoint(ViewModel model) + { + super(model); + setSize(0, 0); + addPin(new Pin(this, 0, 0)); + } + + @Override + public void render(GeneralGC gc, Rectangle visibleRegion) + { + ColorHelper.executeWithDifferentBackground(gc, BitVectorFormatter.formatAsColor(end), () -> gc.fillOval(-1, -1, 2, 2)); + } + + public void setLogicModelBinding(ReadEnd end) + { + this.end = end; + end.addObserver((i, o) -> callComponentChangedListeners()); + } +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/modeladapter/ViewLogicModelAdapter.java b/LogicUI/src/era/mi/gui/modeladapter/ViewLogicModelAdapter.java new file mode 100644 index 00000000..f005a80b --- /dev/null +++ b/LogicUI/src/era/mi/gui/modeladapter/ViewLogicModelAdapter.java @@ -0,0 +1,6 @@ +package era.mi.gui.modeladapter; + +public class ViewLogicModelAdapter +{ + +} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/wires/GUIWire.java b/LogicUI/src/era/mi/gui/wires/GUIWire.java deleted file mode 100644 index 31285bba..00000000 --- a/LogicUI/src/era/mi/gui/wires/GUIWire.java +++ /dev/null @@ -1,67 +0,0 @@ -package era.mi.gui.wires; - -import java.util.Objects; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Color; - -import era.mi.gui.components.BasicGUIComponent; -import era.mi.logic.types.Bit; -import era.mi.logic.wires.Wire; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; - -public class GUIWire -{ - private final Wire wire; - private final double[] path; - - public GUIWire(Runnable redraw, BasicGUIComponent component1, int component1ConnectionIndex, Point component1Pos, - BasicGUIComponent component2, int component2ConnectionIndex, Point component2Pos, Point... path) - { - this.wire = component1.getConnectedWireEnd(component1ConnectionIndex).getWire(); - if (!Objects.equals(wire, component2.getConnectedWireEnd(component2ConnectionIndex).getWire())) - throw new IllegalArgumentException("Given connection points are not connected!"); - this.path = new double[path.length * 2 + 4]; - Point component1ConnectionPoint = component1.getWireEndConnectionPoint(component1ConnectionIndex); - this.path[0] = component1Pos.x + component1ConnectionPoint.x; - this.path[1] = component1Pos.y + component1ConnectionPoint.y; - for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2) - { - this.path[dstI + 0] = path[srcI].x; - this.path[dstI + 1] = path[srcI].y; - } - Point component2ConnectionPoint = component2.getWireEndConnectionPoint(component2ConnectionIndex); - this.path[this.path.length - 2] = component2Pos.x + component2ConnectionPoint.x; - this.path[this.path.length - 1] = component2Pos.y + component2ConnectionPoint.y; - - wire.createReadOnlyEnd().addObserver((initiator, oldValues) -> redraw.run()); - } - - public void render(GeneralGC gc) - { - Color oldFG = gc.getForeground(); - if (wire.length == 1) - gc.setForeground(gc.getDevice().getSystemColor(getSWTColorConstantForBit(wire.getValue()))); - gc.drawPolyline(path); - gc.setForeground(oldFG); - } - - public static int getSWTColorConstantForBit(Bit bit) - { - switch (bit) - { - case ONE: - return SWT.COLOR_GREEN; - case ZERO: - return SWT.COLOR_BLUE; - case Z: - return SWT.COLOR_BLACK; - case U: - case X: - return SWT.COLOR_RED; - default: - throw new IllegalArgumentException("Unknown enum constant: " + bit); - } - } -} \ No newline at end of file diff --git a/LogicUI/src/era/mi/gui/wires/WireConnectionPoint.java b/LogicUI/src/era/mi/gui/wires/WireConnectionPoint.java deleted file mode 100644 index 3ccc1b4b..00000000 --- a/LogicUI/src/era/mi/gui/wires/WireConnectionPoint.java +++ /dev/null @@ -1,65 +0,0 @@ -package era.mi.gui.wires; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.eclipse.swt.graphics.Color; - -import era.mi.gui.components.BasicGUIComponent; -import era.mi.logic.wires.Wire; -import era.mi.logic.wires.Wire.ReadEnd; -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; - -public class WireConnectionPoint implements BasicGUIComponent -{ - private final Wire wire; - private final List wireEnds; - private final int wiresCrossing; - - public WireConnectionPoint(Wire wire, int wiresCrossing) - { - this.wire = wire; - List wireEndsModifiable = new ArrayList<>(); - for (int i = 0; i < wiresCrossing; i++) - wireEndsModifiable.add(wire.createReadOnlyEnd()); - wireEnds = Collections.unmodifiableList(wireEndsModifiable); - this.wiresCrossing = wiresCrossing; - } - - @Override - public void render(GeneralGC gc) - { - Color oldBG = gc.getBackground(); - if (wire.length == 1) - gc.setBackground(gc.getDevice().getSystemColor(GUIWire.getSWTColorConstantForBit(wire.getValue()))); - gc.fillOval(-1, -1, 2, 2); - gc.setBackground(oldBG); - } - - @Override - public Rectangle getBounds() - { - return new Rectangle(0, 0, 0, 0); - } - - @Override - public int getConnectedWireEndsCount() - { - return wiresCrossing; - } - - @Override - public ReadEnd getConnectedWireEnd(int connectionIndex) - { - return wireEnds.get(connectionIndex); - } - - @Override - public Point getWireEndConnectionPoint(int connectionIndex) - { - return new Point(0, 0); - } -} \ No newline at end of file diff --git a/SampleERCP/src/sampleercp/parts/LogicUIPart.java b/SampleERCP/src/sampleercp/parts/LogicUIPart.java index ee1d7759..fa18e2d3 100644 --- a/SampleERCP/src/sampleercp/parts/LogicUIPart.java +++ b/SampleERCP/src/sampleercp/parts/LogicUIPart.java @@ -8,8 +8,7 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import era.mi.gui.LogicUICanvas; -import era.mi.gui.examples.RSLatchGUIExample; -import era.mi.logic.timeline.Timeline; +import era.mi.gui.model.ViewModel; import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput; public class LogicUIPart @@ -20,41 +19,41 @@ public class LogicUIPart @PostConstruct public void create(Composite parent) { - Timeline timeline = new Timeline(11); - LogicUICanvas ui = new LogicUICanvas(parent, SWT.NONE); - RSLatchGUIExample.addComponentsAndWires(ui, timeline); + ViewModel model = new ViewModel(); + LogicUICanvas ui = new LogicUICanvas(parent, SWT.NONE, model); +// RSLatchGUIExample.addComponentsAndWires(ui, timeline); ui.addTransformListener((x, y, z) -> part.setDirty(z < 1)); ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui); userInput.buttonDrag = 3; userInput.buttonZoom = 2; userInput.enableUserInput(); - Thread simulationThread = new Thread(() -> - { - // TODO find a better condition - while (!ui.isDisposed()) - { - // 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(); - }); +// Thread simulationThread = new Thread(() -> +// { +// // TODO find a better condition +// while (!ui.isDisposed()) +// { +// // always execute to keep timeline from "hanging behind" for too long +// timeline.executeUpTo(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(); +// }); } } \ No newline at end of file diff --git a/era.mi/src/era/mi/logic/types/BitVectorFormatter.java b/era.mi/src/era/mi/logic/types/BitVectorFormatter.java new file mode 100644 index 00000000..6dab1d7b --- /dev/null +++ b/era.mi/src/era/mi/logic/types/BitVectorFormatter.java @@ -0,0 +1,53 @@ +package era.mi.logic.types; + +import era.mi.logic.types.ColorDefinition.BuiltInColor; +import era.mi.logic.wires.Wire.ReadEnd; + +public class BitVectorFormatter +{ + public static String formatValueAsString(ReadEnd end) + { + return formatAsString(end == null ? null : end.getValues()); + } + + public static String formatAsString(BitVector bitVector) + { + if (bitVector == null) + return "null"; + else + return bitVector.toString(); + } + + public static ColorDefinition formatAsColor(ReadEnd end) + { + return formatAsColor(end == null ? null : end.getValues()); + } + + public static ColorDefinition formatAsColor(BitVector bitVector) + { + // TODO maybe find a color assignment for multiple-bit bit vectors? + if (bitVector == null || bitVector.length() != 1) + return new ColorDefinition(BuiltInColor.COLOR_BLACK); + else + switch (bitVector.getBit(0)) + { + case ONE: + return new ColorDefinition(BuiltInColor.COLOR_GREEN); + case U: + return new ColorDefinition(BuiltInColor.COLOR_CYAN); + case X: + return new ColorDefinition(BuiltInColor.COLOR_RED); + case Z: + return new ColorDefinition(BuiltInColor.COLOR_YELLOW); + case ZERO: + return new ColorDefinition(BuiltInColor.COLOR_GRAY); + default: + throw new IllegalArgumentException("Unknown enum constant: " + bitVector.getBit(0)); + } + } + + private BitVectorFormatter() + { + throw new UnsupportedOperationException("No BitVectorFormatter instances"); + } +} \ No newline at end of file diff --git a/era.mi/src/era/mi/logic/types/ColorDefinition.java b/era.mi/src/era/mi/logic/types/ColorDefinition.java new file mode 100644 index 00000000..b9e851fd --- /dev/null +++ b/era.mi/src/era/mi/logic/types/ColorDefinition.java @@ -0,0 +1,54 @@ +package era.mi.logic.types; + +/** + * A way to define a color with the possibility to use colors built into the system (called "system colors" in SWT). + *

+ * A {@link ColorDefinition} is defined either by a {@link BuiltInColor} constant, in which case r==g==b==-1, or by red / green + * / blue components, in which case builtInColor==null + */ +public class ColorDefinition +{ + /** + * The built-in color constant defining this color. + */ + public final ColorDefinition.BuiltInColor builtInColor; + /** + * The red color component defining this color. + */ + public final int r; + /** + * The green color component defining this color. + */ + public final int g; + /** + * The blue color component defining this color. + */ + public final int b; + + public ColorDefinition(ColorDefinition.BuiltInColor col) + { + if (col == null) + throw new IllegalArgumentException("Illegal built-in color: " + col); + this.builtInColor = col; + this.r = -1; + this.g = -1; + this.b = -1; + } + + public ColorDefinition(int r, int g, int b) + { + if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) + throw new IllegalArgumentException("Illegal color components: r=" + r + "; g=" + g + "; b=" + b); + this.builtInColor = null; + this.r = r; + this.g = g; + this.b = b; + } + + public static enum BuiltInColor + { + COLOR_WHITE, COLOR_BLACK, COLOR_RED, COLOR_DARK_RED, COLOR_GREEN, COLOR_DARK_GREEN, COLOR_YELLOW, COLOR_DARK_YELLOW, COLOR_BLUE, + COLOR_DARK_BLUE, COLOR_MAGENTA, COLOR_DARK_MAGENTA, COLOR_CYAN, COLOR_DARK_CYAN, COLOR_GRAY, COLOR_DARK_GRAY; + } + +} \ No newline at end of file