import era.mi.gui.model.ViewModel;
import era.mi.gui.model.components.GUIComponent;
+import era.mi.gui.model.wires.GUIWire;
import era.mi.gui.model.wires.Pin;
import net.haspamelodica.swt.helper.gcs.GeneralGC;
import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
p.removePinMovedListener(redrawConsumer);
redrawThreadsafe();
};
- model.addComponentAddedListener(c ->
+ Consumer<? super GUIComponent> componentAddedListener = c ->
{
- c.addComponentChangedListener(redrawConsumer);
+ c.addComponentLookChangedListener(redrawConsumer);
c.addComponentMovedListener(redrawConsumer);
c.addPinAddedListener(pinAddedListener);
c.addPinRemovedListener(pinRemovedListener);
redrawThreadsafe();
- });
+ };
+ model.addComponentAddedListener(componentAddedListener);
+ model.getComponents().forEach(componentAddedListener);
model.addComponentRemovedListener(c ->
{
- c.removeComponentChangedListener(redrawConsumer);
+ c.removeComponentLookChangedListener(redrawConsumer);
c.removeComponentMovedListener(redrawConsumer);
c.removePinAddedListener(pinAddedListener);
c.removePinRemovedListener(pinRemovedListener);
redrawThreadsafe();
});
- model.addWireAddedListener(w ->
+ Consumer<? super GUIWire> wireAddedListener = w ->
{
- w.addWireChangedListener(redrawConsumer);
+ w.addWireLookChangedListener(redrawConsumer);
redrawThreadsafe();
- });
+ };
+ model.addWireAddedListener(wireAddedListener);
+ model.getWires().forEach(wireAddedListener);
model.addWireRemovedListener(w ->
{
- w.removeWireChangedListener(redrawConsumer);
+ w.removeWireLookChangedListener(redrawConsumer);
redrawThreadsafe();
});
import org.eclipse.swt.widgets.Shell;
import era.mi.gui.model.ViewModel;
+import era.mi.gui.modeladapter.LogicModelParameters;
+import era.mi.gui.modeladapter.ViewLogicModelAdapter;
+import era.mi.logic.timeline.Timeline;
import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
public class LogicUIStandalone
{
private ViewModel model;
+ private Timeline timeline;
private final Display display;
private final Shell shell;
userInput.buttonZoom = 2;
userInput.enableUserInput();
new ZoomableCanvasOverlay(ui, null).enableScale();
+
+ // TODO don't do this here
+ LogicModelParameters params = new LogicModelParameters();
+ params.gateProcessTime = 50;
+ params.wireTravelTime = 10;
+ timeline = ViewLogicModelAdapter.convert(model, params);
}
public LogicUICanvas getLogicUICanvas()
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);
-// 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();
-// });
+ Thread simulationThread = new Thread(() ->
+ {
+ while (running.get())
+ {
+ // always execute to keep timeline from "hanging behind" for too long
+ timeline.executeUntil(timeline.laterThan(System.currentTimeMillis()), System.currentTimeMillis() + 10);
+ long sleepTime;
+ if (timeline.hasNext())
+ sleepTime = timeline.nextEventTime() - System.currentTimeMillis();
+ else
+ sleepTime = 10;
+ try
+ {
+ if (sleepTime > 0)
+ Thread.sleep(sleepTime);
+ }
+ catch (InterruptedException e)
+ {
+ } // it is normal execution flow to be interrupted
+ }
+ });
+ simulationThread.start();
+ timeline.addEventAddedListener(event ->
+ {
+ if (event.getTiming() <= System.currentTimeMillis())
+ simulationThread.interrupt();
+ });
shell.open();
while (!shell.isDisposed())
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();
+ GUIAndGate andGate = new GUIAndGate(model, 1);
+ andGate.moveTo(10, 10);
+ GUINotGate notGate = new GUINotGate(model, 1);
+ notGate.moveTo(10, 40);
+
+ new GUIWire(model, andGate.getPins().get(0), notGate.getPins().get(1), new Point(20, 50));
+
LogicUIStandalone ui = new LogicUIStandalone(model);
- addComponentsAndWires(ui, model);
+
+ ui.getLogicUICanvas().addListener(SWT.KeyDown, e -> notGate.moveTo(150, 10));
ui.run();
}
public static void addComponentsAndWires(LogicUIStandalone ui, ViewModel model)
{
- GUIAndGate andGate = new GUIAndGate(model);
+ GUIAndGate andGate = new GUIAndGate(model, 1);
andGate.moveTo(10, 10);
- GUINotGate notGate = new GUINotGate(model);
+ GUINotGate notGate = new GUINotGate(model, 1);
notGate.moveTo(10, 40);
new GUIWire(model, andGate.getPins().get(0), notGate.getPins().get(1), new Point(20, 50));
import era.mi.gui.model.ViewModel;
-public class GUIAndGate extends RectangularShapedGUIGate
+public class GUIAndGate extends SimpleRectangularGUIGate
{
- public GUIAndGate(ViewModel model)
+ public GUIAndGate(ViewModel model, int logicWidth)
{
- super(model, "&", false);
- setInputCount(2);
+ super(model, logicWidth, "&", false);
+ setInputCount(2);// TODO make variable
}
}
\ No newline at end of file
private final List<Pin> pins;
protected final List<Pin> pinsUnmodifiable;
- private final List<Consumer<? super GUIComponent>> componentChangedListeners;
+ private final List<Consumer<? super GUIComponent>> componentLookChangedListeners;
private final List<Consumer<? super GUIComponent>> componentMovedListeners;
private final List<Consumer<? super Pin>> pinAddedListeners;
private final List<Consumer<? super Pin>> pinRemovedListeners;
this.pins = new ArrayList<>();
this.pinsUnmodifiable = Collections.unmodifiableList(pins);
- this.componentChangedListeners = new ArrayList<>();
+ this.componentLookChangedListeners = new ArrayList<>();
this.componentMovedListeners = new ArrayList<>();
this.pinAddedListeners = new ArrayList<>();
this.pinRemovedListeners = new ArrayList<>();
}
// @formatter:off
- public void addComponentChangedListener (Consumer<? super GUIComponent> listener) {componentChangedListeners.add (listener);}
- public void addComponentMovedListener (Consumer<? super GUIComponent> listener) {componentMovedListeners .add (listener);}
- public void addPinAddedListener (Consumer<? super Pin > listener) {pinAddedListeners .add (listener);}
- public void addPinRemovedListener (Consumer<? super Pin > listener) {pinRemovedListeners .add (listener);}
-
- public void removeComponentChangedListener(Consumer<? super GUIComponent> listener) {componentChangedListeners.remove(listener);}
- public void removeComponentMovedListener (Consumer<? super GUIComponent> listener) {componentMovedListeners .remove(listener);}
- public void removePinAddedListener (Consumer<? super Pin > listener) {pinAddedListeners .remove(listener);}
- public void removePinRemovedListener (Consumer<? super Pin > 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 ));}
+ public void addComponentLookChangedListener (Consumer<? super GUIComponent> listener) {componentLookChangedListeners.add (listener);}
+ public void addComponentMovedListener (Consumer<? super GUIComponent> listener) {componentMovedListeners .add (listener);}
+ public void addPinAddedListener (Consumer<? super Pin > listener) {pinAddedListeners .add (listener);}
+ public void addPinRemovedListener (Consumer<? super Pin > listener) {pinRemovedListeners .add (listener);}
+
+ public void removeComponentLookChangedListener(Consumer<? super GUIComponent> listener) {componentLookChangedListeners.remove(listener);}
+ public void removeComponentMovedListener (Consumer<? super GUIComponent> listener) {componentMovedListeners .remove(listener);}
+ public void removePinAddedListener (Consumer<? super Pin > listener) {pinAddedListeners .remove(listener);}
+ public void removePinRemovedListener (Consumer<? super Pin > listener) {pinRemovedListeners .remove(listener);}
+
+ protected void callComponentLookChangedListeners( ) {componentLookChangedListeners.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
/**
{
bounds.width = width;
bounds.height = height;
- callComponentChangedListeners();
+ callComponentLookChangedListeners();
}
protected void addPin(Pin pin)
{
super(model);
setSize(width, height);
- addPin(new Pin(this, width, height / 2));
+ addPin(new Pin(this, 1, width, height / 2));
}
@Override
this.logicSwitch = logicSwitch;
this.end = end;
// TODO when ManualSwitch supports it, add listeners
- end.addObserver((i, o) -> callComponentChangedListeners());
+ end.addObserver((i, o) -> callComponentLookChangedListeners());
}
@Override
import era.mi.gui.model.ViewModel;
-public class GUINotGate extends RectangularShapedGUIGate
+public class GUINotGate extends SimpleRectangularGUIGate
{
- public GUINotGate(ViewModel model)
+ public GUINotGate(ViewModel model, int logicWidth)
{
- super(model, "1", true);
+ super(model, logicWidth, "1", true);
setInputCount(1);
}
}
\ No newline at end of file
import era.mi.gui.model.ViewModel;
-public class GUIOrGate extends RectangularShapedGUIGate
+public class GUIOrGate extends SimpleRectangularGUIGate
{
- public GUIOrGate(ViewModel model)
+ public GUIOrGate(ViewModel model, int logicWidth)
{
- super(model, "\u22651", false);// ">=1"
+ super(model, logicWidth, "\u22651", false);// ">=1"
setInputCount(2);
}
}
\ No newline at end of file
+++ /dev/null
-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<Pin> 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
--- /dev/null
+package era.mi.gui.model.components;
+
+import java.util.ArrayList;
+import java.util.Collections;
+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 SimpleRectangularGUIGate 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;
+ protected final int logicWidth;
+ private final boolean isInverted;
+ private final double rectWidth;
+
+ private MovablePin outputPin;
+ private final List<Pin> inputPins;
+ private final List<Pin> inputPinsUnmodifiable;
+
+ protected SimpleRectangularGUIGate(ViewModel model, int logicWidth, String label, boolean isInverted)
+ {
+ super(model);
+ this.label = label;
+ this.logicWidth = logicWidth;
+ this.isInverted = isInverted;
+ this.rectWidth = width - (isInverted ? invertedCircleDiam : 0);
+ this.outputPin = new MovablePin(this, logicWidth, width, 0);
+ addPin(outputPin);
+ this.inputPins = new ArrayList<>();
+ this.inputPinsUnmodifiable = Collections.unmodifiableList(inputPins);
+ 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, logicWidth, 0, pinDistance / 2 + i * pinDistance);
+ inputPins.add(pin);
+ addPin(pin);
+ }
+ outputPin.setRelPos(width, inputCount * pinDistance / 2);
+ }
+
+ public Pin getOutputPin()
+ {
+ return outputPin;
+ }
+
+ public List<Pin> getInputPins()
+ {
+ return inputPinsUnmodifiable;
+ }
+
+ @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
public class GUIWire
{
private final ViewModel model;
+ public final int logicWidth;
private Pin pin1;
private Pin pin2;
private double[] path;
- private final List<Consumer<? super GUIWire>> wireChangedListeners;
+ private final List<Consumer<? super GUIWire>> wireLookChangedListeners;
private ReadEnd end;
public GUIWire(ViewModel model, Pin pin1, Pin pin2, Point... path)
{
this.model = model;
+ this.logicWidth = pin1.logicWidth;
+ if (pin2.logicWidth != pin1.logicWidth)
+ throw new IllegalArgumentException("Can't connect pins of different logic width");
this.path = new double[path.length * 2 + 4];
for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2)
{
this.pin1 = pin1;
this.pin2 = pin2;
- wireChangedListeners = new ArrayList<>();
+ wireLookChangedListeners = new ArrayList<>();
pin1.addPinMovedListener(p -> pin1Moved());
pin2.addPinMovedListener(p -> pin2Moved());
public void setLogicModelBinding(ReadEnd end)
{
this.end = end;
- end.addObserver((i, o) -> callWireChangedListeners());
+ end.addObserver((i, o) -> callWireLookChangedListeners());
+ }
+
+ public Pin getPin1()
+ {
+ return pin1;
+ }
+
+ public Pin getPin2()
+ {
+ return pin2;
}
// @formatter:off
- public void addWireChangedListener (Consumer<? super GUIWire> listener) {wireChangedListeners.add (listener);}
+ public void addWireLookChangedListener (Consumer<? super GUIWire> listener) {wireLookChangedListeners.add (listener);}
- public void removeWireChangedListener(Consumer<? super GUIWire> listener) {wireChangedListeners.remove(listener);}
+ public void removeWireLookChangedListener(Consumer<? super GUIWire> listener) {wireLookChangedListeners.remove(listener);}
- private void callWireChangedListeners() {wireChangedListeners.forEach(l -> l.accept(this));}
+ private void callWireLookChangedListeners() {wireLookChangedListeners.forEach(l -> l.accept(this));}
// @formatter:on
}
\ No newline at end of file
public class MovablePin extends Pin
{
- public MovablePin(GUIComponent component, double relX, double relY)
+ public MovablePin(GUIComponent component, int logicWidth, double relX, double relY)
{
- super(component, relX, relY);
+ super(component, logicWidth, relX, relY);
}
@Override
public class Pin
{
public final GUIComponent component;
+ public final int logicWidth;
protected double relX;
protected double relY;
private final List<Consumer<? super Pin>> pinMovedListeners;
- public Pin(GUIComponent component, double relX, double relY)
+ public Pin(GUIComponent component, int logicWidth, double relX, double relY)
{
this.component = component;
+ this.logicWidth = logicWidth;
this.relX = relX;
this.relY = relY;
public class WireCrossPoint extends GUIComponent
{
private ReadEnd end;
+ private final int logicWidth;
- public WireCrossPoint(ViewModel model)
+ public WireCrossPoint(ViewModel model, int logicWidth)
{
super(model);
+ this.logicWidth = logicWidth;
setSize(0, 0);
- addPin(new Pin(this, 0, 0));
+ addPin(new Pin(this, logicWidth, 0, 0));
}
@Override
public void setLogicModelBinding(ReadEnd end)
{
this.end = end;
- end.addObserver((i, o) -> callComponentChangedListeners());
+ end.addObserver((i, o) -> callComponentLookChangedListeners());
+ }
+
+ public int getLogicWidth()
+ {
+ return logicWidth;
}
}
\ No newline at end of file
--- /dev/null
+package era.mi.gui.modeladapter;
+
+public class LogicModelParameters
+{
+ public int wireTravelTime;
+ public int gateProcessTime;
+}
\ No newline at end of file
package era.mi.gui.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.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import era.mi.gui.model.ViewModel;
+import era.mi.gui.model.components.GUIAndGate;
+import era.mi.gui.model.components.GUIComponent;
+import era.mi.gui.model.components.GUINotGate;
+import era.mi.gui.model.components.GUIOrGate;
+import era.mi.gui.model.wires.GUIWire;
+import era.mi.gui.model.wires.Pin;
+import era.mi.gui.model.wires.WireCrossPoint;
+import era.mi.gui.modeladapter.componentadapters.ComponentAdapter;
+import era.mi.gui.modeladapter.componentadapters.SimpleGateAdapter;
+import era.mi.logic.components.Component;
+import era.mi.logic.components.gates.AndGate;
+import era.mi.logic.components.gates.NotGate;
+import era.mi.logic.components.gates.OrGate;
+import era.mi.logic.timeline.Timeline;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.ReadEnd;
+
public class ViewLogicModelAdapter
{
+ private final static Map<Class<? extends GUIComponent>, ComponentAdapter<? extends GUIComponent>> componentAdapters;
+ static
+ {
+ Map<Class<? extends GUIComponent>, ComponentAdapter<? extends GUIComponent>> componentAdaptersModifiable = new HashMap<>();
+ componentAdaptersModifiable.put(GUIOrGate.class, new SimpleGateAdapter(OrGate::new));
+ componentAdaptersModifiable.put(GUIAndGate.class, new SimpleGateAdapter(AndGate::new));
+ componentAdaptersModifiable.put(GUINotGate.class, new SimpleGateAdapter((t, p, o, i) -> new NotGate(t, p, i[0], o)));
+ // TODO list all "primitive" adapters here
+ componentAdapters = Collections.unmodifiableMap(componentAdaptersModifiable);
+ }
+
+ public static Timeline convert(ViewModel viewModel, LogicModelParameters params)
+ {
+ // 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);
+ Map<Pin, Wire> logicWiresPerPinUnmodifiable = Collections.unmodifiableMap(logicWiresPerPin);
+
+ Map<GUIComponent, Component> oneToOneComponents = new HashMap<>();
+ for (GUIComponent guiComp : viewModel.getComponents())
+ {
+ // WireCrossPoints just vanish
+ if (!(guiComp instanceof WireCrossPoint))
+ oneToOneComponents.put(guiComp, createAndLinkComponent(timeline, params, guiComp, logicWiresPerPinUnmodifiable,
+ componentAdapters.get(guiComp.getClass())));
+ }
+
+ // TODO handle complex components
+
+ List<Component> logicComponents = new ArrayList<>();
+ logicComponents.addAll(oneToOneComponents.values());
+
+ return timeline;
+ }
+
+ private static Map<Pin, Wire> convertWires(Set<Pin> allPins, List<GUIWire> wires, LogicModelParameters params, Timeline timeline)
+ {
+ Map<Pin, Set<Pin>> connectedPinGroups = getConnectedPinGroups(allPins, wires);
+ Map<Pin, Wire> logicWiresPerPin = createLogicWires(params, timeline, connectedPinGroups);
+ setGUIWiresLogicModelBinding(wires, logicWiresPerPin);
+ return logicWiresPerPin;
+ }
+
+ private static Map<Pin, Wire> createLogicWires(LogicModelParameters params, Timeline timeline, Map<Pin, Set<Pin>> connectedPinGroups)
+ {
+ 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)));
+ return logicWiresPerPin;
+ }
+
+ private static void setGUIWiresLogicModelBinding(List<GUIWire> wires, Map<Pin, Wire> logicWiresPerPin)
+ {
+ Map<Wire, ReadEnd> guiWireSharedReadEnd = logicWiresPerPin.values().stream().distinct()
+ .collect(Collectors.toMap(Function.identity(), Wire::createReadOnlyEnd));
+ for (GUIWire guiWire : wires)
+ guiWire.setLogicModelBinding(guiWireSharedReadEnd.get(logicWiresPerPin.get(guiWire.getPin1())));
+ }
+
+ private static Map<Pin, Set<Pin>> getConnectedPinGroups(Set<Pin> allPins, List<GUIWire> wires)
+ {
+ Map<Pin, Set<Pin>> connectedPinsPerPin = new HashMap<>();
+
+ for (Pin p : allPins)
+ {
+ HashSet<Pin> connectedPins = new HashSet<>();
+ connectedPins.add(p);
+ connectedPinsPerPin.put(p, connectedPins);
+ }
+
+ wires.forEach(wire ->
+ {
+ Pin pin1 = wire.getPin1();
+ Pin pin2 = wire.getPin2();
+
+ Set<Pin> pin1ConnectedPins = connectedPinsPerPin.get(pin1);
+ Set<Pin> pin2ConnectedPins = connectedPinsPerPin.get(pin2);
+
+ pin1ConnectedPins.addAll(pin2ConnectedPins);
+ pin1ConnectedPins.add(pin1);
+ pin1ConnectedPins.add(pin2);
+
+ pin2ConnectedPins.forEach(pin -> connectedPinsPerPin.put(pin, pin1ConnectedPins));
+ });
+ return connectedPinsPerPin;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <G extends GUIComponent> Component createAndLinkComponent(Timeline timeline, LogicModelParameters params,
+ GUIComponent guiComponent, Map<Pin, Wire> logicWiresPerPin, ComponentAdapter<G> adapter)
+ {
+ if (adapter == null)
+ throw new IllegalArgumentException("Unknown component class: " + guiComponent.getClass());
+ return adapter.createAndLinkComponent(timeline, params, (G) guiComponent, logicWiresPerPin);
+ }
+ private ViewLogicModelAdapter()
+ {
+ throw new UnsupportedOperationException("No ViewLogicModelConverter instances");
+ }
}
\ No newline at end of file
--- /dev/null
+package era.mi.gui.modeladapter.componentadapters;
+
+import java.util.Map;
+
+import era.mi.gui.model.components.GUIComponent;
+import era.mi.gui.model.wires.Pin;
+import era.mi.gui.modeladapter.LogicModelParameters;
+import era.mi.logic.components.Component;
+import era.mi.logic.timeline.Timeline;
+import era.mi.logic.wires.Wire;
+
+public interface ComponentAdapter<G extends GUIComponent>
+{
+ public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G guiComponent,
+ Map<Pin, Wire> logicWiresPerPin);
+}
\ No newline at end of file
--- /dev/null
+package era.mi.gui.modeladapter.componentadapters;
+
+import java.util.List;
+import java.util.Map;
+
+import era.mi.gui.model.components.SimpleRectangularGUIGate;
+import era.mi.gui.model.wires.Pin;
+import era.mi.gui.modeladapter.LogicModelParameters;
+import era.mi.logic.components.Component;
+import era.mi.logic.timeline.Timeline;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.ReadEnd;
+import era.mi.logic.wires.Wire.ReadWriteEnd;
+
+public class SimpleGateAdapter implements ComponentAdapter<SimpleRectangularGUIGate>
+{
+ private final ComponentConstructor constructor;
+
+ public SimpleGateAdapter(ComponentConstructor constructor)
+ {
+ this.constructor = constructor;
+ }
+
+ @Override
+ public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, SimpleRectangularGUIGate guiComponent,
+ Map<Pin, Wire> logicWiresPerPin)
+ {
+ ReadWriteEnd out = logicWiresPerPin.get(guiComponent.getOutputPin()).createReadWriteEnd();
+ List<Pin> inputPins = guiComponent.getInputPins();
+ ReadEnd[] ins = new ReadEnd[inputPins.size()];
+ for (int i = 0; i < inputPins.size(); i++)
+ ins[i] = logicWiresPerPin.get(inputPins.get(i)).createReadOnlyEnd();
+ return constructor.newComponent(timeline, params.gateProcessTime, out, ins);
+ }
+
+ public static interface ComponentConstructor
+ {
+ public Component newComponent(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd[] ins);
+ }
+}
\ No newline at end of file