From: Daniel Kirschten Date: Tue, 25 Jun 2019 09:23:43 +0000 (+0200) Subject: Removed visitor pattern used for one test only X-Git-Url: https://mograsim.net/gitweb/?a=commitdiff_plain;h=81d89ebec7f67ddcfda22018d5dbfebe64fbe11a;p=Mograsim.git Removed visitor pattern used for one test only --- diff --git a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java index 6c7be71d..d8934ced 100644 --- a/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java +++ b/net.mograsim.logic.ui.am2900/test/net/mograsim/logic/ui/am2900/TestableAm2901Impl.java @@ -5,7 +5,9 @@ import static org.junit.jupiter.api.Assertions.fail; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.Objects; +import java.util.Queue; import java.util.Set; import java.util.TreeSet; @@ -15,18 +17,14 @@ import net.mograsim.logic.core.timeline.Timeline; import net.mograsim.logic.core.types.Bit; import net.mograsim.logic.core.types.BitVector; import net.mograsim.logic.core.types.BitVector.BitVectorMutator; -import net.mograsim.logic.ui.model.ModelVisitor; import net.mograsim.logic.ui.model.ViewModel; import net.mograsim.logic.ui.model.ViewModelModifiable; import net.mograsim.logic.ui.model.components.GUIBitDisplay; import net.mograsim.logic.ui.model.components.GUIComponent; import net.mograsim.logic.ui.model.components.GUIManualSwitch; -import net.mograsim.logic.ui.model.components.SimpleRectangularGUIGate; -import net.mograsim.logic.ui.model.components.SimpleRectangularSubmodelComponent; -import net.mograsim.logic.ui.model.components.SubmodelInterface; +import net.mograsim.logic.ui.model.components.SubmodelComponent; import net.mograsim.logic.ui.model.components.mi.nandbased.am2901.GUIAm2901; import net.mograsim.logic.ui.model.wires.GUIWire; -import net.mograsim.logic.ui.model.wires.WireCrossPoint; import net.mograsim.logic.ui.modeladapter.LogicModelParameters; import net.mograsim.logic.ui.modeladapter.ViewLogicModelAdapter; @@ -45,9 +43,6 @@ public class TestableAm2901Impl implements TestableAm2901 private BitDisplay F_0, Cn_4, OVR, F3; private BitDisplay ORAMn, ORAMn_3, OQn, OQn_3; - private Set allWires; - private Set allComponents; - private Set wireDebugChangeSet; private boolean debugWires = false; public int debugEventThreshold = 10_000; @@ -136,11 +131,18 @@ public class TestableAm2901Impl implements TestableAm2901 C.switchOff(); // Debug code - allWires = new HashSet<>(); - allComponents = new HashSet<>(); - ModelAccumulator accumulator = new ModelAccumulator(); - accumulator.visit(viewModel); - allWires.forEach(w -> w.addRedrawListener(() -> + HashSet wiresIncludingSubmodels = new HashSet<>(); + Queue modelsToIterate = new LinkedList<>(); + modelsToIterate.add(viewModel); + while (modelsToIterate.size() > 0) + { + ViewModel model = modelsToIterate.poll(); + wiresIncludingSubmodels.addAll(model.getWires()); + for (GUIComponent comp : model.getComponents()) + if (comp instanceof SubmodelComponent) + modelsToIterate.offer(((SubmodelComponent) comp).submodel); + } + wiresIncludingSubmodels.forEach(w -> w.addRedrawListener(() -> { if (debugWires) { @@ -345,58 +347,4 @@ public class TestableAm2901Impl implements TestableAm2901 } return mutator.toBitVector(); } - - class ModelAccumulator implements ModelVisitor - { - @Override - public void visit(GUIWire w) - { - allWires.add(w); - } - - @Override - public void visit(SimpleRectangularGUIGate simpleRectangularGUIGate) - { - allComponents.add(simpleRectangularGUIGate); - } - - @Override - public void visit(SimpleRectangularSubmodelComponent simpleRectangularSubmodelComponent) - { - allComponents.add(simpleRectangularSubmodelComponent); - simpleRectangularSubmodelComponent.getWires().forEach(w -> w.accept(this)); - simpleRectangularSubmodelComponent.getComponents().forEach(w -> w.accept(this)); - } - - @Override - public void visit(WireCrossPoint wireCrossPoint) - { - // nothing - } - - @Override - public void visit(GUIBitDisplay guiBitDisplay) - { - allComponents.add(guiBitDisplay); - } - - @Override - public void visit(GUIManualSwitch guiManualSwitch) - { - allComponents.add(guiManualSwitch); - } - - @Override - public void visit(SubmodelInterface submodelInterface) - { - // nothing - } - - @Override - public void visit(ViewModel viewModel) - { - viewModel.getWires().forEach(w -> w.accept(this)); - viewModel.getComponents().forEach(w -> w.accept(this)); - } - } } diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/ModelVisitor.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/ModelVisitor.java deleted file mode 100644 index a11d2fc6..00000000 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/ModelVisitor.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.mograsim.logic.ui.model; - -import net.mograsim.logic.ui.model.components.GUIBitDisplay; -import net.mograsim.logic.ui.model.components.GUIManualSwitch; -import net.mograsim.logic.ui.model.components.SimpleRectangularGUIGate; -import net.mograsim.logic.ui.model.components.SimpleRectangularSubmodelComponent; -import net.mograsim.logic.ui.model.components.SubmodelInterface; -import net.mograsim.logic.ui.model.wires.GUIWire; -import net.mograsim.logic.ui.model.wires.WireCrossPoint; - -public interface ModelVisitor -{ - void visit(GUIWire w); - - void visit(SimpleRectangularGUIGate simpleRectangularGUIGate); - - void visit(SimpleRectangularSubmodelComponent simpleRectangularSubmodelComponent); - - void visit(WireCrossPoint wireCrossPoint); - - void visit(GUIBitDisplay guiBitDisplay); - - void visit(GUIManualSwitch guiManualSwitch); - - void visit(SubmodelInterface submodelInterface); - - void visit(ViewModel viewModel); -} diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/ViewModel.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/ViewModel.java index 445810a0..1f69acf3 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/ViewModel.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/ViewModel.java @@ -8,7 +8,7 @@ import java.util.function.Consumer; import net.mograsim.logic.ui.model.components.GUIComponent; import net.mograsim.logic.ui.model.wires.GUIWire; -public class ViewModel implements Visitable +public class ViewModel { private final List components; private final List componentsUnmodifiable; @@ -105,12 +105,6 @@ public class ViewModel implements Visitable return wiresUnmodifiable; } - @Override - public void accept(ModelVisitor mv) - { - mv.visit(this); - } - // @formatter:off public void addComponentAddedListener (Consumer listener) {componentAddedListeners .add (listener);} public void addComponentRemovedListener (Consumer listener) {componentRemovedListeners.add (listener);} diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/Visitable.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/Visitable.java deleted file mode 100644 index 3cbe9c5a..00000000 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/Visitable.java +++ /dev/null @@ -1,6 +0,0 @@ -package net.mograsim.logic.ui.model; - -public interface Visitable -{ - void accept(ModelVisitor mv); -} diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIBitDisplay.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIBitDisplay.java index c4d8df38..82b3bbba 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIBitDisplay.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIBitDisplay.java @@ -8,7 +8,6 @@ import net.mograsim.logic.core.LogicObservable; import net.mograsim.logic.core.LogicObserver; import net.mograsim.logic.core.components.BitDisplay; import net.mograsim.logic.core.types.BitVectorFormatter; -import net.mograsim.logic.ui.model.ModelVisitor; import net.mograsim.logic.ui.model.ViewModelModifiable; import net.mograsim.logic.ui.model.wires.Pin; import net.mograsim.logic.ui.modeladapter.ViewLogicModelAdapter; @@ -77,12 +76,6 @@ public class GUIBitDisplay extends GUIComponent return inputPin; } - @Override - public void accept(ModelVisitor mv) - { - mv.visit(this); - } - static { ViewLogicModelAdapter.addComponentAdapter(new BitDisplayAdapter()); diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIComponent.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIComponent.java index 2c8324af..6e566c48 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIComponent.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIComponent.java @@ -12,7 +12,6 @@ import java.util.function.Supplier; import net.haspamelodica.swt.helper.gcs.GeneralGC; import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; import net.mograsim.logic.ui.model.ViewModelModifiable; -import net.mograsim.logic.ui.model.Visitable; import net.mograsim.logic.ui.model.wires.Pin; /** @@ -21,7 +20,7 @@ import net.mograsim.logic.ui.model.wires.Pin; * * @author Daniel Kirschten */ -public abstract class GUIComponent implements Visitable +public abstract class GUIComponent { /** * The model this component is a part of. diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIManualSwitch.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIManualSwitch.java index 563f9284..43c71990 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIManualSwitch.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIManualSwitch.java @@ -9,7 +9,6 @@ import net.mograsim.logic.core.LogicObserver; import net.mograsim.logic.core.components.ManualSwitch; import net.mograsim.logic.core.types.BitVectorFormatter; import net.mograsim.logic.core.wires.Wire.ReadEnd; -import net.mograsim.logic.ui.model.ModelVisitor; import net.mograsim.logic.ui.model.ViewModelModifiable; import net.mograsim.logic.ui.model.wires.Pin; import net.mograsim.logic.ui.modeladapter.ViewLogicModelAdapter; @@ -90,12 +89,6 @@ public class GUIManualSwitch extends GUIComponent return outputPin; } - @Override - public void accept(ModelVisitor mv) - { - mv.visit(this); - } - static { ViewLogicModelAdapter.addComponentAdapter(new ManualSwitchAdapter()); diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SimpleRectangularGUIGate.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SimpleRectangularGUIGate.java index 7beafe12..d263f6de 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SimpleRectangularGUIGate.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SimpleRectangularGUIGate.java @@ -8,7 +8,6 @@ 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; -import net.mograsim.logic.ui.model.ModelVisitor; import net.mograsim.logic.ui.model.ViewModelModifiable; import net.mograsim.logic.ui.model.wires.MovablePin; import net.mograsim.logic.ui.model.wires.Pin; @@ -83,10 +82,4 @@ public class SimpleRectangularGUIGate extends GUIComponent m.put(kLogicWidth, logicWidth); return m; } - - @Override - public void accept(ModelVisitor mv) - { - mv.visit(this); - } } \ No newline at end of file diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SimpleRectangularSubmodelComponent.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SimpleRectangularSubmodelComponent.java index 2fd94c6a..59d800a4 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SimpleRectangularSubmodelComponent.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SimpleRectangularSubmodelComponent.java @@ -12,7 +12,6 @@ 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; -import net.mograsim.logic.ui.model.ModelVisitor; import net.mograsim.logic.ui.model.ViewModelModifiable; import net.mograsim.logic.ui.model.wires.MovablePin; import net.mograsim.logic.ui.model.wires.Pin; @@ -156,10 +155,4 @@ public class SimpleRectangularSubmodelComponent extends SubmodelComponent throw new UnsupportedOperationException( "Can't set the size of a SimpleRectangularSubmodelComponent directly, call setInputPins / setOutputPins instead"); } - - @Override - public void accept(ModelVisitor mv) - { - mv.visit(this); - } } \ No newline at end of file diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelInterface.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelInterface.java index d08c937f..8f448a80 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelInterface.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelInterface.java @@ -2,7 +2,6 @@ package net.mograsim.logic.ui.model.components; import net.haspamelodica.swt.helper.gcs.GeneralGC; import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; -import net.mograsim.logic.ui.model.ModelVisitor; import net.mograsim.logic.ui.model.ViewModelModifiable; public class SubmodelInterface extends GUIComponent @@ -16,10 +15,4 @@ public class SubmodelInterface extends GUIComponent public void render(GeneralGC gc, Rectangle visibleRegion) {// nothing to do here } - - @Override - public void accept(ModelVisitor mv) - { - mv.visit(this); - } } \ No newline at end of file diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/GUIWire.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/GUIWire.java index a79054c9..08b1d42e 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/GUIWire.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/GUIWire.java @@ -1,334 +1,326 @@ -package net.mograsim.logic.ui.model.wires; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.swt.SWT; - -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Point; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; -import net.mograsim.logic.core.LogicObserver; -import net.mograsim.logic.core.types.BitVectorFormatter; -import net.mograsim.logic.core.wires.Wire.ReadEnd; -import net.mograsim.logic.ui.ColorHelper; -import net.mograsim.logic.ui.model.ModelVisitor; -import net.mograsim.logic.ui.model.ViewModelModifiable; -import net.mograsim.logic.ui.model.Visitable; - -/** - * A wire connecting exactly two {@link Pin}s. - * - * @author Daniel Kirschten - */ -public class GUIWire implements Visitable -{ - /** - * The model this wire is a part of. - */ - private final ViewModelModifiable model; - /** - * The logical width of this wire. Is equal to the logical with of {@link #pin1} and {@link #pin2}. - */ - public final int logicWidth; - /** - * The {@link Pin} on one side of this wire, usually the signal source. - */ - private Pin pin1; - /** - * The {@link Pin} on one side of this wire, usually the signal target. - */ - private Pin pin2; - /** - * The user-defined path between {@link #pin1} and {@link #pin2}.
- * Special cases: null means "choose an interpolation as fits", and an empty array means "direct connection without any - * interpolation". - */ - private Point[] path; - /** - * The bounds of this wire, excluding line width (and line joins, if the line join is {@link SWT#JOIN_MITER}) - */ - private final Rectangle bounds; - /** - * The effective path of this wire, including automatic interpolation and the position of both {@link Pin}s. Is never null. - */ - private double[] effectivePath; - - private final List redrawListeners; - - /** - * A LogicObserver calling redrawListeners. Used for logic model bindings. - */ - private final LogicObserver logicObs; - /** - * A ReadEnd of the logic wire this GUI wire currently is bound to. - */ - private ReadEnd end; - - // creation and destruction - - /** - * Creates a new {@link GUIWire} with automatic interpolation. - * - * @author Daniel Kirschten - */ - public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, WireCrossPoint pin2) - { - this(model, pin1, pin2, (Point[]) null); - } - - /** - * Creates a new {@link GUIWire} with automatic interpolation. - * - * @author Daniel Kirschten - */ - public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, Pin pin2) - { - this(model, pin1, pin2, (Point[]) null); - } - - /** - * Creates a new {@link GUIWire} with automatic interpolation. - * - * @author Daniel Kirschten - */ - public GUIWire(ViewModelModifiable model, Pin pin1, WireCrossPoint pin2) - { - this(model, pin1, pin2, (Point[]) null); - } - - /** - * Creates a new {@link GUIWire} with automatic interpolation. - * - * @author Daniel Kirschten - */ - public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2) - { - this(model, pin1, pin2, (Point[]) null); - } - - /** - * Creates a new {@link GUIWire} without automatic interpolation. - * - * @author Daniel Kirschten - */ - public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, WireCrossPoint pin2, Point... path) - { - this(model, pin1.getPin(), pin2.getPin(), path); - } - - /** - * Creates a new {@link GUIWire} without automatic interpolation. - * - * @author Daniel Kirschten - */ - public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, Pin pin2, Point... path) - { - this(model, pin1.getPin(), pin2, path); - } - - /** - * Creates a new {@link GUIWire} without automatic interpolation. - * - * @author Daniel Kirschten - */ - public GUIWire(ViewModelModifiable model, Pin pin1, WireCrossPoint pin2, Point... path) - { - this(model, pin1, pin2.getPin(), path); - } - - /** - * Creates a new {@link GUIWire} without automatic interpolation. - * - * @author Daniel Kirschten - */ - public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2, Point... path) - { - logicObs = (i) -> callRedrawListeners(); - this.model = model; - this.logicWidth = pin1.logicWidth; - if (pin2.logicWidth != pin1.logicWidth) - throw new IllegalArgumentException("Can't connect pins of different logic width"); - - this.pin1 = pin1; - this.pin2 = pin2; - - this.path = path == null ? null : Arrays.copyOf(path, path.length); - this.bounds = new Rectangle(0, 0, -1, -1); - - redrawListeners = new ArrayList<>(); - - pin1.addPinMovedListener(p -> pinMoved()); - pin2.addPinMovedListener(p -> pinMoved()); - - recalculateEffectivePath(); - - model.wireCreated(this); - } - - /** - * Destroys this wire. This method implicitly calls {@link ViewModelModifiable#wireDestroyed(GUIWire) wireDestroyed()} for the model - * this component is a part of. - * - * @author Daniel Kirschten - */ - public void destroy() - { - model.wireDestroyed(this); - } - - // pins - - /** - * Returns the {@link Pin} on one side of this wire, usually the signal source. - * - * @author Daniel Kirschten - */ - public Pin getPin1() - { - return pin1; - } - - /** - * Returns the {@link Pin} on one side of this wire, usually the signal target. - * - * @author Daniel Kirschten - */ - public Pin getPin2() - { - return pin2; - } - - /** - * Called when {@link #pin1} or {@link #pin2} were moved. - * - * @author Daniel Kirschten - */ - private void pinMoved() - { - recalculateEffectivePath(); - callRedrawListeners(); - } - - // "graphical" operations - - /** - * Recalculates {@link #effectivePath} "from scratch". Also updates {@link #bounds}. - * - * @author Daniel Kirschten - */ - private void recalculateEffectivePath() - { - Point pos1 = pin1.getPos(), pos2 = pin2.getPos(); - - double boundsX1 = Math.min(pos1.x, pos2.x); - double boundsY1 = Math.min(pos1.y, pos2.y); - double boundsX2 = Math.max(pos1.x, pos2.x); - double boundsY2 = Math.max(pos1.y, pos2.y); - - if (path == null) - effectivePath = new double[] { pos1.x, pos1.y, (pos1.x + pos2.x) / 2, pos1.y, (pos1.x + pos2.x) / 2, pos2.y, pos2.x, pos2.y }; - else - { - effectivePath = new double[path.length * 2 + 4]; - effectivePath[0] = pos1.x; - effectivePath[1] = pos1.y; - for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2) - { - double pathX = path[srcI].x; - double pathY = path[srcI].y; - effectivePath[dstI + 0] = pathX; - effectivePath[dstI + 1] = pathY; - if (pathX < boundsX1) - boundsX1 = pathX; - if (pathX > boundsX2) - boundsX2 = pathX; - if (pathY < boundsY1) - boundsY1 = pathY; - if (pathY > boundsY2) - boundsY2 = pathY; - } - effectivePath[effectivePath.length - 2] = pos2.x; - effectivePath[effectivePath.length - 1] = pos2.y; - } - - bounds.x = boundsX1; - bounds.y = boundsY1; - bounds.width = boundsX2 - boundsX1; - bounds.height = boundsY2 - boundsY1; - } - - /** - * Returns the bounds of this wire, excluding line width (and line joins, if the line join is {@link SWT#JOIN_MITER}) - * - * @author Daniel Kirschten - */ - public Rectangle getBounds() - { - return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height); - } - - /** - * Render this wire to the given gc, in absoulute coordinates. - * - * @author Daniel Kirschten - */ - public void render(GeneralGC gc) - { - ColorHelper.executeWithDifferentForeground(gc, BitVectorFormatter.formatAsColor(end), () -> gc.drawPolyline(effectivePath)); - } - - /** - * The user-defined path between {@link #pin1} and {@link #pin2}. Note that this is not neccessarily equal to the effective path drawn - * in {@link #render(GeneralGC)}.
- * Special cases: null means "choose an interpolation as fits", and an empty array means "direct connection without any - * interpolation". - * - * @author Daniel Kirschten - */ - public Point[] getPath() - { - return path == null ? null : path.clone(); - } - - // logic model binding - - /** - * Binds this {@link GUIWire} to the given {@link ReadEnd}: The color of this {@link GUIWire} will now depend on the state of the given - * {@link ReadEnd}, and further changes of the given {@link ReadEnd} will result in readrawListeners being called.
- * The argument can be null, in which case the old binding is stopped. - * - * @author Daniel Kirschten - */ - public void setLogicModelBinding(ReadEnd end) - { - if (this.end != null) - this.end.deregisterObserver(logicObs); - this.end = end; - if (end != null) - end.registerObserver(logicObs); - } - - // listeners - - // @formatter:off - public void addRedrawListener (Runnable listener) {redrawListeners .add (listener);} - - public void removeRedrawListener(Runnable listener) {redrawListeners .remove(listener);} - - private void callRedrawListeners() {redrawListeners.forEach(l -> l.run());} - // @formatter:on - - @Override - public String toString() - { - return "GUIWire [" + pin1 + "---" + pin2 + ", value=" + (end == null ? "null" : end.getValues()) + "]"; - } - - @Override - public void accept(ModelVisitor mv) - { - mv.visit(this); - } +package net.mograsim.logic.ui.model.wires; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.swt.SWT; + +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Point; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; +import net.mograsim.logic.core.LogicObserver; +import net.mograsim.logic.core.types.BitVectorFormatter; +import net.mograsim.logic.core.wires.Wire.ReadEnd; +import net.mograsim.logic.ui.ColorHelper; +import net.mograsim.logic.ui.model.ViewModelModifiable; + +/** + * A wire connecting exactly two {@link Pin}s. + * + * @author Daniel Kirschten + */ +public class GUIWire +{ + /** + * The model this wire is a part of. + */ + private final ViewModelModifiable model; + /** + * The logical width of this wire. Is equal to the logical with of {@link #pin1} and {@link #pin2}. + */ + public final int logicWidth; + /** + * The {@link Pin} on one side of this wire, usually the signal source. + */ + private Pin pin1; + /** + * The {@link Pin} on one side of this wire, usually the signal target. + */ + private Pin pin2; + /** + * The user-defined path between {@link #pin1} and {@link #pin2}.
+ * Special cases: null means "choose an interpolation as fits", and an empty array means "direct connection without any + * interpolation". + */ + private Point[] path; + /** + * The bounds of this wire, excluding line width (and line joins, if the line join is {@link SWT#JOIN_MITER}) + */ + private final Rectangle bounds; + /** + * The effective path of this wire, including automatic interpolation and the position of both {@link Pin}s. Is never null. + */ + private double[] effectivePath; + + private final List redrawListeners; + + /** + * A LogicObserver calling redrawListeners. Used for logic model bindings. + */ + private final LogicObserver logicObs; + /** + * A ReadEnd of the logic wire this GUI wire currently is bound to. + */ + private ReadEnd end; + + // creation and destruction + + /** + * Creates a new {@link GUIWire} with automatic interpolation. + * + * @author Daniel Kirschten + */ + public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, WireCrossPoint pin2) + { + this(model, pin1, pin2, (Point[]) null); + } + + /** + * Creates a new {@link GUIWire} with automatic interpolation. + * + * @author Daniel Kirschten + */ + public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, Pin pin2) + { + this(model, pin1, pin2, (Point[]) null); + } + + /** + * Creates a new {@link GUIWire} with automatic interpolation. + * + * @author Daniel Kirschten + */ + public GUIWire(ViewModelModifiable model, Pin pin1, WireCrossPoint pin2) + { + this(model, pin1, pin2, (Point[]) null); + } + + /** + * Creates a new {@link GUIWire} with automatic interpolation. + * + * @author Daniel Kirschten + */ + public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2) + { + this(model, pin1, pin2, (Point[]) null); + } + + /** + * Creates a new {@link GUIWire} without automatic interpolation. + * + * @author Daniel Kirschten + */ + public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, WireCrossPoint pin2, Point... path) + { + this(model, pin1.getPin(), pin2.getPin(), path); + } + + /** + * Creates a new {@link GUIWire} without automatic interpolation. + * + * @author Daniel Kirschten + */ + public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, Pin pin2, Point... path) + { + this(model, pin1.getPin(), pin2, path); + } + + /** + * Creates a new {@link GUIWire} without automatic interpolation. + * + * @author Daniel Kirschten + */ + public GUIWire(ViewModelModifiable model, Pin pin1, WireCrossPoint pin2, Point... path) + { + this(model, pin1, pin2.getPin(), path); + } + + /** + * Creates a new {@link GUIWire} without automatic interpolation. + * + * @author Daniel Kirschten + */ + public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2, Point... path) + { + logicObs = (i) -> callRedrawListeners(); + this.model = model; + this.logicWidth = pin1.logicWidth; + if (pin2.logicWidth != pin1.logicWidth) + throw new IllegalArgumentException("Can't connect pins of different logic width"); + + this.pin1 = pin1; + this.pin2 = pin2; + + this.path = path == null ? null : Arrays.copyOf(path, path.length); + this.bounds = new Rectangle(0, 0, -1, -1); + + redrawListeners = new ArrayList<>(); + + pin1.addPinMovedListener(p -> pinMoved()); + pin2.addPinMovedListener(p -> pinMoved()); + + recalculateEffectivePath(); + + model.wireCreated(this); + } + + /** + * Destroys this wire. This method implicitly calls {@link ViewModelModifiable#wireDestroyed(GUIWire) wireDestroyed()} for the model + * this component is a part of. + * + * @author Daniel Kirschten + */ + public void destroy() + { + model.wireDestroyed(this); + } + + // pins + + /** + * Returns the {@link Pin} on one side of this wire, usually the signal source. + * + * @author Daniel Kirschten + */ + public Pin getPin1() + { + return pin1; + } + + /** + * Returns the {@link Pin} on one side of this wire, usually the signal target. + * + * @author Daniel Kirschten + */ + public Pin getPin2() + { + return pin2; + } + + /** + * Called when {@link #pin1} or {@link #pin2} were moved. + * + * @author Daniel Kirschten + */ + private void pinMoved() + { + recalculateEffectivePath(); + callRedrawListeners(); + } + + // "graphical" operations + + /** + * Recalculates {@link #effectivePath} "from scratch". Also updates {@link #bounds}. + * + * @author Daniel Kirschten + */ + private void recalculateEffectivePath() + { + Point pos1 = pin1.getPos(), pos2 = pin2.getPos(); + + double boundsX1 = Math.min(pos1.x, pos2.x); + double boundsY1 = Math.min(pos1.y, pos2.y); + double boundsX2 = Math.max(pos1.x, pos2.x); + double boundsY2 = Math.max(pos1.y, pos2.y); + + if (path == null) + effectivePath = new double[] { pos1.x, pos1.y, (pos1.x + pos2.x) / 2, pos1.y, (pos1.x + pos2.x) / 2, pos2.y, pos2.x, pos2.y }; + else + { + effectivePath = new double[path.length * 2 + 4]; + effectivePath[0] = pos1.x; + effectivePath[1] = pos1.y; + for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2) + { + double pathX = path[srcI].x; + double pathY = path[srcI].y; + effectivePath[dstI + 0] = pathX; + effectivePath[dstI + 1] = pathY; + if (pathX < boundsX1) + boundsX1 = pathX; + if (pathX > boundsX2) + boundsX2 = pathX; + if (pathY < boundsY1) + boundsY1 = pathY; + if (pathY > boundsY2) + boundsY2 = pathY; + } + effectivePath[effectivePath.length - 2] = pos2.x; + effectivePath[effectivePath.length - 1] = pos2.y; + } + + bounds.x = boundsX1; + bounds.y = boundsY1; + bounds.width = boundsX2 - boundsX1; + bounds.height = boundsY2 - boundsY1; + } + + /** + * Returns the bounds of this wire, excluding line width (and line joins, if the line join is {@link SWT#JOIN_MITER}) + * + * @author Daniel Kirschten + */ + public Rectangle getBounds() + { + return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height); + } + + /** + * Render this wire to the given gc, in absoulute coordinates. + * + * @author Daniel Kirschten + */ + public void render(GeneralGC gc) + { + ColorHelper.executeWithDifferentForeground(gc, BitVectorFormatter.formatAsColor(end), () -> gc.drawPolyline(effectivePath)); + } + + /** + * The user-defined path between {@link #pin1} and {@link #pin2}. Note that this is not neccessarily equal to the effective path drawn + * in {@link #render(GeneralGC)}.
+ * Special cases: null means "choose an interpolation as fits", and an empty array means "direct connection without any + * interpolation". + * + * @author Daniel Kirschten + */ + public Point[] getPath() + { + return path == null ? null : path.clone(); + } + + // logic model binding + + /** + * Binds this {@link GUIWire} to the given {@link ReadEnd}: The color of this {@link GUIWire} will now depend on the state of the given + * {@link ReadEnd}, and further changes of the given {@link ReadEnd} will result in readrawListeners being called.
+ * The argument can be null, in which case the old binding is stopped. + * + * @author Daniel Kirschten + */ + public void setLogicModelBinding(ReadEnd end) + { + if (this.end != null) + this.end.deregisterObserver(logicObs); + this.end = end; + if (end != null) + end.registerObserver(logicObs); + } + + // listeners + + // @formatter:off + public void addRedrawListener (Runnable listener) {redrawListeners .add (listener);} + + public void removeRedrawListener(Runnable listener) {redrawListeners .remove(listener);} + + private void callRedrawListeners() {redrawListeners.forEach(l -> l.run());} + // @formatter:on + + @Override + public String toString() + { + return "GUIWire [" + pin1 + "---" + pin2 + ", value=" + (end == null ? "null" : end.getValues()) + "]"; + } } \ No newline at end of file diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/WireCrossPoint.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/WireCrossPoint.java index 2b07238f..f79cf9aa 100644 --- a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/WireCrossPoint.java +++ b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/WireCrossPoint.java @@ -1,92 +1,85 @@ -package net.mograsim.logic.ui.model.wires; - -import java.util.Map; - -import net.haspamelodica.swt.helper.gcs.GeneralGC; -import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; -import net.mograsim.logic.core.LogicObservable; -import net.mograsim.logic.core.LogicObserver; -import net.mograsim.logic.core.types.BitVectorFormatter; -import net.mograsim.logic.core.wires.Wire.ReadEnd; -import net.mograsim.logic.ui.ColorHelper; -import net.mograsim.logic.ui.model.ModelVisitor; -import net.mograsim.logic.ui.model.ViewModelModifiable; -import net.mograsim.logic.ui.model.components.GUIComponent; -import net.mograsim.logic.ui.model.components.SimpleRectangularGUIGate; - -public class WireCrossPoint extends GUIComponent -{ - private static final int CIRCLE_RADIUS = 1; - private static final int CIRCLE_DIAM = CIRCLE_RADIUS * 2; - - private final Pin pin; - private final int logicWidth; - - private final LogicObserver logicObs; - private ReadEnd end; - - public WireCrossPoint(ViewModelModifiable model, int logicWidth) - { - super(model); - logicObs = (i) -> requestRedraw(); - - this.logicWidth = logicWidth; - setSize(CIRCLE_DIAM, CIRCLE_DIAM); - addPin(this.pin = new Pin(this, "", logicWidth, CIRCLE_RADIUS, CIRCLE_RADIUS)); - } - - public void moveCenterTo(double x, double y) - { - moveTo(x - CIRCLE_RADIUS, y - CIRCLE_RADIUS); - } - - @Override - public void render(GeneralGC gc, Rectangle visibleRegion) - { - ColorHelper.executeWithDifferentBackground(gc, BitVectorFormatter.formatAsColor(end), - () -> gc.fillOval(getPosX(), getPosY(), CIRCLE_DIAM, CIRCLE_DIAM)); - } - - public void setLogicModelBinding(ReadEnd end) - { - deregisterLogicObs(this.end); - this.end = end; - registerLogicObs(end); - } - - private void registerLogicObs(LogicObservable observable) - { - if (observable != null) - observable.registerObserver(logicObs); - } - - private void deregisterLogicObs(LogicObservable observable) - { - if (observable != null) - observable.deregisterObserver(logicObs); - } - - public int getLogicWidth() - { - return logicWidth; - } - - public Pin getPin() - { - return pin; - } - - @Override - public Map getInstantiationParameters() - { - Map m = super.getInstantiationParameters(); - m.put(SimpleRectangularGUIGate.kLogicWidth, logicWidth); - return m; - } - - @Override - public void accept(ModelVisitor mv) - { - mv.visit(this); - } +package net.mograsim.logic.ui.model.wires; + +import java.util.Map; + +import net.haspamelodica.swt.helper.gcs.GeneralGC; +import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle; +import net.mograsim.logic.core.LogicObservable; +import net.mograsim.logic.core.LogicObserver; +import net.mograsim.logic.core.types.BitVectorFormatter; +import net.mograsim.logic.core.wires.Wire.ReadEnd; +import net.mograsim.logic.ui.ColorHelper; +import net.mograsim.logic.ui.model.ViewModelModifiable; +import net.mograsim.logic.ui.model.components.GUIComponent; +import net.mograsim.logic.ui.model.components.SimpleRectangularGUIGate; + +public class WireCrossPoint extends GUIComponent +{ + private static final int CIRCLE_RADIUS = 1; + private static final int CIRCLE_DIAM = CIRCLE_RADIUS * 2; + + private final Pin pin; + private final int logicWidth; + + private final LogicObserver logicObs; + private ReadEnd end; + + public WireCrossPoint(ViewModelModifiable model, int logicWidth) + { + super(model); + logicObs = (i) -> requestRedraw(); + + this.logicWidth = logicWidth; + setSize(CIRCLE_DIAM, CIRCLE_DIAM); + addPin(this.pin = new Pin(this, "", logicWidth, CIRCLE_RADIUS, CIRCLE_RADIUS)); + } + + public void moveCenterTo(double x, double y) + { + moveTo(x - CIRCLE_RADIUS, y - CIRCLE_RADIUS); + } + + @Override + public void render(GeneralGC gc, Rectangle visibleRegion) + { + ColorHelper.executeWithDifferentBackground(gc, BitVectorFormatter.formatAsColor(end), + () -> gc.fillOval(getPosX(), getPosY(), CIRCLE_DIAM, CIRCLE_DIAM)); + } + + public void setLogicModelBinding(ReadEnd end) + { + deregisterLogicObs(this.end); + this.end = end; + registerLogicObs(end); + } + + private void registerLogicObs(LogicObservable observable) + { + if (observable != null) + observable.registerObserver(logicObs); + } + + private void deregisterLogicObs(LogicObservable observable) + { + if (observable != null) + observable.deregisterObserver(logicObs); + } + + public int getLogicWidth() + { + return logicWidth; + } + + public Pin getPin() + { + return pin; + } + + @Override + public Map getInstantiationParameters() + { + Map m = super.getInstantiationParameters(); + m.put(SimpleRectangularGUIGate.kLogicWidth, logicWidth); + return m; + } } \ No newline at end of file