Added SubmodelComponent
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 3 Jun 2019 20:11:22 +0000 (22:11 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 3 Jun 2019 20:11:22 +0000 (22:11 +0200)
net.mograsim.logic.ui/src/net/mograsim/logic/ui/examples/SubmodelExample.java [new file with mode: 0644]
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelComponent.java [new file with mode: 0644]
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelInterface.java [new file with mode: 0644]
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/TestSubmodelNANDComponent.java [new file with mode: 0644]
net.mograsim.logic.ui/src/net/mograsim/logic/ui/modeladapter/ViewLogicModelAdapter.java

diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/examples/SubmodelExample.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/examples/SubmodelExample.java
new file mode 100644 (file)
index 0000000..3cba4db
--- /dev/null
@@ -0,0 +1,33 @@
+package net.mograsim.logic.ui.examples;
+
+import net.mograsim.logic.ui.SimpleLogicUIStandalone;
+import net.mograsim.logic.ui.model.ViewModelModifiable;
+import net.mograsim.logic.ui.model.components.GUIBitDisplay;
+import net.mograsim.logic.ui.model.components.GUIManualSwitch;
+import net.mograsim.logic.ui.model.components.TestSubmodelNANDComponent;
+import net.mograsim.logic.ui.model.wires.GUIWire;
+
+public class SubmodelExample
+{
+       public static void main(String[] args)
+       {
+               SimpleLogicUIStandalone.executeVisualisation(SubmodelExample::createSubmodelExample);
+       }
+
+       @SuppressWarnings("unused") // GUIWires being created
+       public static void createSubmodelExample(ViewModelModifiable model)
+       {
+               GUIManualSwitch swA = new GUIManualSwitch(model);
+               swA.moveTo(0, 0);
+               GUIManualSwitch swB = new GUIManualSwitch(model);
+               swB.moveTo(0, 25);
+               TestSubmodelNANDComponent nand = new TestSubmodelNANDComponent(model);
+               nand.moveTo(30, 10);
+               GUIBitDisplay bdY = new GUIBitDisplay(model);
+               bdY.moveTo(70, 12.5);
+
+               new GUIWire(model, swA.getOutputPin(), nand.getPins().get(0));
+               new GUIWire(model, swB.getOutputPin(), nand.getPins().get(1));
+               new GUIWire(model, nand.getPins().get(2), bdY.getInputPin());
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelComponent.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/SubmodelComponent.java
new file mode 100644 (file)
index 0000000..9b0e41a
--- /dev/null
@@ -0,0 +1,156 @@
+package net.mograsim.logic.ui.model.components;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import net.haspamelodica.swt.helper.gcs.GCDefaultConfig;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.gcs.TranslatedGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.mograsim.logic.ui.LogicUIRenderer;
+import net.mograsim.logic.ui.model.ViewModel;
+import net.mograsim.logic.ui.model.ViewModelModifiable;
+import net.mograsim.logic.ui.model.wires.Pin;
+
+public class SubmodelComponent extends GUIComponent
+{
+       protected final ViewModelModifiable submodelModifiable;
+       public final ViewModel submodel;
+       private final Map<PinMovable, PinMovable> submodelPinsPerSupermodelPin;
+       private final Map<Pin, Pin> submodelPinsPerSupermodelPinUnmodifiable;
+       private final Map<PinMovable, PinMovable> supermodelPinsPerSubmodelPin;
+       private final Map<Pin, Pin> supermodelPinsPerSubmodelPinUnmodifiable;
+       private final SubmodelInterface submodelInterface;
+
+       private double submodelScale;
+       private final LogicUIRenderer renderer;
+
+       public SubmodelComponent(ViewModelModifiable model)
+       {
+               super(model);
+               this.submodelModifiable = new ViewModelModifiable();
+               this.submodel = submodelModifiable;
+               this.submodelPinsPerSupermodelPin = new HashMap<>();
+               this.submodelPinsPerSupermodelPinUnmodifiable = Collections.unmodifiableMap(submodelPinsPerSupermodelPin);
+               this.supermodelPinsPerSubmodelPin = new HashMap<>();
+               this.supermodelPinsPerSubmodelPinUnmodifiable = Collections.unmodifiableMap(supermodelPinsPerSubmodelPin);
+               this.submodelInterface = new SubmodelInterface(submodelModifiable);
+
+               this.submodelScale = 1;
+               this.renderer = new LogicUIRenderer(submodelModifiable);
+
+               submodelModifiable.addRedrawListener(this::requestRedraw);
+       }
+
+       protected void setSubmodelScale(double submodelScale)
+       {
+               this.submodelScale = submodelScale;
+
+               for (Entry<PinMovable, PinMovable> e : supermodelPinsPerSubmodelPin.entrySet())
+                       e.getKey().setRelPos(e.getValue().getRelX() * submodelScale, e.getValue().getRelY() * submodelScale);
+
+               requestRedraw();// needed if there is no submodel interface pin
+       }
+
+       /**
+        * Returns the submodel pin.
+        */
+       protected Pin addSubmodelInterface(int logicWidth, double relX, double relY)
+       {
+               PinMovable submodelPin = new PinMovable(submodelInterface, logicWidth, relX / submodelScale, relY / submodelScale);
+               submodelInterface.addPin(submodelPin);
+
+               PinMovable supermodelPin = new PinMovable(this, logicWidth, relX, relY);
+               addPin(supermodelPin);
+
+               submodelPinsPerSupermodelPin.put(supermodelPin, submodelPin);
+               supermodelPinsPerSubmodelPin.put(submodelPin, supermodelPin);
+
+               // no need to call requestRedraw() because addPin() will request a redraw
+               return submodelPin;
+       }
+
+       protected void moveSubmodelInterface(Pin supermodelPin, double relX, double relY)
+       {
+               PinMovable submodelPin = getSubmodelMovablePin(supermodelPin);
+               PinMovable supermodelPinMovable = getSupermodelMovablePin(submodelPin);
+
+               submodelPin.setRelPos(relX / submodelScale, relY / submodelScale);
+               supermodelPinMovable.setRelPos(relX, relY);
+
+               // no need to call requestRedraw() because setRelPos() will request a redraw
+       }
+
+       protected void removeSubmodelInterface(Pin supermodelPin)
+       {
+               removePin(supermodelPin);
+               Pin submodelPin = getSubmodelMovablePin(supermodelPin);
+               submodelInterface.removePin(submodelPin);
+
+               submodelPinsPerSupermodelPin.remove(supermodelPin);
+               supermodelPinsPerSubmodelPin.remove(submodelPin);
+
+               // no need to call requestRedraw() because removePin() will request a redraw
+       }
+
+       public Map<Pin, Pin> getSupermodelPinsPerSubmodelPin()
+       {
+               return supermodelPinsPerSubmodelPinUnmodifiable;
+       }
+
+       public Pin getSupermodelPin(Pin submodelPin)
+       {
+               return getSupermodelMovablePin(submodelPin);
+       }
+
+       protected PinMovable getSupermodelMovablePin(Pin submodelPin)
+       {
+               return supermodelPinsPerSubmodelPin.get(submodelPin);
+       }
+
+       public Map<Pin, Pin> getSubmodelPinsPerSupermodelPin()
+       {
+               return submodelPinsPerSupermodelPinUnmodifiable;
+       }
+
+       public Pin getSubmodelPin(Pin supermodelPin)
+       {
+               return getSubmodelMovablePin(supermodelPin);
+       }
+
+       protected PinMovable getSubmodelMovablePin(Pin supermodelPin)
+       {
+               return submodelPinsPerSupermodelPin.get(supermodelPin);
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               double posX = getBounds().x;
+               double posY = getBounds().y;
+
+               GCDefaultConfig conf = new GCDefaultConfig(gc);
+               TranslatedGC tgc = new TranslatedGC(gc, posX, posY, submodelScale, true);
+               conf.reset(tgc);
+               renderer.render(tgc, visibleRegion.translate(posX, posY, submodelScale));
+               conf.reset(gc);
+               // draw the "bounding box" after all other operations to make interface pins look better
+               gc.drawRectangle(getBounds());
+       }
+
+       private static class PinMovable extends Pin
+       {
+               public PinMovable(GUIComponent component, int logicWidth, double relX, double relY)
+               {
+                       super(component, logicWidth, relX, relY);
+               }
+
+               @Override
+               protected void setRelPos(double relX, double relY)
+               {
+                       super.setRelPos(relX, relY);
+               }
+       }
+}
\ 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
new file mode 100644 (file)
index 0000000..8f448a8
--- /dev/null
@@ -0,0 +1,18 @@
+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.ViewModelModifiable;
+
+public class SubmodelInterface extends GUIComponent
+{
+       public SubmodelInterface(ViewModelModifiable model)
+       {
+               super(model);
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {// nothing to do here
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/TestSubmodelNANDComponent.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/TestSubmodelNANDComponent.java
new file mode 100644 (file)
index 0000000..9cfdb26
--- /dev/null
@@ -0,0 +1,34 @@
+package net.mograsim.logic.ui.model.components;
+
+import net.mograsim.logic.ui.model.ViewModelModifiable;
+import net.mograsim.logic.ui.model.wires.GUIWire;
+import net.mograsim.logic.ui.model.wires.Pin;
+
+public class TestSubmodelNANDComponent extends SubmodelComponent
+{
+       public TestSubmodelNANDComponent(ViewModelModifiable model)
+       {
+               super(model);
+               setSize(30, 20);
+               setSubmodelScale(.5);
+               initSubmodelComponents();
+       }
+
+       @SuppressWarnings("unused") // GUIWires being created
+       private void initSubmodelComponents()
+       {
+               Pin A = addSubmodelInterface(1, 0, 5);
+               Pin B = addSubmodelInterface(1, 0, 15);
+               Pin Y = addSubmodelInterface(1, 30, 10);
+
+               GUIAndGate and = new GUIAndGate(submodelModifiable, 1);
+               and.moveTo(5, 10);
+               GUINotGate not = new GUINotGate(submodelModifiable, 1);
+               not.moveTo(30, 15);
+
+               new GUIWire(submodelModifiable, A, and.getInputPins().get(0));
+               new GUIWire(submodelModifiable, B, and.getInputPins().get(1));
+               new GUIWire(submodelModifiable, and.getOutputPin(), not.getInputPins().get(0));
+               new GUIWire(submodelModifiable, not.getOutputPin(), Y);
+       }
+}
\ No newline at end of file
index 3f05964..80c2898 100644 (file)
@@ -1,13 +1,11 @@
 package net.mograsim.logic.ui.modeladapter;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Objects;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -24,6 +22,8 @@ import net.mograsim.logic.ui.model.components.GUIAndGate;
 import net.mograsim.logic.ui.model.components.GUIComponent;
 import net.mograsim.logic.ui.model.components.GUINotGate;
 import net.mograsim.logic.ui.model.components.GUIOrGate;
+import net.mograsim.logic.ui.model.components.SubmodelComponent;
+import net.mograsim.logic.ui.model.components.SubmodelInterface;
 import net.mograsim.logic.ui.model.wires.GUIWire;
 import net.mograsim.logic.ui.model.wires.Pin;
 import net.mograsim.logic.ui.model.wires.WireCrossPoint;
@@ -45,7 +45,7 @@ public class ViewLogicModelAdapter
                componentAdaptersModifiable.add(new ManualSwitchAdapter());
                componentAdaptersModifiable.add(new BitDisplayAdapter());
                componentAdaptersModifiable.add(new Am2901NANDBasedAdapter());
-               // TODO list all "primitive" adapters here
+               // TODO list all adapters here
                componentAdapters = Collections.unmodifiableMap(
                                componentAdaptersModifiable.stream().collect(Collectors.toMap(ComponentAdapter::getSupportedClass, Function.identity())));
        }
@@ -55,48 +55,68 @@ public class ViewLogicModelAdapter
                // TODO replace Timeline with LogicModel as soon as it exists
                Timeline timeline = new Timeline(10);
 
-               Map<Pin, Wire> logicWiresPerPin = convertWires(
-                               viewModel.getComponents().stream().flatMap(component -> component.getPins().stream()).collect(Collectors.toSet()),
-                               viewModel.getWires(), params, timeline);
+               convert(viewModel, params, timeline, Map.of());
+
+               return timeline;
+       }
+
+       private static void convert(ViewModel viewModel, LogicModelParameters params, Timeline timeline, Map<Pin, Wire> externalWires)
+       {
+               Map<Pin, Wire> logicWiresPerPin = convertWires(getAllPins(viewModel), viewModel.getWires(), externalWires, params, timeline);
                Map<Pin, Wire> logicWiresPerPinUnmodifiable = Collections.unmodifiableMap(logicWiresPerPin);
 
-               Map<GUIComponent, Component> oneToOneComponents = new HashMap<>();
                for (GUIComponent guiComp : viewModel.getComponents())
                {
-                       if (!(guiComp instanceof WireCrossPoint))
-                               oneToOneComponents.put(guiComp, createAndLinkComponent(timeline, params, guiComp, logicWiresPerPinUnmodifiable,
-                                               componentAdapters.get(guiComp.getClass())));
-                       else
+                       if (guiComp instanceof SubmodelComponent)
+                       {
+                               SubmodelComponent guiCompCasted = (SubmodelComponent) guiComp;
+                               Map<Pin, Pin> supermodelPinsPerSubmodelPin = guiCompCasted.getSupermodelPinsPerSubmodelPin();
+                               Map<Pin, Wire> externalWiresForSubmodel = supermodelPinsPerSubmodelPin.entrySet().stream()
+                                               .collect(Collectors.toMap(Entry::getKey, e -> logicWiresPerPin.get(e.getValue())));
+                               convert(guiCompCasted.submodel, params, timeline, externalWiresForSubmodel);
+                       } else if (guiComp instanceof WireCrossPoint)
                        {
                                WireCrossPoint guiCompCasted = (WireCrossPoint) guiComp;
                                guiCompCasted.setLogicModelBinding(logicWiresPerPin.get(guiCompCasted.getPin()).createReadOnlyEnd());
-                       }
+                       } else if (!(guiComp instanceof SubmodelInterface))// nothing to do for SubmodelInterfaces
+                               createAndLinkComponent(timeline, params, guiComp, logicWiresPerPinUnmodifiable, componentAdapters.get(guiComp.getClass()));
                }
+       }
 
-               // TODO handle complex components
-
-               List<Component> logicComponents = new ArrayList<>();
-               // null means "no one to one mapping"
-               oneToOneComponents.values().stream().filter(Objects::nonNull).forEach(logicComponents::add);
-
-               return timeline;
+       private static Set<Pin> getAllPins(ViewModel viewModel)
+       {
+               return viewModel.getComponents().stream().flatMap(component -> component.getPins().stream()).collect(Collectors.toSet());
        }
 
-       private static Map<Pin, Wire> convertWires(Set<Pin> allPins, List<GUIWire> wires, LogicModelParameters params, Timeline timeline)
+       private static Map<Pin, Wire> convertWires(Set<Pin> allPins, List<GUIWire> wires, Map<Pin, Wire> externalWires,
+                       LogicModelParameters params, Timeline timeline)
        {
                Map<Pin, Set<Pin>> connectedPinGroups = getConnectedPinGroups(allPins, wires);
-               Map<Pin, Wire> logicWiresPerPin = createLogicWires(params, timeline, connectedPinGroups);
+               Map<Pin, Wire> logicWiresPerPin = createLogicWires(params, timeline, connectedPinGroups, externalWires);
                setGUIWiresLogicModelBinding(wires, logicWiresPerPin);
                return logicWiresPerPin;
        }
 
-       private static Map<Pin, Wire> createLogicWires(LogicModelParameters params, Timeline timeline, Map<Pin, Set<Pin>> connectedPinGroups)
+       private static Map<Pin, Wire> createLogicWires(LogicModelParameters params, Timeline timeline, Map<Pin, Set<Pin>> connectedPinGroups,
+                       Map<Pin, Wire> externalWires)
        {
                Map<Pin, Wire> logicWiresPerPin = new HashMap<>();
                Map<Set<Pin>, Wire> logicWiresPerPinGroup = new HashMap<>();
                for (Entry<Pin, Set<Pin>> e : connectedPinGroups.entrySet())
-                       logicWiresPerPin.put(e.getKey(), logicWiresPerPinGroup.computeIfAbsent(e.getValue(),
-                                       set -> new Wire(timeline, e.getKey().logicWidth, params.wireTravelTime)));
+                       logicWiresPerPin.put(e.getKey(), logicWiresPerPinGroup.computeIfAbsent(e.getValue(), set ->
+                       {
+                               Wire externalWire = null;
+                               for (Pin p : set)
+                               {
+                                       Wire externalWireCandidate = externalWires.get(p);
+                                       if (externalWireCandidate != null)
+                                               if (externalWire == null)
+                                                       externalWire = externalWireCandidate;
+                                               else
+                                                       throw new IllegalArgumentException("Two pins to external wires can't be connected directly");
+                               }
+                               return new Wire(timeline, e.getKey().logicWidth, params.wireTravelTime);
+                       }));
                return logicWiresPerPin;
        }