Renamed project to MoGraSim
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Wed, 29 May 2019 20:59:35 +0000 (22:59 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Wed, 29 May 2019 20:59:35 +0000 (22:59 +0200)
136 files changed:
LogicUI/.project
LogicUI/.settings/org.eclipse.jdt.ui.prefs
LogicUI/META-INF/MANIFEST.MF
LogicUI/src/era/mi/gui/ColorHelper.java [deleted file]
LogicUI/src/era/mi/gui/LogicExecuter.java [deleted file]
LogicUI/src/era/mi/gui/LogicUICanvas.java [deleted file]
LogicUI/src/era/mi/gui/LogicUIStandaloneGUI.java [deleted file]
LogicUI/src/era/mi/gui/SimpleLogicUIStandalone.java [deleted file]
LogicUI/src/era/mi/gui/examples/RSLatchExample.java [deleted file]
LogicUI/src/era/mi/gui/model/ViewModel.java [deleted file]
LogicUI/src/era/mi/gui/model/components/GUIAndGate.java [deleted file]
LogicUI/src/era/mi/gui/model/components/GUIComponent.java [deleted file]
LogicUI/src/era/mi/gui/model/components/GUIManualSwitch.java [deleted file]
LogicUI/src/era/mi/gui/model/components/GUINotGate.java [deleted file]
LogicUI/src/era/mi/gui/model/components/GUIOrGate.java [deleted file]
LogicUI/src/era/mi/gui/model/components/SimpleRectangularGUIGate.java [deleted file]
LogicUI/src/era/mi/gui/model/wires/GUIWire.java [deleted file]
LogicUI/src/era/mi/gui/model/wires/MovablePin.java [deleted file]
LogicUI/src/era/mi/gui/model/wires/Pin.java [deleted file]
LogicUI/src/era/mi/gui/model/wires/WireCrossPoint.java [deleted file]
LogicUI/src/era/mi/gui/modeladapter/LogicModelParameters.java [deleted file]
LogicUI/src/era/mi/gui/modeladapter/ViewLogicModelAdapter.java [deleted file]
LogicUI/src/era/mi/gui/modeladapter/componentadapters/ComponentAdapter.java [deleted file]
LogicUI/src/era/mi/gui/modeladapter/componentadapters/ManualSwitchAdapter.java [deleted file]
LogicUI/src/era/mi/gui/modeladapter/componentadapters/SimpleGateAdapter.java [deleted file]
LogicUI/src/mograsim/logic/ui/ColorHelper.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/LogicExecuter.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/LogicUICanvas.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/LogicUIStandaloneGUI.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/SimpleLogicUIStandalone.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/examples/RSLatchExample.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/ViewModel.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/components/GUIAndGate.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/components/GUIComponent.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/components/GUIManualSwitch.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/components/GUINotGate.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/components/GUIOrGate.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/components/SimpleRectangularGUIGate.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/wires/GUIWire.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/wires/MovablePin.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/wires/Pin.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/model/wires/WireCrossPoint.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/modeladapter/LogicModelParameters.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/modeladapter/ViewLogicModelAdapter.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/ComponentAdapter.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/ManualSwitchAdapter.java [new file with mode: 0644]
LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/SimpleGateAdapter.java [new file with mode: 0644]
SampleERCP/.project
SampleERCP/.settings/org.eclipse.jdt.ui.prefs
SampleERCP/Application.e4xmi
SampleERCP/META-INF/MANIFEST.MF
SampleERCP/SampleERCP.product [deleted file]
SampleERCP/mograsim.rcp.product [new file with mode: 0644]
SampleERCP/plugin.xml
SampleERCP/src/mograsim/rcp/handlers/AboutHandler.java [new file with mode: 0644]
SampleERCP/src/mograsim/rcp/handlers/OpenHandler.java [new file with mode: 0644]
SampleERCP/src/mograsim/rcp/handlers/QuitHandler.java [new file with mode: 0644]
SampleERCP/src/mograsim/rcp/handlers/SaveHandler.java [new file with mode: 0644]
SampleERCP/src/mograsim/rcp/parts/LogicUIPart.java [new file with mode: 0644]
SampleERCP/src/mograsim/rcp/parts/SamplePart.java [new file with mode: 0644]
SampleERCP/src/mograsim/rcp/splashhandlers/ExtensibleSplashHandler.java [new file with mode: 0644]
SampleERCP/src/sampleercp/handlers/AboutHandler.java [deleted file]
SampleERCP/src/sampleercp/handlers/OpenHandler.java [deleted file]
SampleERCP/src/sampleercp/handlers/QuitHandler.java [deleted file]
SampleERCP/src/sampleercp/handlers/SaveHandler.java [deleted file]
SampleERCP/src/sampleercp/parts/LogicUIPart.java [deleted file]
SampleERCP/src/sampleercp/parts/SamplePart.java [deleted file]
SampleERCP/src/sampleercp/splashhandlers/ExtensibleSplashHandler.java [deleted file]
era.mi/.project
era.mi/.settings/org.eclipse.jdt.core.prefs
era.mi/.settings/org.eclipse.jdt.ui.prefs
era.mi/META-INF/MANIFEST.MF
era.mi/src/era/mi/logic/Util.java [deleted file]
era.mi/src/era/mi/logic/components/BasicComponent.java [deleted file]
era.mi/src/era/mi/logic/components/BitDisplay.java [deleted file]
era.mi/src/era/mi/logic/components/Clock.java [deleted file]
era.mi/src/era/mi/logic/components/Component.java [deleted file]
era.mi/src/era/mi/logic/components/Connector.java [deleted file]
era.mi/src/era/mi/logic/components/Demux.java [deleted file]
era.mi/src/era/mi/logic/components/ManualSwitch.java [deleted file]
era.mi/src/era/mi/logic/components/Merger.java [deleted file]
era.mi/src/era/mi/logic/components/Mux.java [deleted file]
era.mi/src/era/mi/logic/components/Splitter.java [deleted file]
era.mi/src/era/mi/logic/components/TriStateBuffer.java [deleted file]
era.mi/src/era/mi/logic/components/gates/AndGate.java [deleted file]
era.mi/src/era/mi/logic/components/gates/MultiInputGate.java [deleted file]
era.mi/src/era/mi/logic/components/gates/NotGate.java [deleted file]
era.mi/src/era/mi/logic/components/gates/OrGate.java [deleted file]
era.mi/src/era/mi/logic/components/gates/XorGate.java [deleted file]
era.mi/src/era/mi/logic/tests/ComponentTest.java [deleted file]
era.mi/src/era/mi/logic/tests/GUITest.java [deleted file]
era.mi/src/era/mi/logic/tests/TestBitDisplay.java [deleted file]
era.mi/src/era/mi/logic/timeline/Timeline.java [deleted file]
era.mi/src/era/mi/logic/timeline/TimelineEvent.java [deleted file]
era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java [deleted file]
era.mi/src/era/mi/logic/types/Bit.java [deleted file]
era.mi/src/era/mi/logic/types/BitVector.java [deleted file]
era.mi/src/era/mi/logic/types/BitVectorFormatter.java [deleted file]
era.mi/src/era/mi/logic/types/ColorDefinition.java [deleted file]
era.mi/src/era/mi/logic/types/LogicType.java [deleted file]
era.mi/src/era/mi/logic/types/MutationOperation.java [deleted file]
era.mi/src/era/mi/logic/types/StrictLogicType.java [deleted file]
era.mi/src/era/mi/logic/wires/Wire.java [deleted file]
era.mi/src/era/mi/logic/wires/WireObserver.java [deleted file]
era.mi/src/mograsim/logic/core/Util.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/BasicComponent.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/BitDisplay.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/Clock.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/Component.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/Connector.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/Demux.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/ManualSwitch.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/Merger.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/Mux.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/Splitter.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/TriStateBuffer.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/gates/AndGate.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/gates/MultiInputGate.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/gates/NotGate.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/gates/OrGate.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/components/gates/XorGate.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/tests/ComponentTest.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/tests/GUITest.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/tests/TestBitDisplay.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/timeline/Timeline.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/timeline/TimelineEvent.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/timeline/TimelineEventHandler.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/types/Bit.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/types/BitVector.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/types/BitVectorFormatter.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/types/ColorDefinition.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/types/LogicType.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/types/MutationOperation.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/types/StrictLogicType.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/wires/Wire.java [new file with mode: 0644]
era.mi/src/mograsim/logic/core/wires/WireObserver.java [new file with mode: 0644]

index cc7eae3..9ba08bb 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-       <name>LogicUI</name>
+       <name>mograsim.logic.ui</name>
        <comment></comment>
        <projects>
-               <project>era.mi</project>
+               <project>mograsim.logic.core</project>
                <project>SWTZoomableCanvas</project>
        </projects>
        <buildSpec>
index 715c6cc..8f2c0a4 100644 (file)
@@ -1,6 +1,6 @@
 eclipse.preferences.version=1
 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
-formatter_profile=_ERA-MI
+formatter_profile=_MoGraSim
 formatter_settings_version=16
 sp_cleanup.add_default_serial_version_id=true
 sp_cleanup.add_generated_serial_version_id=false
index 9f8199a..c1dcd55 100644 (file)
@@ -1,17 +1,17 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
-Bundle-Name: LogicUI
-Bundle-SymbolicName: LogicUI;singleton:=true
+Bundle-Name: mograsim.logic.ui
+Bundle-SymbolicName: mograsim.logic.ui;singleton:=true
 Bundle-Version: 1.0.0
-Export-Package: era.mi.gui,
era.mi.gui.examples,
era.mi.gui.model,
era.mi.gui.model.components,
era.mi.gui.model.wires,
era.mi.gui.modeladapter,
era.mi.gui.modeladapter.componentadapters
+Export-Package: mograsim.logic.ui,
mograsim.logic.ui.examples,
mograsim.logic.ui.model,
mograsim.logic.ui.model.components,
mograsim.logic.ui.model.wires,
mograsim.logic.ui.modeladapter,
mograsim.logic.ui.modeladapter.componentadapters
 Bundle-RequiredExecutionEnvironment: JavaSE-10
 Require-Bundle: org.eclipse.swt;bundle-version="3.110.0",
  SWTZoomableCanvas;bundle-version="1.0.0";visibility:=reexport,
era.mi;bundle-version="1.0.0";visibility:=reexport
-Automatic-Module-Name: LogicUI
mograsim.logic.core;bundle-version="1.0.0";visibility:=reexport
+Automatic-Module-Name: mograsim.logic.ui
diff --git a/LogicUI/src/era/mi/gui/ColorHelper.java b/LogicUI/src/era/mi/gui/ColorHelper.java
deleted file mode 100644 (file)
index ff6a495..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-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<Color> getColor, Consumer<Color> 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/LogicExecuter.java b/LogicUI/src/era/mi/gui/LogicExecuter.java
deleted file mode 100644 (file)
index 65abd4c..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-package era.mi.gui;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-
-import era.mi.logic.timeline.Timeline;
-
-//TODO maybe move to logic core?
-public class LogicExecuter
-{
-       // TODO replace with LogicModel when it exists
-       private final Timeline timeline;
-
-       private final AtomicBoolean shouldBeRunningLive;
-       private final AtomicBoolean isRunningLive;
-       private final AtomicLong nextExecSimulTime;
-       private final Thread simulationThread;
-
-       public LogicExecuter(Timeline timeline)
-       {
-               this.timeline = timeline;
-
-               timeline.setTimeFunction(System::currentTimeMillis);
-               shouldBeRunningLive = new AtomicBoolean();
-               isRunningLive = new AtomicBoolean();
-               nextExecSimulTime = new AtomicLong();
-               simulationThread = new Thread(() ->
-               {
-                       isRunningLive.set(true);
-                       synchronized (isRunningLive)
-                       {
-                               isRunningLive.notify();
-                       }
-                       while (shouldBeRunningLive.get())
-                       {
-                               // always execute to keep timeline from "hanging behind" for too long
-                               long current = System.currentTimeMillis();
-                               timeline.executeUntil(timeline.laterThan(current), current + 10);
-                               long sleepTime;
-                               if (timeline.hasNext())
-                                       sleepTime = timeline.nextEventTime() - current;
-                               else
-                                       sleepTime = 10000;
-                               try
-                               {
-                                       nextExecSimulTime.set(current + sleepTime);
-                                       if (sleepTime > 0)
-                                               Thread.sleep(sleepTime);
-                               }
-                               catch (@SuppressWarnings("unused") InterruptedException e)
-                               {// do nothing; it is normal execution flow to be interrupted
-                               }
-                       }
-                       isRunningLive.set(false);
-                       synchronized (isRunningLive)
-                       {
-                               isRunningLive.notify();
-                       }
-               });
-               timeline.addEventAddedListener(event ->
-               {
-                       if (isRunningLive.get())
-                               if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
-                                       simulationThread.interrupt();
-               });
-       }
-
-       public void executeNextStep()
-       {
-               timeline.executeNext();
-       }
-
-       public synchronized void startLiveExecution()
-       {
-               if (shouldBeRunningLive.get())
-                       return;
-               shouldBeRunningLive.set(true);
-               simulationThread.start();
-               waitForIsRunning(true);
-       }
-
-       public synchronized void stopLiveExecution()
-       {
-               if (!shouldBeRunningLive.get())
-                       return;
-               shouldBeRunningLive.set(false);
-               simulationThread.interrupt();
-               waitForIsRunning(false);
-       }
-
-       private void waitForIsRunning(boolean expectedState)
-       {
-               while (isRunningLive.get() ^ expectedState)
-                       try
-                       {
-                               synchronized (isRunningLive)
-                               {
-                                       isRunningLive.wait();
-                               }
-                       }
-                       catch (@SuppressWarnings("unused") InterruptedException e)
-                       {// no need to do anything
-                       }
-       }
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/LogicUICanvas.java b/LogicUI/src/era/mi/gui/LogicUICanvas.java
deleted file mode 100644 (file)
index 6355044..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-package era.mi.gui;
-
-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.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;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;
-
-/**
- * Simulation visualizer canvas.
- * 
- * @author Daniel Kirschten
- */
-public class LogicUICanvas extends ZoomableCanvas
-{
-       private static final boolean DRAW_PINS = false;
-
-       private final ViewModel model;
-
-       public LogicUICanvas(Composite parent, int style, ViewModel model)
-       {
-               super(parent, style);
-
-               this.model = model;
-
-               Consumer<Object> redrawConsumer = o -> redrawThreadsafe();
-               Consumer<Pin> pinAddedListener = p ->
-               {
-                       p.addPinMovedListener(redrawConsumer);
-                       redrawThreadsafe();
-               };
-               Consumer<Pin> pinRemovedListener = p ->
-               {
-                       p.removePinMovedListener(redrawConsumer);
-                       redrawThreadsafe();
-               };
-               Consumer<? super GUIComponent> componentAddedListener = c ->
-               {
-                       c.addComponentLookChangedListener(redrawConsumer);
-                       c.addComponentMovedListener(redrawConsumer);
-                       c.addPinAddedListener(pinAddedListener);
-                       c.addPinRemovedListener(pinRemovedListener);
-                       redrawThreadsafe();
-               };
-               model.addComponentAddedListener(componentAddedListener);
-               model.getComponents().forEach(componentAddedListener);
-               model.addComponentRemovedListener(c ->
-               {
-                       c.removeComponentLookChangedListener(redrawConsumer);
-                       c.removeComponentMovedListener(redrawConsumer);
-                       c.removePinAddedListener(pinAddedListener);
-                       c.removePinRemovedListener(pinRemovedListener);
-                       redrawThreadsafe();
-               });
-               Consumer<? super GUIWire> wireAddedListener = w ->
-               {
-                       w.addWireLookChangedListener(redrawConsumer);
-                       redrawThreadsafe();
-               };
-               model.addWireAddedListener(wireAddedListener);
-               model.getWires().forEach(wireAddedListener);
-               model.addWireRemovedListener(w ->
-               {
-                       w.removeWireLookChangedListener(redrawConsumer);
-                       redrawThreadsafe();
-               });
-
-               addZoomedRenderer(gc ->
-               {
-                       gc.setLineWidth(.5);
-                       model.getWires().forEach(w -> w.render(gc));
-                       Rectangle visibleRegion = new Rectangle(offX, offY, gW / zoom, gH / zoom);
-                       model.getComponents().forEach(c -> drawComponent(gc, c, visibleRegion));
-               });
-               addListener(SWT.MouseDown, this::mouseDown);
-       }
-
-       private void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion)
-       {
-               component.render(gc, visibleRegion);
-               if (DRAW_PINS)
-               {
-                       gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_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)
-       {
-               if (e.button == 1)
-               {
-                       Point click = displayToWorldCoords(e.x, e.y);
-                       for (GUIComponent component : model.getComponents())
-                               if (component.getBounds().contains(click) && component.clicked(click.x, click.y))
-                               {
-                                       redraw();
-                                       break;
-                               }
-               }
-       }
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/LogicUIStandaloneGUI.java b/LogicUI/src/era/mi/gui/LogicUIStandaloneGUI.java
deleted file mode 100644 (file)
index 55931cf..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-package era.mi.gui;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
-import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
-
-/**
- * Standalone simulation visualizer graphical user interface.
- * 
- * @author Daniel Kirschten
- */
-public class LogicUIStandaloneGUI
-{
-       private final Display display;
-       private final Shell shell;
-       private final LogicUICanvas ui;
-
-       public LogicUIStandaloneGUI(ViewModel model)
-       {
-               display = new Display();
-               shell = new Shell(display);
-               shell.setLayout(new FillLayout());
-               ui = new LogicUICanvas(shell, SWT.NONE, model);
-
-               ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
-               userInput.buttonDrag = 3;
-               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()
-       {
-               return ui;
-       }
-
-       /**
-        * Opens the UI shell. Returns when the shell is closed.
-        */
-       public void run()
-       {
-               shell.open();
-               while (!shell.isDisposed())
-                       if (!display.readAndDispatch())
-                               display.sleep();
-       }
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/SimpleLogicUIStandalone.java b/LogicUI/src/era/mi/gui/SimpleLogicUIStandalone.java
deleted file mode 100644 (file)
index 0573aa9..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-package era.mi.gui;
-
-import java.util.function.Consumer;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import era.mi.gui.modeladapter.ViewLogicModelAdapter;
-import era.mi.logic.timeline.Timeline;
-
-public class SimpleLogicUIStandalone
-{
-       public static void executeVisualisation(Consumer<ViewModel> setupViewModel)
-       {
-               // setup view model
-               ViewModel viewModel = new ViewModel();
-               setupViewModel.accept(viewModel);
-
-               // convert to logic model
-               LogicModelParameters params = new LogicModelParameters();
-               params.gateProcessTime = 50;
-               params.wireTravelTime = 10;
-               Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
-
-               // initialize UI and executer
-               LogicUIStandaloneGUI ui = new LogicUIStandaloneGUI(viewModel);
-               LogicExecuter exec = new LogicExecuter(timeline);
-
-               // run it
-               exec.startLiveExecution();
-               ui.run();
-               exec.stopLiveExecution();
-       }
-
-       private SimpleLogicUIStandalone()
-       {
-               throw new UnsupportedOperationException("No SimpleLogicUIStandalone instances");
-       }
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/examples/RSLatchExample.java b/LogicUI/src/era/mi/gui/examples/RSLatchExample.java
deleted file mode 100644 (file)
index 08c42c5..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package era.mi.gui.examples;
-
-import era.mi.gui.SimpleLogicUIStandalone;
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.components.GUIManualSwitch;
-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.WireCrossPoint;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-
-public class RSLatchExample
-{
-       public static void main(String[] args)
-       {
-               SimpleLogicUIStandalone.executeVisualisation(RSLatchExample::createRSLatchExample);
-       }
-
-       @SuppressWarnings("unused") // for GUIWires being created
-       public static void createRSLatchExample(ViewModel model)
-       {
-               GUIManualSwitch rIn = new GUIManualSwitch(model);
-               rIn.moveTo(100, 100);
-               GUIManualSwitch sIn = new GUIManualSwitch(model);
-               sIn.moveTo(100, 200);
-
-               GUIOrGate or1 = new GUIOrGate(model, 1);
-               or1.moveTo(160, 102.5);
-               new GUIWire(model, rIn.getOutputPin(), or1.getInputPins().get(0));
-
-               GUIOrGate or2 = new GUIOrGate(model, 1);
-               or2.moveTo(160, 192.5);
-               new GUIWire(model, sIn.getOutputPin(), or2.getInputPins().get(1));
-
-               GUINotGate not1 = new GUINotGate(model, 1);
-               not1.moveTo(200, 107.5);
-               new GUIWire(model, or1.getOutputPin(), not1.getInputPins().get(0));
-
-               GUINotGate not2 = new GUINotGate(model, 1);
-               not2.moveTo(200, 197.5);
-               new GUIWire(model, or2.getOutputPin(), not2.getInputPins().get(0));
-
-               WireCrossPoint p1 = new WireCrossPoint(model, 1);
-               p1.moveTo(250, 112.5);
-               new GUIWire(model, not1.getOutputPin(), p1.getPin());
-               new GUIWire(model, p1.getPin(), or2.getInputPins().get(0), new Point(250, 130), new Point(140, 185), new Point(140, 197.5));
-
-               WireCrossPoint p2 = new WireCrossPoint(model, 1);
-               p2.moveTo(250, 202.5);
-               new GUIWire(model, not2.getOutputPin(), p2.getPin());
-               new GUIWire(model, p2.getPin(), or1.getInputPins().get(1), new Point(250, 185), new Point(140, 130), new Point(140, 117.5));
-
-               WireCrossPoint o1 = new WireCrossPoint(model, 1);
-               o1.moveTo(270, 112.5);
-               new GUIWire(model, p1.getPin(), o1.getPin());
-
-               WireCrossPoint o2 = new WireCrossPoint(model, 1);
-               o2.moveTo(270, 202.5);
-               new GUIWire(model, p2.getPin(), o2.getPin());
-       }
-}
\ 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
deleted file mode 100644 (file)
index 7eb55c1..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-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<GUIComponent> components;
-       private final List<GUIComponent> componentsUnmodifiable;
-       private final List<GUIWire> wires;
-       private final List<GUIWire> wiresUnmodifiable;
-
-       private final List<Consumer<? super GUIComponent>> componentAddedListeners;
-       private final List<Consumer<? super GUIComponent>> componentRemovedListeners;
-       private final List<Consumer<? super GUIWire>> wireAddedListeners;
-       private final List<Consumer<? super GUIWire>> 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<GUIComponent> getComponents()
-       {
-               return componentsUnmodifiable;
-       }
-
-       public List<GUIWire> getWires()
-       {
-               return wiresUnmodifiable;
-       }
-
-       // @formatter:off
-       public void addComponentAddedListener     (Consumer<? super GUIComponent> listener){componentAddedListeners  .add   (listener);}
-       public void addComponentRemovedListener   (Consumer<? super GUIComponent> listener){componentRemovedListeners.add   (listener);}
-       public void addWireAddedListener          (Consumer<? super GUIWire     > listener){wireAddedListeners       .add   (listener);}
-       public void addWireRemovedListener        (Consumer<? super GUIWire     > listener){wireRemovedListeners     .add   (listener);}
-
-       public void removeComponentAddedListener  (Consumer<? super GUIComponent> listener){componentAddedListeners  .remove(listener);}
-       public void removeComponentRemovedListener(Consumer<? super GUIComponent> listener){componentRemovedListeners.remove(listener);}
-       public void removeWireAddedListener       (Consumer<? super GUIWire     > listener){wireAddedListeners       .remove(listener);}
-       public void removeWireRemovedListener     (Consumer<? super GUIWire     > 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
deleted file mode 100644 (file)
index 65f1db4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-package era.mi.gui.model.components;
-
-import era.mi.gui.model.ViewModel;
-
-public class GUIAndGate extends SimpleRectangularGUIGate
-{
-       public GUIAndGate(ViewModel model, int logicWidth)
-       {
-               super(model, logicWidth, "&", false);
-               setInputCount(2);// TODO make variable
-       }
-}
\ 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
deleted file mode 100644 (file)
index b8f49f3..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-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<Pin> pins;
-       protected final List<Pin> pinsUnmodifiable;
-
-       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;
-
-       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.componentLookChangedListeners = 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.
-        */
-       @SuppressWarnings({ "static-method", "unused" }) // this method is inteded to be overridden
-       public boolean clicked(double x, double y)
-       {
-               return false;
-       }
-
-       /**
-        * Returns a list of pins of this component.
-        */
-       public List<Pin> getPins()
-       {
-               return pinsUnmodifiable;
-       }
-
-       // @formatter:off
-       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
-
-       /**
-        * 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;
-               callComponentLookChangedListeners();
-       }
-
-       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
deleted file mode 100644 (file)
index b2a8b01..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-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 final Pin outputPin;
-
-       private ManualSwitch logicSwitch;
-       private ReadEnd end;
-
-       public GUIManualSwitch(ViewModel model)
-       {
-               super(model);
-               setSize(width, height);
-               addPin(this.outputPin = new Pin(this, 1, width, height / 2));
-       }
-
-       @Override
-       public void render(GeneralGC gc, Rectangle visibleRegion)
-       {
-               double posX = getBounds().x;
-               double posY = getBounds().y;
-
-               gc.drawRectangle(posX, posY, 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, posX + (width - textExtent.x) / 2, posY + (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) -> callComponentLookChangedListeners());
-       }
-
-       @Override
-       public boolean clicked(double x, double y)
-       {
-               if (logicSwitch != null)
-                       logicSwitch.toggle();
-               return true;
-       }
-
-       public Pin getOutputPin()
-       {
-               return outputPin;
-       }
-}
\ 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
deleted file mode 100644 (file)
index c22d9b2..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-package era.mi.gui.model.components;
-
-import era.mi.gui.model.ViewModel;
-
-public class GUINotGate extends SimpleRectangularGUIGate
-{
-       public GUINotGate(ViewModel model, int logicWidth)
-       {
-               super(model, logicWidth, "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
deleted file mode 100644 (file)
index a732509..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-package era.mi.gui.model.components;
-
-import era.mi.gui.model.ViewModel;
-
-public class GUIOrGate extends SimpleRectangularGUIGate
-{
-       public GUIOrGate(ViewModel model, int logicWidth)
-       {
-               super(model, logicWidth, "\u22651", false);// ">=1"
-               setInputCount(2);
-       }
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/model/components/SimpleRectangularGUIGate.java b/LogicUI/src/era/mi/gui/model/components/SimpleRectangularGUIGate.java
deleted file mode 100644 (file)
index eb396cc..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-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
diff --git a/LogicUI/src/era/mi/gui/model/wires/GUIWire.java b/LogicUI/src/era/mi/gui/model/wires/GUIWire.java
deleted file mode 100644 (file)
index 6bcbd1c..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-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;
-       public final int logicWidth;
-       private Pin pin1;
-       private Pin pin2;
-       private double[] path;
-
-       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.path[dstI + 0] = path[srcI].x;
-                       this.path[dstI + 1] = path[srcI].y;
-               }
-
-               this.pin1 = pin1;
-               this.pin2 = pin2;
-
-               wireLookChangedListeners = 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) -> callWireLookChangedListeners());
-       }
-
-       public Pin getPin1()
-       {
-               return pin1;
-       }
-
-       public Pin getPin2()
-       {
-               return pin2;
-       }
-
-       // @formatter:off
-       public void addWireLookChangedListener   (Consumer<? super GUIWire> listener) {wireLookChangedListeners.add   (listener);}
-
-       public void removeWireLookChangedListener(Consumer<? super GUIWire> listener) {wireLookChangedListeners.remove(listener);}
-
-       private void callWireLookChangedListeners() {wireLookChangedListeners.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
deleted file mode 100644 (file)
index 949e7d7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-package era.mi.gui.model.wires;
-
-import era.mi.gui.model.components.GUIComponent;
-
-public class MovablePin extends Pin
-{
-       public MovablePin(GUIComponent component, int logicWidth, double relX, double relY)
-       {
-               super(component, logicWidth, 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
deleted file mode 100644 (file)
index abafc07..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-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;
-       public final int logicWidth;
-
-       protected double relX;
-       protected double relY;
-
-       private final List<Consumer<? super Pin>> pinMovedListeners;
-
-       public Pin(GUIComponent component, int logicWidth, double relX, double relY)
-       {
-               this.component = component;
-               this.logicWidth = logicWidth;
-               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<? super Pin> listener){pinMovedListeners.add   (listener);}
-
-       public void removePinMovedListener(Consumer<? super Pin> 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
deleted file mode 100644 (file)
index 04c5f1e..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-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 final Pin pin;
-
-       private ReadEnd end;
-       private final int logicWidth;
-
-       public WireCrossPoint(ViewModel model, int logicWidth)
-       {
-               super(model);
-               this.logicWidth = logicWidth;
-               setSize(0, 0);
-               addPin(this.pin = new Pin(this, logicWidth, 0, 0));
-       }
-
-       @Override
-       public void render(GeneralGC gc, Rectangle visibleRegion)
-       {
-               Rectangle bounds = getBounds();
-               ColorHelper.executeWithDifferentBackground(gc, BitVectorFormatter.formatAsColor(end),
-                               () -> gc.fillOval(bounds.x - 1, bounds.y - 1, 2, 2));
-       }
-
-       public void setLogicModelBinding(ReadEnd end)
-       {
-               this.end = end;
-               end.addObserver((i, o) -> callComponentLookChangedListeners());
-       }
-
-       public int getLogicWidth()
-       {
-               return logicWidth;
-       }
-
-       public Pin getPin()
-       {
-               return pin;
-       }
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/modeladapter/LogicModelParameters.java b/LogicUI/src/era/mi/gui/modeladapter/LogicModelParameters.java
deleted file mode 100644 (file)
index 435f708..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package era.mi.gui.modeladapter;
-
-public class LogicModelParameters
-{
-       public int wireTravelTime;
-       public int gateProcessTime;
-}
\ 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
deleted file mode 100644 (file)
index 1e7d341..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-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.ManualSwitchAdapter;
-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
-       {
-               Set<ComponentAdapter<? extends GUIComponent>> componentAdaptersModifiable = new HashSet<>();
-               componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUIOrGate.class, OrGate::new));
-               componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUIAndGate.class, AndGate::new));
-               componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUINotGate.class, (t, p, o, i) -> new NotGate(t, p, i[0], o)));
-               componentAdaptersModifiable.add(new ManualSwitchAdapter());
-               // TODO list all "primitive" adapters here
-               componentAdapters = Collections.unmodifiableMap(
-                               componentAdaptersModifiable.stream().collect(Collectors.toMap(ComponentAdapter::getSupportedClass, Function.identity())));
-       }
-
-       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())
-               {
-                       if (!(guiComp instanceof WireCrossPoint))
-                               oneToOneComponents.put(guiComp, createAndLinkComponent(timeline, params, guiComp, logicWiresPerPinUnmodifiable,
-                                               componentAdapters.get(guiComp.getClass())));
-                       else
-                       {
-                               WireCrossPoint guiCompCasted = (WireCrossPoint) guiComp;
-                               guiCompCasted.setLogicModelBinding(logicWiresPerPin.get(guiCompCasted.getPin()).createReadOnlyEnd());
-                       }
-               }
-
-               // 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
diff --git a/LogicUI/src/era/mi/gui/modeladapter/componentadapters/ComponentAdapter.java b/LogicUI/src/era/mi/gui/modeladapter/componentadapters/ComponentAdapter.java
deleted file mode 100644 (file)
index c109d73..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-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 Class<G> getSupportedClass();
-
-       public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G guiComponent,
-                       Map<Pin, Wire> logicWiresPerPin);
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/modeladapter/componentadapters/ManualSwitchAdapter.java b/LogicUI/src/era/mi/gui/modeladapter/componentadapters/ManualSwitchAdapter.java
deleted file mode 100644 (file)
index 3a6ea05..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-package era.mi.gui.modeladapter.componentadapters;
-
-import java.util.Map;
-
-import era.mi.gui.model.components.GUIManualSwitch;
-import era.mi.gui.model.wires.Pin;
-import era.mi.gui.modeladapter.LogicModelParameters;
-import era.mi.logic.components.Component;
-import era.mi.logic.components.ManualSwitch;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.wires.Wire;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public class ManualSwitchAdapter implements ComponentAdapter<GUIManualSwitch>
-{
-       @Override
-       public Class<GUIManualSwitch> getSupportedClass()
-       {
-               return GUIManualSwitch.class;
-       }
-
-       @Override
-       public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, GUIManualSwitch guiComponent,
-                       Map<Pin, Wire> logicWiresPerPin)
-       {
-               ReadWriteEnd end = logicWiresPerPin.get(guiComponent.getOutputPin()).createReadWriteEnd();
-               ManualSwitch manualSwitch = new ManualSwitch(timeline, end);
-               guiComponent.setLogicModelBinding(manualSwitch, end);
-               return manualSwitch;
-       }
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/modeladapter/componentadapters/SimpleGateAdapter.java b/LogicUI/src/era/mi/gui/modeladapter/componentadapters/SimpleGateAdapter.java
deleted file mode 100644 (file)
index b244973..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-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<G extends SimpleRectangularGUIGate> implements ComponentAdapter<G>
-{
-       private final Class<G> supportedClass;
-       private final ComponentConstructor constructor;
-
-       public SimpleGateAdapter(Class<G> supportedClass, ComponentConstructor constructor)
-       {
-               this.supportedClass = supportedClass;
-               this.constructor = constructor;
-       }
-
-       @Override
-       public Class<G> getSupportedClass()
-       {
-               return supportedClass;
-       }
-
-       @Override
-       public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G 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
diff --git a/LogicUI/src/mograsim/logic/ui/ColorHelper.java b/LogicUI/src/mograsim/logic/ui/ColorHelper.java
new file mode 100644 (file)
index 0000000..886c6f7
--- /dev/null
@@ -0,0 +1,91 @@
+package mograsim.logic.ui;
+
+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 mograsim.logic.core.types.ColorDefinition;
+import mograsim.logic.core.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<Color> getColor, Consumer<Color> 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/mograsim/logic/ui/LogicExecuter.java b/LogicUI/src/mograsim/logic/ui/LogicExecuter.java
new file mode 100644 (file)
index 0000000..dec5c53
--- /dev/null
@@ -0,0 +1,105 @@
+package mograsim.logic.ui;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import mograsim.logic.core.timeline.Timeline;
+
+//TODO maybe move to logic core?
+public class LogicExecuter
+{
+       // TODO replace with LogicModel when it exists
+       private final Timeline timeline;
+
+       private final AtomicBoolean shouldBeRunningLive;
+       private final AtomicBoolean isRunningLive;
+       private final AtomicLong nextExecSimulTime;
+       private final Thread simulationThread;
+
+       public LogicExecuter(Timeline timeline)
+       {
+               this.timeline = timeline;
+
+               timeline.setTimeFunction(System::currentTimeMillis);
+               shouldBeRunningLive = new AtomicBoolean();
+               isRunningLive = new AtomicBoolean();
+               nextExecSimulTime = new AtomicLong();
+               simulationThread = new Thread(() ->
+               {
+                       isRunningLive.set(true);
+                       synchronized (isRunningLive)
+                       {
+                               isRunningLive.notify();
+                       }
+                       while (shouldBeRunningLive.get())
+                       {
+                               // always execute to keep timeline from "hanging behind" for too long
+                               long current = System.currentTimeMillis();
+                               timeline.executeUntil(timeline.laterThan(current), current + 10);
+                               long sleepTime;
+                               if (timeline.hasNext())
+                                       sleepTime = timeline.nextEventTime() - current;
+                               else
+                                       sleepTime = 10000;
+                               try
+                               {
+                                       nextExecSimulTime.set(current + sleepTime);
+                                       if (sleepTime > 0)
+                                               Thread.sleep(sleepTime);
+                               }
+                               catch (@SuppressWarnings("unused") InterruptedException e)
+                               {// do nothing; it is normal execution flow to be interrupted
+                               }
+                       }
+                       isRunningLive.set(false);
+                       synchronized (isRunningLive)
+                       {
+                               isRunningLive.notify();
+                       }
+               });
+               timeline.addEventAddedListener(event ->
+               {
+                       if (isRunningLive.get())
+                               if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
+                                       simulationThread.interrupt();
+               });
+       }
+
+       public void executeNextStep()
+       {
+               timeline.executeNext();
+       }
+
+       public synchronized void startLiveExecution()
+       {
+               if (shouldBeRunningLive.get())
+                       return;
+               shouldBeRunningLive.set(true);
+               simulationThread.start();
+               waitForIsRunning(true);
+       }
+
+       public synchronized void stopLiveExecution()
+       {
+               if (!shouldBeRunningLive.get())
+                       return;
+               shouldBeRunningLive.set(false);
+               simulationThread.interrupt();
+               waitForIsRunning(false);
+       }
+
+       private void waitForIsRunning(boolean expectedState)
+       {
+               while (isRunningLive.get() ^ expectedState)
+                       try
+                       {
+                               synchronized (isRunningLive)
+                               {
+                                       isRunningLive.wait();
+                               }
+                       }
+                       catch (@SuppressWarnings("unused") InterruptedException e)
+                       {// no need to do anything
+                       }
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/LogicUICanvas.java b/LogicUI/src/mograsim/logic/ui/LogicUICanvas.java
new file mode 100644 (file)
index 0000000..4761839
--- /dev/null
@@ -0,0 +1,114 @@
+package mograsim.logic.ui;
+
+import java.util.function.Consumer;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.components.GUIComponent;
+import mograsim.logic.ui.model.wires.GUIWire;
+import mograsim.logic.ui.model.wires.Pin;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;
+
+/**
+ * Simulation visualizer canvas.
+ * 
+ * @author Daniel Kirschten
+ */
+public class LogicUICanvas extends ZoomableCanvas
+{
+       private static final boolean DRAW_PINS = false;
+
+       private final ViewModel model;
+
+       public LogicUICanvas(Composite parent, int style, ViewModel model)
+       {
+               super(parent, style);
+
+               this.model = model;
+
+               Consumer<Object> redrawConsumer = o -> redrawThreadsafe();
+               Consumer<Pin> pinAddedListener = p ->
+               {
+                       p.addPinMovedListener(redrawConsumer);
+                       redrawThreadsafe();
+               };
+               Consumer<Pin> pinRemovedListener = p ->
+               {
+                       p.removePinMovedListener(redrawConsumer);
+                       redrawThreadsafe();
+               };
+               Consumer<? super GUIComponent> componentAddedListener = c ->
+               {
+                       c.addComponentLookChangedListener(redrawConsumer);
+                       c.addComponentMovedListener(redrawConsumer);
+                       c.addPinAddedListener(pinAddedListener);
+                       c.addPinRemovedListener(pinRemovedListener);
+                       redrawThreadsafe();
+               };
+               model.addComponentAddedListener(componentAddedListener);
+               model.getComponents().forEach(componentAddedListener);
+               model.addComponentRemovedListener(c ->
+               {
+                       c.removeComponentLookChangedListener(redrawConsumer);
+                       c.removeComponentMovedListener(redrawConsumer);
+                       c.removePinAddedListener(pinAddedListener);
+                       c.removePinRemovedListener(pinRemovedListener);
+                       redrawThreadsafe();
+               });
+               Consumer<? super GUIWire> wireAddedListener = w ->
+               {
+                       w.addWireLookChangedListener(redrawConsumer);
+                       redrawThreadsafe();
+               };
+               model.addWireAddedListener(wireAddedListener);
+               model.getWires().forEach(wireAddedListener);
+               model.addWireRemovedListener(w ->
+               {
+                       w.removeWireLookChangedListener(redrawConsumer);
+                       redrawThreadsafe();
+               });
+
+               addZoomedRenderer(gc ->
+               {
+                       gc.setLineWidth(.5);
+                       model.getWires().forEach(w -> w.render(gc));
+                       Rectangle visibleRegion = new Rectangle(offX, offY, gW / zoom, gH / zoom);
+                       model.getComponents().forEach(c -> drawComponent(gc, c, visibleRegion));
+               });
+               addListener(SWT.MouseDown, this::mouseDown);
+       }
+
+       private void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion)
+       {
+               component.render(gc, visibleRegion);
+               if (DRAW_PINS)
+               {
+                       gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_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)
+       {
+               if (e.button == 1)
+               {
+                       Point click = displayToWorldCoords(e.x, e.y);
+                       for (GUIComponent component : model.getComponents())
+                               if (component.getBounds().contains(click) && component.clicked(click.x, click.y))
+                               {
+                                       redraw();
+                                       break;
+                               }
+               }
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/LogicUIStandaloneGUI.java b/LogicUI/src/mograsim/logic/ui/LogicUIStandaloneGUI.java
new file mode 100644 (file)
index 0000000..f39727c
--- /dev/null
@@ -0,0 +1,59 @@
+package mograsim.logic.ui;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
+
+/**
+ * Standalone simulation visualizer graphical user interface.
+ * 
+ * @author Daniel Kirschten
+ */
+public class LogicUIStandaloneGUI
+{
+       private final Display display;
+       private final Shell shell;
+       private final LogicUICanvas ui;
+
+       public LogicUIStandaloneGUI(ViewModel model)
+       {
+               display = new Display();
+               shell = new Shell(display);
+               shell.setLayout(new FillLayout());
+               ui = new LogicUICanvas(shell, SWT.NONE, model);
+
+               ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
+               userInput.buttonDrag = 3;
+               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()
+       {
+               return ui;
+       }
+
+       /**
+        * Opens the UI shell. Returns when the shell is closed.
+        */
+       public void run()
+       {
+               shell.open();
+               while (!shell.isDisposed())
+                       if (!display.readAndDispatch())
+                               display.sleep();
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/SimpleLogicUIStandalone.java b/LogicUI/src/mograsim/logic/ui/SimpleLogicUIStandalone.java
new file mode 100644 (file)
index 0000000..ef0beb3
--- /dev/null
@@ -0,0 +1,38 @@
+package mograsim.logic.ui;
+
+import java.util.function.Consumer;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+import mograsim.logic.ui.modeladapter.ViewLogicModelAdapter;
+
+public class SimpleLogicUIStandalone
+{
+       public static void executeVisualisation(Consumer<ViewModel> setupViewModel)
+       {
+               // setup view model
+               ViewModel viewModel = new ViewModel();
+               setupViewModel.accept(viewModel);
+
+               // convert to logic model
+               LogicModelParameters params = new LogicModelParameters();
+               params.gateProcessTime = 50;
+               params.wireTravelTime = 10;
+               Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
+
+               // initialize UI and executer
+               LogicUIStandaloneGUI ui = new LogicUIStandaloneGUI(viewModel);
+               LogicExecuter exec = new LogicExecuter(timeline);
+
+               // run it
+               exec.startLiveExecution();
+               ui.run();
+               exec.stopLiveExecution();
+       }
+
+       private SimpleLogicUIStandalone()
+       {
+               throw new UnsupportedOperationException("No SimpleLogicUIStandalone instances");
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/examples/RSLatchExample.java b/LogicUI/src/mograsim/logic/ui/examples/RSLatchExample.java
new file mode 100644 (file)
index 0000000..f787c81
--- /dev/null
@@ -0,0 +1,61 @@
+package mograsim.logic.ui.examples;
+
+import mograsim.logic.ui.SimpleLogicUIStandalone;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.components.GUIManualSwitch;
+import mograsim.logic.ui.model.components.GUINotGate;
+import mograsim.logic.ui.model.components.GUIOrGate;
+import mograsim.logic.ui.model.wires.GUIWire;
+import mograsim.logic.ui.model.wires.WireCrossPoint;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+
+public class RSLatchExample
+{
+       public static void main(String[] args)
+       {
+               SimpleLogicUIStandalone.executeVisualisation(RSLatchExample::createRSLatchExample);
+       }
+
+       @SuppressWarnings("unused") // for GUIWires being created
+       public static void createRSLatchExample(ViewModel model)
+       {
+               GUIManualSwitch rIn = new GUIManualSwitch(model);
+               rIn.moveTo(100, 100);
+               GUIManualSwitch sIn = new GUIManualSwitch(model);
+               sIn.moveTo(100, 200);
+
+               GUIOrGate or1 = new GUIOrGate(model, 1);
+               or1.moveTo(160, 102.5);
+               new GUIWire(model, rIn.getOutputPin(), or1.getInputPins().get(0));
+
+               GUIOrGate or2 = new GUIOrGate(model, 1);
+               or2.moveTo(160, 192.5);
+               new GUIWire(model, sIn.getOutputPin(), or2.getInputPins().get(1));
+
+               GUINotGate not1 = new GUINotGate(model, 1);
+               not1.moveTo(200, 107.5);
+               new GUIWire(model, or1.getOutputPin(), not1.getInputPins().get(0));
+
+               GUINotGate not2 = new GUINotGate(model, 1);
+               not2.moveTo(200, 197.5);
+               new GUIWire(model, or2.getOutputPin(), not2.getInputPins().get(0));
+
+               WireCrossPoint p1 = new WireCrossPoint(model, 1);
+               p1.moveTo(250, 112.5);
+               new GUIWire(model, not1.getOutputPin(), p1.getPin());
+               new GUIWire(model, p1.getPin(), or2.getInputPins().get(0), new Point(250, 130), new Point(140, 185), new Point(140, 197.5));
+
+               WireCrossPoint p2 = new WireCrossPoint(model, 1);
+               p2.moveTo(250, 202.5);
+               new GUIWire(model, not2.getOutputPin(), p2.getPin());
+               new GUIWire(model, p2.getPin(), or1.getInputPins().get(1), new Point(250, 185), new Point(140, 130), new Point(140, 117.5));
+
+               WireCrossPoint o1 = new WireCrossPoint(model, 1);
+               o1.moveTo(270, 112.5);
+               new GUIWire(model, p1.getPin(), o1.getPin());
+
+               WireCrossPoint o2 = new WireCrossPoint(model, 1);
+               o2.moveTo(270, 202.5);
+               new GUIWire(model, p2.getPin(), o2.getPin());
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/model/ViewModel.java b/LogicUI/src/mograsim/logic/ui/model/ViewModel.java
new file mode 100644 (file)
index 0000000..31cd1a8
--- /dev/null
@@ -0,0 +1,110 @@
+package mograsim.logic.ui.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+import mograsim.logic.ui.model.components.GUIComponent;
+import mograsim.logic.ui.model.wires.GUIWire;
+
+public class ViewModel
+{
+       private final List<GUIComponent> components;
+       private final List<GUIComponent> componentsUnmodifiable;
+       private final List<GUIWire> wires;
+       private final List<GUIWire> wiresUnmodifiable;
+
+       private final List<Consumer<? super GUIComponent>> componentAddedListeners;
+       private final List<Consumer<? super GUIComponent>> componentRemovedListeners;
+       private final List<Consumer<? super GUIWire>> wireAddedListeners;
+       private final List<Consumer<? super GUIWire>> 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<GUIComponent> getComponents()
+       {
+               return componentsUnmodifiable;
+       }
+
+       public List<GUIWire> getWires()
+       {
+               return wiresUnmodifiable;
+       }
+
+       // @formatter:off
+       public void addComponentAddedListener     (Consumer<? super GUIComponent> listener){componentAddedListeners  .add   (listener);}
+       public void addComponentRemovedListener   (Consumer<? super GUIComponent> listener){componentRemovedListeners.add   (listener);}
+       public void addWireAddedListener          (Consumer<? super GUIWire     > listener){wireAddedListeners       .add   (listener);}
+       public void addWireRemovedListener        (Consumer<? super GUIWire     > listener){wireRemovedListeners     .add   (listener);}
+
+       public void removeComponentAddedListener  (Consumer<? super GUIComponent> listener){componentAddedListeners  .remove(listener);}
+       public void removeComponentRemovedListener(Consumer<? super GUIComponent> listener){componentRemovedListeners.remove(listener);}
+       public void removeWireAddedListener       (Consumer<? super GUIWire     > listener){wireAddedListeners       .remove(listener);}
+       public void removeWireRemovedListener     (Consumer<? super GUIWire     > 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/mograsim/logic/ui/model/components/GUIAndGate.java b/LogicUI/src/mograsim/logic/ui/model/components/GUIAndGate.java
new file mode 100644 (file)
index 0000000..8efea1c
--- /dev/null
@@ -0,0 +1,12 @@
+package mograsim.logic.ui.model.components;
+
+import mograsim.logic.ui.model.ViewModel;
+
+public class GUIAndGate extends SimpleRectangularGUIGate
+{
+       public GUIAndGate(ViewModel model, int logicWidth)
+       {
+               super(model, logicWidth, "&", false);
+               setInputCount(2);// TODO make variable
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/model/components/GUIComponent.java b/LogicUI/src/mograsim/logic/ui/model/components/GUIComponent.java
new file mode 100644 (file)
index 0000000..c3e4529
--- /dev/null
@@ -0,0 +1,119 @@
+package mograsim.logic.ui.model.components;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.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<Pin> pins;
+       protected final List<Pin> pinsUnmodifiable;
+
+       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;
+
+       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.componentLookChangedListeners = 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.
+        */
+       @SuppressWarnings({ "static-method", "unused" }) // this method is inteded to be overridden
+       public boolean clicked(double x, double y)
+       {
+               return false;
+       }
+
+       /**
+        * Returns a list of pins of this component.
+        */
+       public List<Pin> getPins()
+       {
+               return pinsUnmodifiable;
+       }
+
+       // @formatter:off
+       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
+
+       /**
+        * 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;
+               callComponentLookChangedListeners();
+       }
+
+       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/mograsim/logic/ui/model/components/GUIManualSwitch.java b/LogicUI/src/mograsim/logic/ui/model/components/GUIManualSwitch.java
new file mode 100644 (file)
index 0000000..a89bc6a
--- /dev/null
@@ -0,0 +1,67 @@
+package mograsim.logic.ui.model.components;
+
+import mograsim.logic.core.components.ManualSwitch;
+import mograsim.logic.core.types.BitVectorFormatter;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.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 GUIManualSwitch extends GUIComponent
+{
+       private static final double width = 20;
+       private static final double height = 15;
+       private static final double fontHeight = 5;
+
+       private final Pin outputPin;
+
+       private ManualSwitch logicSwitch;
+       private ReadEnd end;
+
+       public GUIManualSwitch(ViewModel model)
+       {
+               super(model);
+               setSize(width, height);
+               addPin(this.outputPin = new Pin(this, 1, width, height / 2));
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               double posX = getBounds().x;
+               double posY = getBounds().y;
+
+               gc.drawRectangle(posX, posY, 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, posX + (width - textExtent.x) / 2, posY + (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) -> callComponentLookChangedListeners());
+       }
+
+       @Override
+       public boolean clicked(double x, double y)
+       {
+               if (logicSwitch != null)
+                       logicSwitch.toggle();
+               return true;
+       }
+
+       public Pin getOutputPin()
+       {
+               return outputPin;
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/model/components/GUINotGate.java b/LogicUI/src/mograsim/logic/ui/model/components/GUINotGate.java
new file mode 100644 (file)
index 0000000..7a6865f
--- /dev/null
@@ -0,0 +1,12 @@
+package mograsim.logic.ui.model.components;
+
+import mograsim.logic.ui.model.ViewModel;
+
+public class GUINotGate extends SimpleRectangularGUIGate
+{
+       public GUINotGate(ViewModel model, int logicWidth)
+       {
+               super(model, logicWidth, "1", true);
+               setInputCount(1);
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/model/components/GUIOrGate.java b/LogicUI/src/mograsim/logic/ui/model/components/GUIOrGate.java
new file mode 100644 (file)
index 0000000..3a3c324
--- /dev/null
@@ -0,0 +1,12 @@
+package mograsim.logic.ui.model.components;
+
+import mograsim.logic.ui.model.ViewModel;
+
+public class GUIOrGate extends SimpleRectangularGUIGate
+{
+       public GUIOrGate(ViewModel model, int logicWidth)
+       {
+               super(model, logicWidth, "\u22651", false);// ">=1"
+               setInputCount(2);
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/model/components/SimpleRectangularGUIGate.java b/LogicUI/src/mograsim/logic/ui/model/components/SimpleRectangularGUIGate.java
new file mode 100644 (file)
index 0000000..b09d9c9
--- /dev/null
@@ -0,0 +1,89 @@
+package mograsim.logic.ui.model.components;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.wires.MovablePin;
+import mograsim.logic.ui.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
diff --git a/LogicUI/src/mograsim/logic/ui/model/wires/GUIWire.java b/LogicUI/src/mograsim/logic/ui/model/wires/GUIWire.java
new file mode 100644 (file)
index 0000000..2512b88
--- /dev/null
@@ -0,0 +1,100 @@
+package mograsim.logic.ui.model.wires;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import mograsim.logic.core.types.BitVectorFormatter;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.ui.ColorHelper;
+import mograsim.logic.ui.model.ViewModel;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+
+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>> 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.path[dstI + 0] = path[srcI].x;
+                       this.path[dstI + 1] = path[srcI].y;
+               }
+
+               this.pin1 = pin1;
+               this.pin2 = pin2;
+
+               wireLookChangedListeners = 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) -> callWireLookChangedListeners());
+       }
+
+       public Pin getPin1()
+       {
+               return pin1;
+       }
+
+       public Pin getPin2()
+       {
+               return pin2;
+       }
+
+       // @formatter:off
+       public void addWireLookChangedListener   (Consumer<? super GUIWire> listener) {wireLookChangedListeners.add   (listener);}
+
+       public void removeWireLookChangedListener(Consumer<? super GUIWire> listener) {wireLookChangedListeners.remove(listener);}
+
+       private void callWireLookChangedListeners() {wireLookChangedListeners.forEach(l -> l.accept(this));}
+       // @formatter:on
+
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/model/wires/MovablePin.java b/LogicUI/src/mograsim/logic/ui/model/wires/MovablePin.java
new file mode 100644 (file)
index 0000000..4036432
--- /dev/null
@@ -0,0 +1,17 @@
+package mograsim.logic.ui.model.wires;
+
+import mograsim.logic.ui.model.components.GUIComponent;
+
+public class MovablePin extends Pin
+{
+       public MovablePin(GUIComponent component, int logicWidth, double relX, double relY)
+       {
+               super(component, logicWidth, 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/mograsim/logic/ui/model/wires/Pin.java b/LogicUI/src/mograsim/logic/ui/model/wires/Pin.java
new file mode 100644 (file)
index 0000000..350de8d
--- /dev/null
@@ -0,0 +1,68 @@
+package mograsim.logic.ui.model.wires;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import mograsim.logic.ui.model.components.GUIComponent;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+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, int logicWidth, double relX, double relY)
+       {
+               this.component = component;
+               this.logicWidth = logicWidth;
+               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<? super Pin> listener){pinMovedListeners.add   (listener);}
+
+       public void removePinMovedListener(Consumer<? super Pin> 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/mograsim/logic/ui/model/wires/WireCrossPoint.java b/LogicUI/src/mograsim/logic/ui/model/wires/WireCrossPoint.java
new file mode 100644 (file)
index 0000000..34f6903
--- /dev/null
@@ -0,0 +1,49 @@
+package mograsim.logic.ui.model.wires;
+
+import mograsim.logic.core.types.BitVectorFormatter;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.ui.ColorHelper;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.components.GUIComponent;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+public class WireCrossPoint extends GUIComponent
+{
+       private final Pin pin;
+
+       private ReadEnd end;
+       private final int logicWidth;
+
+       public WireCrossPoint(ViewModel model, int logicWidth)
+       {
+               super(model);
+               this.logicWidth = logicWidth;
+               setSize(0, 0);
+               addPin(this.pin = new Pin(this, logicWidth, 0, 0));
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               Rectangle bounds = getBounds();
+               ColorHelper.executeWithDifferentBackground(gc, BitVectorFormatter.formatAsColor(end),
+                               () -> gc.fillOval(bounds.x - 1, bounds.y - 1, 2, 2));
+       }
+
+       public void setLogicModelBinding(ReadEnd end)
+       {
+               this.end = end;
+               end.addObserver((i, o) -> callComponentLookChangedListeners());
+       }
+
+       public int getLogicWidth()
+       {
+               return logicWidth;
+       }
+
+       public Pin getPin()
+       {
+               return pin;
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/modeladapter/LogicModelParameters.java b/LogicUI/src/mograsim/logic/ui/modeladapter/LogicModelParameters.java
new file mode 100644 (file)
index 0000000..010cdd1
--- /dev/null
@@ -0,0 +1,7 @@
+package mograsim.logic.ui.modeladapter;
+
+public class LogicModelParameters
+{
+       public int wireTravelTime;
+       public int gateProcessTime;
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/modeladapter/ViewLogicModelAdapter.java b/LogicUI/src/mograsim/logic/ui/modeladapter/ViewLogicModelAdapter.java
new file mode 100644 (file)
index 0000000..076d64b
--- /dev/null
@@ -0,0 +1,146 @@
+package 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.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import mograsim.logic.core.components.Component;
+import mograsim.logic.core.components.gates.AndGate;
+import mograsim.logic.core.components.gates.NotGate;
+import mograsim.logic.core.components.gates.OrGate;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.model.components.GUIAndGate;
+import mograsim.logic.ui.model.components.GUIComponent;
+import mograsim.logic.ui.model.components.GUINotGate;
+import mograsim.logic.ui.model.components.GUIOrGate;
+import mograsim.logic.ui.model.wires.GUIWire;
+import mograsim.logic.ui.model.wires.Pin;
+import mograsim.logic.ui.model.wires.WireCrossPoint;
+import mograsim.logic.ui.modeladapter.componentadapters.ComponentAdapter;
+import mograsim.logic.ui.modeladapter.componentadapters.ManualSwitchAdapter;
+import mograsim.logic.ui.modeladapter.componentadapters.SimpleGateAdapter;
+
+public class ViewLogicModelAdapter
+{
+       private final static Map<Class<? extends GUIComponent>, ComponentAdapter<? extends GUIComponent>> componentAdapters;
+       static
+       {
+               Set<ComponentAdapter<? extends GUIComponent>> componentAdaptersModifiable = new HashSet<>();
+               componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUIOrGate.class, OrGate::new));
+               componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUIAndGate.class, AndGate::new));
+               componentAdaptersModifiable.add(new SimpleGateAdapter<>(GUINotGate.class, (t, p, o, i) -> new NotGate(t, p, i[0], o)));
+               componentAdaptersModifiable.add(new ManualSwitchAdapter());
+               // TODO list all "primitive" adapters here
+               componentAdapters = Collections.unmodifiableMap(
+                               componentAdaptersModifiable.stream().collect(Collectors.toMap(ComponentAdapter::getSupportedClass, Function.identity())));
+       }
+
+       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())
+               {
+                       if (!(guiComp instanceof WireCrossPoint))
+                               oneToOneComponents.put(guiComp, createAndLinkComponent(timeline, params, guiComp, logicWiresPerPinUnmodifiable,
+                                               componentAdapters.get(guiComp.getClass())));
+                       else
+                       {
+                               WireCrossPoint guiCompCasted = (WireCrossPoint) guiComp;
+                               guiCompCasted.setLogicModelBinding(logicWiresPerPin.get(guiCompCasted.getPin()).createReadOnlyEnd());
+                       }
+               }
+
+               // 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
diff --git a/LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/ComponentAdapter.java b/LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/ComponentAdapter.java
new file mode 100644 (file)
index 0000000..9be1b96
--- /dev/null
@@ -0,0 +1,18 @@
+package mograsim.logic.ui.modeladapter.componentadapters;
+
+import java.util.Map;
+
+import mograsim.logic.core.components.Component;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.ui.model.components.GUIComponent;
+import mograsim.logic.ui.model.wires.Pin;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+
+public interface ComponentAdapter<G extends GUIComponent>
+{
+       public Class<G> getSupportedClass();
+
+       public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G guiComponent,
+                       Map<Pin, Wire> logicWiresPerPin);
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/ManualSwitchAdapter.java b/LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/ManualSwitchAdapter.java
new file mode 100644 (file)
index 0000000..c27cbdf
--- /dev/null
@@ -0,0 +1,31 @@
+package mograsim.logic.ui.modeladapter.componentadapters;
+
+import java.util.Map;
+
+import mograsim.logic.core.components.Component;
+import mograsim.logic.core.components.ManualSwitch;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+import mograsim.logic.ui.model.components.GUIManualSwitch;
+import mograsim.logic.ui.model.wires.Pin;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+
+public class ManualSwitchAdapter implements ComponentAdapter<GUIManualSwitch>
+{
+       @Override
+       public Class<GUIManualSwitch> getSupportedClass()
+       {
+               return GUIManualSwitch.class;
+       }
+
+       @Override
+       public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, GUIManualSwitch guiComponent,
+                       Map<Pin, Wire> logicWiresPerPin)
+       {
+               ReadWriteEnd end = logicWiresPerPin.get(guiComponent.getOutputPin()).createReadWriteEnd();
+               ManualSwitch manualSwitch = new ManualSwitch(timeline, end);
+               guiComponent.setLogicModelBinding(manualSwitch, end);
+               return manualSwitch;
+       }
+}
\ No newline at end of file
diff --git a/LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/SimpleGateAdapter.java b/LogicUI/src/mograsim/logic/ui/modeladapter/componentadapters/SimpleGateAdapter.java
new file mode 100644 (file)
index 0000000..f88308b
--- /dev/null
@@ -0,0 +1,48 @@
+package mograsim.logic.ui.modeladapter.componentadapters;
+
+import java.util.List;
+import java.util.Map;
+
+import mograsim.logic.core.components.Component;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+import mograsim.logic.ui.model.components.SimpleRectangularGUIGate;
+import mograsim.logic.ui.model.wires.Pin;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+
+public class SimpleGateAdapter<G extends SimpleRectangularGUIGate> implements ComponentAdapter<G>
+{
+       private final Class<G> supportedClass;
+       private final ComponentConstructor constructor;
+
+       public SimpleGateAdapter(Class<G> supportedClass, ComponentConstructor constructor)
+       {
+               this.supportedClass = supportedClass;
+               this.constructor = constructor;
+       }
+
+       @Override
+       public Class<G> getSupportedClass()
+       {
+               return supportedClass;
+       }
+
+       @Override
+       public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G 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
index dd05f6c..4577bb5 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-       <name>SampleERCP</name>
+       <name>mograsim.rcp</name>
        <comment></comment>
        <projects>
-               <project>LogicUI</project>
+               <project>mograsim.rcp</project>
        </projects>
        <buildSpec>
                <buildCommand>
index 614cb32..5ae94b6 100644 (file)
@@ -1,6 +1,6 @@
 eclipse.preferences.version=1
 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
-formatter_profile=_ERA-MI
+formatter_profile=_MoGraSim
 formatter_settings_version=16
 org.eclipse.jdt.ui.text.custom_code_templates=
 sp_cleanup.add_default_serial_version_id=true
index 6e2ca3e..7581568 100644 (file)
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_6wlLcMgZEeSyMNYR5xypkQ" elementId="Sample.application" bindingContexts="_6wlLecgZEeSyMNYR5xypkQ">
-  <children xsi:type="basic:TrimmedWindow" xmi:id="_6wlLccgZEeSyMNYR5xypkQ" elementId="Sample.window.main" label="Sample RCP4" iconURI="platform:/plugin/SampleERCP/icons/app/ico_16t.png" width="500" height="400">
+  <children xsi:type="basic:TrimmedWindow" xmi:id="_6wlLccgZEeSyMNYR5xypkQ" elementId="Sample.window.main" label="Sample RCP4" iconURI="platform:/plugin/mograsim.rcp/icons/app/ico_16t.png" width="500" height="400">
     <children xsi:type="basic:PartSashContainer" xmi:id="_6wlLksgZEeSyMNYR5xypkQ" elementId="Sample.partsashcontainer.sample">
       <children xsi:type="basic:PartStack" xmi:id="_6wlLk8gZEeSyMNYR5xypkQ" elementId="Sample.partstack.sample">
-        <children xsi:type="basic:Part" xmi:id="_6wlLlMgZEeSyMNYR5xypkQ" elementId="Sample.part.sample" contributionURI="bundleclass://SampleERCP/sampleercp.parts.SamplePart" label="Sample Part" iconURI="platform:/plugin/SampleERCP/icons/home.png"/>
-        <children xsi:type="basic:Part" xmi:id="_cldhcH1HEema06ZDPR6BSw" elementId="sampleercp.part.logicui" contributionURI="bundleclass://SampleERCP/sampleercp.parts.LogicUIPart" label="LogicUI part"/>
+        <children xsi:type="basic:Part" xmi:id="_6wlLlMgZEeSyMNYR5xypkQ" elementId="Sample.part.sample" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.parts.SamplePart" label="Sample Part" iconURI="platform:/plugin/mograsim.rcp/icons/home.png"/>
+        <children xsi:type="basic:Part" xmi:id="_cldhcH1HEema06ZDPR6BSw" elementId="mograsim.rcp.part.logicui" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.parts.LogicUIPart" label="LogicUI part"/>
       </children>
       <children xsi:type="basic:PartStack" xmi:id="_l2EzYG6wEemo__tDmTCqCQ" elementId="sample.partstack.0">
         <children xsi:type="basic:Part" xmi:id="_mW1XEG6wEemo__tDmTCqCQ" elementId="sample.part.none" label="None" tooltip="Something"/>
@@ -12,8 +12,8 @@
     </children>
     <mainMenu xmi:id="_6wlLicgZEeSyMNYR5xypkQ" elementId="org.eclipse.ui.main.menu">
       <children xsi:type="menu:Menu" xmi:id="_6wlLisgZEeSyMNYR5xypkQ" elementId="file" label="File">
-        <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLi8gZEeSyMNYR5xypkQ" elementId="Sample.handleditem.file.open" label="Open" iconURI="platform:/plugin/SampleERCP/icons/open_in_app.png" command="_6wlLgMgZEeSyMNYR5xypkQ"/>
-        <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLjMgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.save" label="Save" iconURI="platform:/plugin/SampleERCP/icons/save_edit.png" command="_6wlLg8gZEeSyMNYR5xypkQ"/>
+        <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLi8gZEeSyMNYR5xypkQ" elementId="Sample.handleditem.file.open" label="Open" iconURI="platform:/plugin/mograsim.rcp/icons/open_in_app.png" command="_6wlLgMgZEeSyMNYR5xypkQ"/>
+        <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLjMgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.save" label="Save" iconURI="platform:/plugin/mograsim.rcp/icons/save_edit.png" command="_6wlLg8gZEeSyMNYR5xypkQ"/>
         <children xsi:type="menu:HandledMenuItem" xmi:id="_6wlLjcgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.quit" label="Quit" command="_6wlLfMgZEeSyMNYR5xypkQ"/>
       </children>
       <children xsi:type="menu:Menu" xmi:id="_6wlLjsgZEeSyMNYR5xypkQ" elementId="help" label="Help">
     </mainMenu>
     <trimBars xmi:id="_6wlLlcgZEeSyMNYR5xypkQ" elementId="Sample.trimbar.top">
       <children xsi:type="menu:ToolBar" xmi:id="_6wlLlsgZEeSyMNYR5xypkQ" elementId="org.eclipse.ui.main.toolbar">
-        <children xsi:type="menu:HandledToolItem" xmi:id="_6wlLmMgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.trimbar.top.save" iconURI="platform:/plugin/SampleERCP/icons/save_edit.png" command="_6wlLg8gZEeSyMNYR5xypkQ"/>
-        <children xsi:type="menu:HandledToolItem" xmi:id="_6wlLl8gZEeSyMNYR5xypkQ" elementId="Sample.handleditem.trimbar.top.open" iconURI="platform:/plugin/SampleERCP/icons/open_in_app.png" command="_6wlLgMgZEeSyMNYR5xypkQ"/>
+        <children xsi:type="menu:HandledToolItem" xmi:id="_6wlLmMgZEeSyMNYR5xypkQ" elementId="Sample.handleditem.trimbar.top.save" iconURI="platform:/plugin/mograsim.rcp/icons/save_edit.png" command="_6wlLg8gZEeSyMNYR5xypkQ"/>
+        <children xsi:type="menu:HandledToolItem" xmi:id="_6wlLl8gZEeSyMNYR5xypkQ" elementId="Sample.handleditem.trimbar.top.open" iconURI="platform:/plugin/mograsim.rcp/icons/open_in_app.png" command="_6wlLgMgZEeSyMNYR5xypkQ"/>
       </children>
     </trimBars>
   </children>
-  <handlers xmi:id="_6wlLfcgZEeSyMNYR5xypkQ" elementId="sample.handler.quitCommand" contributionURI="bundleclass://SampleERCP/sampleercp.handlers.QuitHandler" command="_6wlLfMgZEeSyMNYR5xypkQ"/>
-  <handlers xmi:id="_6wlLgcgZEeSyMNYR5xypkQ" elementId="sample.handler.openCommand" contributionURI="bundleclass://SampleERCP/sampleercp.handlers.OpenHandler" command="_6wlLgMgZEeSyMNYR5xypkQ"/>
-  <handlers xmi:id="_6wlLhMgZEeSyMNYR5xypkQ" elementId="sample.handler.saveCommand" contributionURI="bundleclass://SampleERCP/sampleercp.handlers.SaveHandler" command="_6wlLg8gZEeSyMNYR5xypkQ"/>
-  <handlers xmi:id="_6wlLh8gZEeSyMNYR5xypkQ" elementId="sample.handler.aboutCommand" contributionURI="bundleclass://SampleERCP/sampleercp.handlers.AboutHandler" command="_6wlLhsgZEeSyMNYR5xypkQ"/>
+  <handlers xmi:id="_6wlLfcgZEeSyMNYR5xypkQ" elementId="sample.handler.quitCommand" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.handlers.QuitHandler" command="_6wlLfMgZEeSyMNYR5xypkQ"/>
+  <handlers xmi:id="_6wlLgcgZEeSyMNYR5xypkQ" elementId="sample.handler.openCommand" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.handlers.OpenHandler" command="_6wlLgMgZEeSyMNYR5xypkQ"/>
+  <handlers xmi:id="_6wlLhMgZEeSyMNYR5xypkQ" elementId="sample.handler.saveCommand" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.handlers.SaveHandler" command="_6wlLg8gZEeSyMNYR5xypkQ"/>
+  <handlers xmi:id="_6wlLh8gZEeSyMNYR5xypkQ" elementId="sample.handler.aboutCommand" contributionURI="bundleclass://mograsim.rcp/mograsim.rcp.handlers.AboutHandler" command="_6wlLhsgZEeSyMNYR5xypkQ"/>
   <bindingTables xmi:id="_6wlLfsgZEeSyMNYR5xypkQ" elementId="Sample.bindingtable" bindingContext="_6wlLecgZEeSyMNYR5xypkQ">
     <bindings xmi:id="_6wlLf8gZEeSyMNYR5xypkQ" elementId="Sample.keybinding.m1q" keySequence="M1+Q" command="_6wlLfMgZEeSyMNYR5xypkQ"/>
     <bindings xmi:id="_6wlLgsgZEeSyMNYR5xypkQ" elementId="Sample.keybinding.m1o" keySequence="M1+O" command="_6wlLgMgZEeSyMNYR5xypkQ"/>
index c0a156b..2597b53 100644 (file)
@@ -1,7 +1,7 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name
-Bundle-SymbolicName: SampleERCP;singleton:=true
+Bundle-SymbolicName: mograsim.rcp;singleton:=true
 Bundle-Version: 1.0.0.qualifier
 Bundle-Vendor: %Bundle-Vendor
 Require-Bundle: org.eclipse.core.runtime;bundle-version="3.15.200",
@@ -12,10 +12,9 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.15.200",
  org.eclipse.e4.ui.di;bundle-version="1.2.500",
  org.eclipse.ui.workbench;bundle-version="3.113.0",
  javax.annotation;bundle-version="1.2.0",
- LogicUI,
- era.mi
+ mograsim.logic.ui
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Automatic-Module-Name: Sample
-Export-Package: sampleercp.handlers;uses:="org.eclipse.swt.widgets,org.eclipse.e4.ui.workbench,org.eclipse.e4.ui.workbench.modeling",
sampleercp.parts;uses:="org.eclipse.swt.widgets",
sampleercp.splashhandlers
+Export-Package: mograsim.rcp.handlers;uses:="org.eclipse.swt.widgets,org.eclipse.e4.ui.workbench,org.eclipse.e4.ui.workbench.modeling",
mograsim.rcp.parts;uses:="org.eclipse.swt.widgets",
mograsim.rcp.splashhandlers
diff --git a/SampleERCP/SampleERCP.product b/SampleERCP/SampleERCP.product
deleted file mode 100644 (file)
index 5d61b95..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?pde version="3.5"?>
-
-<product name="Simulator WIP" uid="sample" id="SampleERCP.product" application="org.eclipse.e4.ui.workbench.swt.E4Application" version="1.0.0.qualifier" useFeatures="false" includeLaunchers="true">
-
-   <aboutInfo>
-      <text>
-         Example
-      </text>
-   </aboutInfo>
-
-   <configIni use="default">
-   </configIni>
-
-   <launcherArgs>
-      <programArgs>-clearPersistedState
-      </programArgs>
-      <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts
-      </vmArgsMac>
-   </launcherArgs>
-
-   <windowImages i16="/SampleERCP/icons/app/ico_16t.png" i32="/SampleERCP/icons/app/ico_32t.png" i48="/SampleERCP/icons/app/ico_48t.png" i64="/SampleERCP/icons/app/ico_64t.png" i128="/SampleERCP/icons/app/ico_128t.png" i256="/SampleERCP/icons/app/ico_256t.png"/>
-
-   <splash
-      handlerType="extensible" />
-   <launcher name="Sample">
-      <linux icon="/SampleERCP/icons/app/ico_256t.xpm"/>
-      <macosx icon="/SampleERCP/icons/app/ico_256t.icns"/>
-      <win useIco="true">
-         <ico path="/SampleERCP/icons/app/ico_all.ico"/>
-         <bmp/>
-      </win>
-   </launcher>
-
-   <vm>
-      <linux include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</linux>
-      <macos include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</macos>
-      <windows include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</windows>
-   </vm>
-
-   <license>
-        <url>https://www.eclipse.org/legal/epl-2.0/</url>
-        <text>
-   Copyright (c) 2019 Christian Femers, Daniel Kirschten and Fabian Stemmler
-
-This program and the accompanying materials are made
-available under the terms of the Eclipse Public License 2.0
-which is available at https://www.eclipse.org/legal/epl-2.0/
-
-This Source Code may also be made available under the following Secondary
-Licenses when the conditions for such availability set forth in the Eclipse
-Public License, v. 2.0 are satisfied: GNU General Public License, version 2
-with the GNU Classpath Exception which is
-available at https://www.gnu.org/software/classpath/license.html.
-
-SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-         </text>
-   </license>
-
-   <plugins>
-      <plugin id="LogicUI"/>
-      <plugin id="SWTBufferedCanvas"/>
-      <plugin id="SWTObjectWrappers"/>
-      <plugin id="SWTZoomableCanvas"/>
-      <plugin id="SampleERCP"/>
-      <plugin id="com.ibm.icu"/>
-      <plugin id="era.mi"/>
-      <plugin id="javax.annotation"/>
-      <plugin id="javax.inject"/>
-      <plugin id="javax.servlet"/>
-      <plugin id="javax.xml"/>
-      <plugin id="org.apache.batik.constants"/>
-      <plugin id="org.apache.batik.css"/>
-      <plugin id="org.apache.batik.i18n"/>
-      <plugin id="org.apache.batik.util"/>
-      <plugin id="org.apache.commons.io"/>
-      <plugin id="org.apache.commons.jxpath"/>
-      <plugin id="org.apache.commons.logging"/>
-      <plugin id="org.apache.felix.gogo.runtime"/>
-      <plugin id="org.apache.felix.scr"/>
-      <plugin id="org.apache.log4j"/>
-      <plugin id="org.apache.xmlgraphics"/>
-      <plugin id="org.eclipse.ant.core"/>
-      <plugin id="org.eclipse.core.commands"/>
-      <plugin id="org.eclipse.core.contenttype"/>
-      <plugin id="org.eclipse.core.databinding"/>
-      <plugin id="org.eclipse.core.databinding.beans"/>
-      <plugin id="org.eclipse.core.databinding.observable"/>
-      <plugin id="org.eclipse.core.databinding.property"/>
-      <plugin id="org.eclipse.core.expressions"/>
-      <plugin id="org.eclipse.core.filesystem"/>
-      <plugin id="org.eclipse.core.filesystem.win32.x86_64" fragment="true"/>
-      <plugin id="org.eclipse.core.jobs"/>
-      <plugin id="org.eclipse.core.resources"/>
-      <plugin id="org.eclipse.core.resources.win32.x86_64" fragment="true"/>
-      <plugin id="org.eclipse.core.runtime"/>
-      <plugin id="org.eclipse.core.variables"/>
-      <plugin id="org.eclipse.e4.core.commands"/>
-      <plugin id="org.eclipse.e4.core.contexts"/>
-      <plugin id="org.eclipse.e4.core.di"/>
-      <plugin id="org.eclipse.e4.core.di.annotations"/>
-      <plugin id="org.eclipse.e4.core.di.extensions"/>
-      <plugin id="org.eclipse.e4.core.di.extensions.supplier"/>
-      <plugin id="org.eclipse.e4.core.services"/>
-      <plugin id="org.eclipse.e4.emf.xpath"/>
-      <plugin id="org.eclipse.e4.ui.bindings"/>
-      <plugin id="org.eclipse.e4.ui.css.core"/>
-      <plugin id="org.eclipse.e4.ui.css.swt"/>
-      <plugin id="org.eclipse.e4.ui.css.swt.theme"/>
-      <plugin id="org.eclipse.e4.ui.di"/>
-      <plugin id="org.eclipse.e4.ui.model.workbench"/>
-      <plugin id="org.eclipse.e4.ui.services"/>
-      <plugin id="org.eclipse.e4.ui.swt.gtk" fragment="true"/>
-      <plugin id="org.eclipse.e4.ui.widgets"/>
-      <plugin id="org.eclipse.e4.ui.workbench"/>
-      <plugin id="org.eclipse.e4.ui.workbench.addons.swt"/>
-      <plugin id="org.eclipse.e4.ui.workbench.renderers.swt"/>
-      <plugin id="org.eclipse.e4.ui.workbench.renderers.swt.cocoa" fragment="true"/>
-      <plugin id="org.eclipse.e4.ui.workbench.swt"/>
-      <plugin id="org.eclipse.e4.ui.workbench3"/>
-      <plugin id="org.eclipse.emf.common"/>
-      <plugin id="org.eclipse.emf.databinding"/>
-      <plugin id="org.eclipse.emf.ecore"/>
-      <plugin id="org.eclipse.emf.ecore.change"/>
-      <plugin id="org.eclipse.emf.ecore.xmi"/>
-      <plugin id="org.eclipse.equinox.app"/>
-      <plugin id="org.eclipse.equinox.bidi"/>
-      <plugin id="org.eclipse.equinox.common"/>
-      <plugin id="org.eclipse.equinox.concurrent"/>
-      <plugin id="org.eclipse.equinox.event"/>
-      <plugin id="org.eclipse.equinox.preferences"/>
-      <plugin id="org.eclipse.equinox.region" fragment="true"/>
-      <plugin id="org.eclipse.equinox.registry"/>
-      <plugin id="org.eclipse.equinox.supplement"/>
-      <plugin id="org.eclipse.equinox.transforms.hook" fragment="true"/>
-      <plugin id="org.eclipse.equinox.weaving.hook" fragment="true"/>
-      <plugin id="org.eclipse.fx.osgi" fragment="true"/>
-      <plugin id="org.eclipse.help"/>
-      <plugin id="org.eclipse.jdt.annotation"/>
-      <plugin id="org.eclipse.jface"/>
-      <plugin id="org.eclipse.jface.databinding"/>
-      <plugin id="org.eclipse.osgi"/>
-      <plugin id="org.eclipse.osgi.compatibility.state" fragment="true"/>
-      <plugin id="org.eclipse.osgi.services"/>
-      <plugin id="org.eclipse.osgi.util"/>
-      <plugin id="org.eclipse.pde.ds.lib"/>
-      <plugin id="org.eclipse.swt"/>
-      <plugin id="org.eclipse.swt.cocoa.macosx.x86_64" fragment="true"/>
-      <plugin id="org.eclipse.swt.gtk.linux.ppc64le" fragment="true"/>
-      <plugin id="org.eclipse.swt.gtk.linux.x86_64" fragment="true"/>
-      <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
-      <plugin id="org.eclipse.ui"/>
-      <plugin id="org.eclipse.ui.cocoa" fragment="true"/>
-      <plugin id="org.eclipse.ui.workbench"/>
-      <plugin id="org.eclipse.xtext.logging" fragment="true"/>
-      <plugin id="org.w3c.css.sac"/>
-      <plugin id="org.w3c.dom.events"/>
-      <plugin id="org.w3c.dom.smil"/>
-      <plugin id="org.w3c.dom.svg"/>
-   </plugins>
-
-   <configurations>
-      <plugin id="org.apache.felix.scr" autoStart="true" startLevel="2" />
-      <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="0" />
-      <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" />
-      <plugin id="org.eclipse.equinox.event" autoStart="true" startLevel="2" />
-      <plugin id="org.eclipse.equinox.simpleconfigurator" autoStart="true" startLevel="1" />
-   </configurations>
-
-   <preferencesInfo>
-      <targetfile overwrite="false"/>
-   </preferencesInfo>
-
-   <cssInfo>
-      <file path="/SampleERCP/css/default.css"/>
-   </cssInfo>
-
-</product>
diff --git a/SampleERCP/mograsim.rcp.product b/SampleERCP/mograsim.rcp.product
new file mode 100644 (file)
index 0000000..3614ce7
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?pde version="3.5"?>
+
+<product name="Simulator WIP" uid="sample" id="mograsim.rcp.product" application="org.eclipse.e4.ui.workbench.swt.E4Application" version="1.0.0.qualifier" useFeatures="false" includeLaunchers="true">
+
+   <aboutInfo>
+      <text>
+         Example
+      </text>
+   </aboutInfo>
+
+   <configIni use="default">
+   </configIni>
+
+   <launcherArgs>
+      <programArgs>-clearPersistedState
+      </programArgs>
+      <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts
+      </vmArgsMac>
+   </launcherArgs>
+
+   <windowImages i16="/mograsim.rcp/icons/app/ico_16t.png" i32="/mograsim.rcp/icons/app/ico_32t.png" i48="/mograsim.rcp/icons/app/ico_48t.png" i64="/mograsim.rcp/icons/app/ico_64t.png" i128="/mograsim.rcp/icons/app/ico_128t.png" i256="/mograsim.rcp/icons/app/ico_256t.png"/>
+
+   <splash
+      handlerType="extensible" />
+   <launcher name="Sample">
+      <linux icon="/mograsim.rcp/icons/app/ico_256t.xpm"/>
+      <macosx icon="/mograsim.rcp/icons/app/ico_256t.icns"/>
+      <win useIco="true">
+         <ico path="/mograsim.rcp/icons/app/ico_all.ico"/>
+         <bmp/>
+      </win>
+   </launcher>
+
+
+   <vm>
+      <linux include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</linux>
+      <macos include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</macos>
+      <windows include="false">org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11</windows>
+   </vm>
+
+   <license>
+        <url>https://www.eclipse.org/legal/epl-2.0/</url>
+        <text>
+   Copyright (c) 2019 Christian Femers, Daniel Kirschten and Fabian Stemmler
+
+This program and the accompanying materials are made
+available under the terms of the Eclipse Public License 2.0
+which is available at https://www.eclipse.org/legal/epl-2.0/
+
+This Source Code may also be made available under the following Secondary
+Licenses when the conditions for such availability set forth in the Eclipse
+Public License, v. 2.0 are satisfied: GNU General Public License, version 2
+with the GNU Classpath Exception which is
+available at https://www.gnu.org/software/classpath/license.html.
+
+SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+         </text>
+   </license>
+
+   <plugins>
+      <plugin id="SWTBufferedCanvas"/>
+      <plugin id="SWTObjectWrappers"/>
+      <plugin id="SWTZoomableCanvas"/>
+      <plugin id="com.ibm.icu"/>
+      <plugin id="javax.annotation"/>
+      <plugin id="javax.inject"/>
+      <plugin id="javax.xml"/>
+      <plugin id="mograsim.logic.core"/>
+      <plugin id="mograsim.logic.ui"/>
+      <plugin id="mograsim.rcp"/>
+      <plugin id="org.apache.batik.constants"/>
+      <plugin id="org.apache.batik.css"/>
+      <plugin id="org.apache.batik.i18n"/>
+      <plugin id="org.apache.batik.util"/>
+      <plugin id="org.apache.commons.io"/>
+      <plugin id="org.apache.commons.jxpath"/>
+      <plugin id="org.apache.commons.logging"/>
+      <plugin id="org.apache.xmlgraphics"/>
+      <plugin id="org.eclipse.core.commands"/>
+      <plugin id="org.eclipse.core.contenttype"/>
+      <plugin id="org.eclipse.core.databinding"/>
+      <plugin id="org.eclipse.core.databinding.observable"/>
+      <plugin id="org.eclipse.core.databinding.property"/>
+      <plugin id="org.eclipse.core.expressions"/>
+      <plugin id="org.eclipse.core.jobs"/>
+      <plugin id="org.eclipse.core.runtime"/>
+      <plugin id="org.eclipse.e4.core.commands"/>
+      <plugin id="org.eclipse.e4.core.contexts"/>
+      <plugin id="org.eclipse.e4.core.di"/>
+      <plugin id="org.eclipse.e4.core.di.annotations"/>
+      <plugin id="org.eclipse.e4.core.di.extensions"/>
+      <plugin id="org.eclipse.e4.core.di.extensions.supplier"/>
+      <plugin id="org.eclipse.e4.core.services"/>
+      <plugin id="org.eclipse.e4.emf.xpath"/>
+      <plugin id="org.eclipse.e4.ui.bindings"/>
+      <plugin id="org.eclipse.e4.ui.css.core"/>
+      <plugin id="org.eclipse.e4.ui.css.swt"/>
+      <plugin id="org.eclipse.e4.ui.css.swt.theme"/>
+      <plugin id="org.eclipse.e4.ui.di"/>
+      <plugin id="org.eclipse.e4.ui.model.workbench"/>
+      <plugin id="org.eclipse.e4.ui.services"/>
+      <plugin id="org.eclipse.e4.ui.widgets"/>
+      <plugin id="org.eclipse.e4.ui.workbench"/>
+      <plugin id="org.eclipse.e4.ui.workbench.addons.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench.renderers.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench.swt"/>
+      <plugin id="org.eclipse.e4.ui.workbench3"/>
+      <plugin id="org.eclipse.emf.common"/>
+      <plugin id="org.eclipse.emf.ecore"/>
+      <plugin id="org.eclipse.emf.ecore.change"/>
+      <plugin id="org.eclipse.emf.ecore.xmi"/>
+      <plugin id="org.eclipse.equinox.app"/>
+      <plugin id="org.eclipse.equinox.common"/>
+      <plugin id="org.eclipse.equinox.preferences"/>
+      <plugin id="org.eclipse.equinox.region" fragment="true"/>
+      <plugin id="org.eclipse.equinox.registry"/>
+      <plugin id="org.eclipse.equinox.supplement"/>
+      <plugin id="org.eclipse.equinox.transforms.hook" fragment="true"/>
+      <plugin id="org.eclipse.equinox.weaving.hook" fragment="true"/>
+      <plugin id="org.eclipse.help"/>
+      <plugin id="org.eclipse.jface"/>
+      <plugin id="org.eclipse.jface.databinding"/>
+      <plugin id="org.eclipse.osgi"/>
+      <plugin id="org.eclipse.osgi.compatibility.state" fragment="true"/>
+      <plugin id="org.eclipse.osgi.services"/>
+      <plugin id="org.eclipse.osgi.util"/>
+      <plugin id="org.eclipse.swt"/>
+      <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
+      <plugin id="org.eclipse.ui.workbench"/>
+      <plugin id="org.w3c.css.sac"/>
+      <plugin id="org.w3c.dom.events"/>
+      <plugin id="org.w3c.dom.smil"/>
+      <plugin id="org.w3c.dom.svg"/>
+   </plugins>
+
+   <configurations>
+      <plugin id="org.eclipse.equinox.simpleconfigurator" autoStart="true" startLevel="1" />
+   </configurations>
+
+   <preferencesInfo>
+      <targetfile overwrite="false"/>
+   </preferencesInfo>
+
+   <cssInfo>
+      <file path="/mograsim.rcp/css/default.css"/>
+   </cssInfo>
+
+</product>
index 5091573..06832aa 100644 (file)
@@ -11,7 +11,7 @@
             name="Simulator WIP">
          <property
                name="applicationCSS"
-               value="platform:/plugin/SampleERCP/css/default.css">
+               value="platform:/plugin/mograsim.rcp/css/default.css">
          </property>
          <property
                name="appName"
    <extension
          point="org.eclipse.ui.splashHandlers">
       <splashHandler
-            class="sampleercp.splashHandlers.ExtensibleSplashHandler"
-            id="sampleercp.splashHandlers.extensible">
+            class="mograsim.rcp.splashhandlers.ExtensibleSplashHandler"
+            id="mograsim.rcp.splashHandlers.extensible">
       </splashHandler>
       <splashHandlerProductBinding
-            productId="SampleERCP.product"
-            splashId="sampleercp.splashHandlers.extensible">
-      </splashHandlerProductBinding>
-      <splashHandler
-            class="sampleercp.splashhandlers.ExtensibleSplashHandler"
-            id="sampleercp.splashHandlers.extensible">
-      </splashHandler>
-      <splashHandlerProductBinding
-            productId="SampleERCP.product"
-            splashId="sampleercp.splashHandlers.extensible">
+            productId="mograsim.rcp.product"
+            splashId="mograsim.rcp.splashHandlers.extensible">
       </splashHandlerProductBinding>
    </extension>
    <extension
-         point="SampleERCP.splashExtension">
+         point="mograsim.rcp.splashExtension">
       <splashExtension
             icon="icons/af.png"
             id="af"
diff --git a/SampleERCP/src/mograsim/rcp/handlers/AboutHandler.java b/SampleERCP/src/mograsim/rcp/handlers/AboutHandler.java
new file mode 100644 (file)
index 0000000..ede71bd
--- /dev/null
@@ -0,0 +1,14 @@
+package mograsim.rcp.handlers;
+
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Shell;
+
+public class AboutHandler
+{
+       @Execute
+       public void execute(Shell shell)
+       {
+               MessageDialog.openInformation(shell, "About", "Sample RCP4");
+       }
+}
diff --git a/SampleERCP/src/mograsim/rcp/handlers/OpenHandler.java b/SampleERCP/src/mograsim/rcp/handlers/OpenHandler.java
new file mode 100644 (file)
index 0000000..f0ca44c
--- /dev/null
@@ -0,0 +1,16 @@
+package mograsim.rcp.handlers;
+
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+
+public class OpenHandler
+{
+
+       @Execute
+       public void execute(Shell shell)
+       {
+               FileDialog dialog = new FileDialog(shell);
+               dialog.open();
+       }
+}
diff --git a/SampleERCP/src/mograsim/rcp/handlers/QuitHandler.java b/SampleERCP/src/mograsim/rcp/handlers/QuitHandler.java
new file mode 100644 (file)
index 0000000..27e56ca
--- /dev/null
@@ -0,0 +1,18 @@
+package mograsim.rcp.handlers;
+
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.workbench.IWorkbench;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Shell;
+
+public class QuitHandler
+{
+       @Execute
+       public void execute(IWorkbench workbench, Shell shell)
+       {
+               if (MessageDialog.openConfirm(shell, "Confirmation", "Do you want to exit?"))
+               {
+                       workbench.close();
+               }
+       }
+}
diff --git a/SampleERCP/src/mograsim/rcp/handlers/SaveHandler.java b/SampleERCP/src/mograsim/rcp/handlers/SaveHandler.java
new file mode 100644 (file)
index 0000000..a3fd6be
--- /dev/null
@@ -0,0 +1,25 @@
+package mograsim.rcp.handlers;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+
+public class SaveHandler
+{
+
+       @CanExecute
+       public boolean canExecute(EPartService partService)
+       {
+               if (partService != null)
+               {
+                       return !partService.getDirtyParts().isEmpty();
+               }
+               return false;
+       }
+
+       @Execute
+       public void execute(EPartService partService)
+       {
+               partService.saveAll(false);
+       }
+}
\ No newline at end of file
diff --git a/SampleERCP/src/mograsim/rcp/parts/LogicUIPart.java b/SampleERCP/src/mograsim/rcp/parts/LogicUIPart.java
new file mode 100644 (file)
index 0000000..9f2a36a
--- /dev/null
@@ -0,0 +1,54 @@
+package mograsim.rcp.parts;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.ui.LogicExecuter;
+import mograsim.logic.ui.LogicUICanvas;
+import mograsim.logic.ui.examples.RSLatchExample;
+import mograsim.logic.ui.model.ViewModel;
+import mograsim.logic.ui.modeladapter.LogicModelParameters;
+import mograsim.logic.ui.modeladapter.ViewLogicModelAdapter;
+import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
+
+public class LogicUIPart
+{
+       @Inject
+       private MPart part;
+
+       @PostConstruct
+       public void create(Composite parent)
+       {
+               // setup view model
+               ViewModel viewModel = new ViewModel();
+               RSLatchExample.createRSLatchExample(viewModel);
+
+               // convert to logic model
+               LogicModelParameters params = new LogicModelParameters();
+               params.gateProcessTime = 50;
+               params.wireTravelTime = 10;
+               Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
+
+               // initialize UI
+               LogicUICanvas ui = new LogicUICanvas(parent, SWT.NONE, viewModel);
+               ui.addTransformListener((x, y, z) -> part.setDirty(z < 1));
+               ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
+               userInput.buttonDrag = 3;
+               userInput.buttonZoom = 2;
+               userInput.enableUserInput();
+
+               // initialize executer
+               LogicExecuter exec = new LogicExecuter(timeline);
+
+               // run it
+               exec.startLiveExecution();
+
+               // TODO find a better condition when to stop
+               ui.addDisposeListener(e -> exec.stopLiveExecution());
+       }
+}
\ No newline at end of file
diff --git a/SampleERCP/src/mograsim/rcp/parts/SamplePart.java b/SampleERCP/src/mograsim/rcp/parts/SamplePart.java
new file mode 100644 (file)
index 0000000..f37ffb7
--- /dev/null
@@ -0,0 +1,61 @@
+package mograsim.rcp.parts;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.e4.ui.di.Persist;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+public class SamplePart
+{
+
+       private TableViewer tableViewer;
+
+       @Inject
+       private MPart part;
+
+       @PostConstruct
+       public void createComposite(Composite parent)
+       {
+               parent.setLayout(new GridLayout(1, false));
+
+               Text txtInput = new Text(parent, SWT.BORDER);
+               txtInput.setMessage("Enter text to mark part as dirty");
+               txtInput.addModifyListener(e -> part.setDirty(true));
+               txtInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+               tableViewer = new TableViewer(parent);
+
+               tableViewer.setContentProvider(ArrayContentProvider.getInstance());
+               tableViewer.setInput(createInitialDataModel());
+               tableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
+       }
+
+       @Focus
+       public void setFocus()
+       {
+               tableViewer.getTable().setFocus();
+       }
+
+       @Persist
+       public void save()
+       {
+               part.setDirty(false);
+       }
+
+       private static List<String> createInitialDataModel()
+       {
+               return Arrays.asList("Sample item 1", "Sample item 2", "Sample item 3", "Sample item 4", "Sample item 5");
+       }
+}
\ No newline at end of file
diff --git a/SampleERCP/src/mograsim/rcp/splashhandlers/ExtensibleSplashHandler.java b/SampleERCP/src/mograsim/rcp/splashhandlers/ExtensibleSplashHandler.java
new file mode 100644 (file)
index 0000000..d32258b
--- /dev/null
@@ -0,0 +1,328 @@
+package mograsim.rcp.splashhandlers;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.splash.AbstractSplashHandler;
+
+/**
+ * @since 3.3
+ *
+ */
+public class ExtensibleSplashHandler extends AbstractSplashHandler
+{
+
+       private ArrayList<Image> fImageList;
+
+       private ArrayList<String> fTooltipList;
+
+       private static final String F_SPLASH_EXTENSION_ID = "Sample.splashExtension"; // NON-NLS-1
+
+       private static final String F_ELEMENT_ICON = "icon"; // NON-NLS-1
+
+       private static final String F_ELEMENT_TOOLTIP = "tooltip"; // NON-NLS-1
+
+       private static final String F_DEFAULT_TOOLTIP = "Image"; // NON-NLS-1
+
+       private static final int F_IMAGE_WIDTH = 50;
+
+       private static final int F_IMAGE_HEIGHT = 50;
+
+       private static final int F_SPLASH_SCREEN_BEVEL = 5;
+
+       private Composite fIconPanel;
+
+       /**
+        * 
+        */
+       public ExtensibleSplashHandler()
+       {
+               fImageList = new ArrayList<>();
+               fTooltipList = new ArrayList<>();
+               fIconPanel = null;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.splash.AbstractSplashHandler#init(org.eclipse.swt.widgets. Shell)
+        */
+       @Override
+       public void init(Shell splash)
+       {
+               // Store the shell
+               super.init(splash);
+               // Configure the shell layout
+               configureUISplash();
+               // Load all splash extensions
+               loadSplashExtensions();
+               // If no splash extensions were loaded abort the splash handler
+               if (!hasSplashExtensions())
+               {
+                       return;
+               }
+               // Create UI
+               createUI();
+               // Configure the image panel bounds
+               configureUICompositeIconPanelBounds();
+               // Enter event loop and prevent the RCP application from
+               // loading until all work is done
+               doEventLoop();
+       }
+
+       /**
+        * @return
+        */
+       private boolean hasSplashExtensions()
+       {
+               return !fImageList.isEmpty();
+       }
+
+       /**
+        * 
+        */
+       private void createUI()
+       {
+               // Create the icon panel
+               createUICompositeIconPanel();
+               // Create the images
+               createUIImages();
+       }
+
+       /**
+        * 
+        */
+       private void createUIImages()
+       {
+               Iterator<Image> imageIterator = fImageList.iterator();
+               Iterator<String> tooltipIterator = fTooltipList.iterator();
+               int i = 1;
+               int columnCount = ((GridLayout) fIconPanel.getLayout()).numColumns;
+               // Create all the images
+               // Abort if we run out of columns (left-over images will not fit within
+               // the usable splash screen width)
+               while (imageIterator.hasNext() && (i <= columnCount))
+               {
+                       Image image = imageIterator.next();
+                       String tooltip = tooltipIterator.next();
+                       // Create the image using a label widget
+                       createUILabel(image, tooltip);
+                       i++;
+               }
+       }
+
+       /**
+        * @param image
+        * @param tooltip
+        */
+       private void createUILabel(Image image, String tooltip)
+       {
+               // Create the label (no text)
+               Label label = new Label(fIconPanel, SWT.NONE);
+               label.setImage(image);
+               label.setToolTipText(tooltip);
+       }
+
+       /**
+        * 
+        */
+       private void createUICompositeIconPanel()
+       {
+               Shell splash = getSplash();
+               // Create the composite
+               fIconPanel = new Composite(splash, SWT.NONE);
+               // Determine the maximum number of columns that can fit on the splash
+               // screen. One 50x50 image per column.
+               int maxColumnCount = getUsableSplashScreenWidth() / F_IMAGE_WIDTH;
+               // Limit size to the maximum number of columns if the number of images
+               // exceed this amount; otherwise, use the exact number of columns
+               // required.
+               int actualColumnCount = Math.min(fImageList.size(), maxColumnCount);
+               // Configure the layout
+               GridLayout layout = new GridLayout(actualColumnCount, true);
+               layout.horizontalSpacing = 0;
+               layout.verticalSpacing = 0;
+               layout.marginHeight = 0;
+               layout.marginWidth = 0;
+               fIconPanel.setLayout(layout);
+       }
+
+       /**
+        * 
+        */
+       private void configureUICompositeIconPanelBounds()
+       {
+               // Determine the size of the panel and position it at the bottom-right
+               // of the splash screen.
+               Point panelSize = fIconPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+
+               int xCoord = getSplash().getSize().x - F_SPLASH_SCREEN_BEVEL - panelSize.x;
+               int yCoord = getSplash().getSize().y - F_SPLASH_SCREEN_BEVEL - panelSize.y;
+               int xWidth = panelSize.x;
+               int yWidth = panelSize.y;
+
+               fIconPanel.setBounds(xCoord, yCoord, xWidth, yWidth);
+       }
+
+       /**
+        * @return
+        */
+       private int getUsableSplashScreenWidth()
+       {
+               // Splash screen width minus two graphic border bevel widths
+               return getSplash().getSize().x - (F_SPLASH_SCREEN_BEVEL * 2);
+       }
+
+       /**
+        * 
+        */
+       private void loadSplashExtensions()
+       {
+               // Get all splash handler extensions
+               IExtension[] extensions = Platform.getExtensionRegistry().getExtensionPoint(F_SPLASH_EXTENSION_ID).getExtensions();
+               // Process all splash handler extensions
+               for (int i = 0; i < extensions.length; i++)
+               {
+                       processSplashExtension(extensions[i]);
+               }
+       }
+
+       /**
+        * @param extension
+        */
+       private void processSplashExtension(IExtension extension)
+       {
+               // Get all splash handler configuration elements
+               IConfigurationElement[] elements = extension.getConfigurationElements();
+               // Process all splash handler configuration elements
+               for (int j = 0; j < elements.length; j++)
+               {
+                       processSplashElements(elements[j]);
+               }
+       }
+
+       /**
+        * @param configurationElement
+        */
+       private void processSplashElements(IConfigurationElement configurationElement)
+       {
+               // Attribute: icon
+               processSplashElementIcon(configurationElement);
+               // Attribute: tooltip
+               processSplashElementTooltip(configurationElement);
+       }
+
+       /**
+        * @param configurationElement
+        */
+       private void processSplashElementTooltip(IConfigurationElement configurationElement)
+       {
+               // Get attribute tooltip
+               String tooltip = configurationElement.getAttribute(F_ELEMENT_TOOLTIP);
+               // If a tooltip is not defined, give it a default
+               if ((tooltip == null) || (tooltip.length() == 0))
+               {
+                       fTooltipList.add(F_DEFAULT_TOOLTIP);
+               } else
+               {
+                       fTooltipList.add(tooltip);
+               }
+       }
+
+       /**
+        * @param configurationElement
+        */
+       private void processSplashElementIcon(IConfigurationElement configurationElement)
+       {
+               // Get attribute icon
+               String iconImageFilePath = configurationElement.getAttribute(F_ELEMENT_ICON);
+               // Abort if an icon attribute was not specified
+               if ((iconImageFilePath == null) || (iconImageFilePath.length() == 0))
+               {
+                       return;
+               }
+               // Create a corresponding image descriptor
+               ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(configurationElement.getNamespaceIdentifier(),
+                               iconImageFilePath);
+               // Abort if no corresponding image was found
+               if (descriptor == null)
+               {
+                       return;
+               }
+               // Create the image
+               Image image = descriptor.createImage();
+               // Abort if image creation failed
+               if (image == null)
+               {
+                       return;
+               }
+               // Abort if the image does not have dimensions of 50x50
+               if ((image.getBounds().width != F_IMAGE_WIDTH) || (image.getBounds().height != F_IMAGE_HEIGHT))
+               {
+                       // Dipose of the image
+                       image.dispose();
+                       return;
+               }
+               // Store the image and tooltip
+               fImageList.add(image);
+       }
+
+       /**
+        * 
+        */
+       private void configureUISplash()
+       {
+               // Configure layout
+               GridLayout layout = new GridLayout(1, true);
+               getSplash().setLayout(layout);
+               // Force shell to inherit the splash background
+               getSplash().setBackgroundMode(SWT.INHERIT_DEFAULT);
+       }
+
+       /**
+        * 
+        */
+       private void doEventLoop()
+       {
+               Shell splash = getSplash();
+               if (!splash.getDisplay().readAndDispatch())
+               {
+                       splash.getDisplay().sleep();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.splash.AbstractSplashHandler#dispose()
+        */
+       @Override
+       public void dispose()
+       {
+               super.dispose();
+               // Check to see if any images were defined
+               if ((fImageList == null) || fImageList.isEmpty())
+               {
+                       return;
+               }
+               // Dispose of all the images
+               Iterator<Image> iterator = fImageList.iterator();
+               while (iterator.hasNext())
+               {
+                       Image image = iterator.next();
+                       image.dispose();
+               }
+       }
+}
diff --git a/SampleERCP/src/sampleercp/handlers/AboutHandler.java b/SampleERCP/src/sampleercp/handlers/AboutHandler.java
deleted file mode 100644 (file)
index f052b90..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package sampleercp.handlers;
-
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.widgets.Shell;
-
-public class AboutHandler
-{
-       @Execute
-       public void execute(Shell shell)
-       {
-               MessageDialog.openInformation(shell, "About", "Sample RCP4");
-       }
-}
diff --git a/SampleERCP/src/sampleercp/handlers/OpenHandler.java b/SampleERCP/src/sampleercp/handlers/OpenHandler.java
deleted file mode 100644 (file)
index 1581855..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-package sampleercp.handlers;
-
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Shell;
-
-public class OpenHandler
-{
-
-       @Execute
-       public void execute(Shell shell)
-       {
-               FileDialog dialog = new FileDialog(shell);
-               dialog.open();
-       }
-}
diff --git a/SampleERCP/src/sampleercp/handlers/QuitHandler.java b/SampleERCP/src/sampleercp/handlers/QuitHandler.java
deleted file mode 100644 (file)
index 7f40f8c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-package sampleercp.handlers;
-
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.workbench.IWorkbench;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.widgets.Shell;
-
-public class QuitHandler
-{
-       @Execute
-       public void execute(IWorkbench workbench, Shell shell)
-       {
-               if (MessageDialog.openConfirm(shell, "Confirmation", "Do you want to exit?"))
-               {
-                       workbench.close();
-               }
-       }
-}
diff --git a/SampleERCP/src/sampleercp/handlers/SaveHandler.java b/SampleERCP/src/sampleercp/handlers/SaveHandler.java
deleted file mode 100644 (file)
index c38f133..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-package sampleercp.handlers;
-
-import org.eclipse.e4.core.di.annotations.CanExecute;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.workbench.modeling.EPartService;
-
-public class SaveHandler
-{
-
-       @CanExecute
-       public boolean canExecute(EPartService partService)
-       {
-               if (partService != null)
-               {
-                       return !partService.getDirtyParts().isEmpty();
-               }
-               return false;
-       }
-
-       @Execute
-       public void execute(EPartService partService)
-       {
-               partService.saveAll(false);
-       }
-}
\ No newline at end of file
diff --git a/SampleERCP/src/sampleercp/parts/LogicUIPart.java b/SampleERCP/src/sampleercp/parts/LogicUIPart.java
deleted file mode 100644 (file)
index 98fb64c..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-package sampleercp.parts;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-
-import era.mi.gui.LogicExecuter;
-import era.mi.gui.LogicUICanvas;
-import era.mi.gui.examples.RSLatchExample;
-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.ZoomableCanvasUserInput;
-
-public class LogicUIPart
-{
-       @Inject
-       private MPart part;
-
-       @PostConstruct
-       public void create(Composite parent)
-       {
-               // setup view model
-               ViewModel viewModel = new ViewModel();
-               RSLatchExample.createRSLatchExample(viewModel);
-
-               // convert to logic model
-               LogicModelParameters params = new LogicModelParameters();
-               params.gateProcessTime = 50;
-               params.wireTravelTime = 10;
-               Timeline timeline = ViewLogicModelAdapter.convert(viewModel, params);
-
-               // initialize UI
-               LogicUICanvas ui = new LogicUICanvas(parent, SWT.NONE, viewModel);
-               ui.addTransformListener((x, y, z) -> part.setDirty(z < 1));
-               ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
-               userInput.buttonDrag = 3;
-               userInput.buttonZoom = 2;
-               userInput.enableUserInput();
-
-               // initialize executer
-               LogicExecuter exec = new LogicExecuter(timeline);
-
-               // run it
-               exec.startLiveExecution();
-
-               // TODO find a better condition when to stop
-               ui.addDisposeListener(e -> exec.stopLiveExecution());
-       }
-}
\ No newline at end of file
diff --git a/SampleERCP/src/sampleercp/parts/SamplePart.java b/SampleERCP/src/sampleercp/parts/SamplePart.java
deleted file mode 100644 (file)
index 93f3502..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package sampleercp.parts;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-
-import org.eclipse.e4.ui.di.Focus;
-import org.eclipse.e4.ui.di.Persist;
-import org.eclipse.e4.ui.model.application.ui.basic.MPart;
-import org.eclipse.jface.viewers.ArrayContentProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-public class SamplePart
-{
-
-       private TableViewer tableViewer;
-
-       @Inject
-       private MPart part;
-
-       @PostConstruct
-       public void createComposite(Composite parent)
-       {
-               parent.setLayout(new GridLayout(1, false));
-
-               Text txtInput = new Text(parent, SWT.BORDER);
-               txtInput.setMessage("Enter text to mark part as dirty");
-               txtInput.addModifyListener(e -> part.setDirty(true));
-               txtInput.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-
-               tableViewer = new TableViewer(parent);
-
-               tableViewer.setContentProvider(ArrayContentProvider.getInstance());
-               tableViewer.setInput(createInitialDataModel());
-               tableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
-       }
-
-       @Focus
-       public void setFocus()
-       {
-               tableViewer.getTable().setFocus();
-       }
-
-       @Persist
-       public void save()
-       {
-               part.setDirty(false);
-       }
-
-       private static List<String> createInitialDataModel()
-       {
-               return Arrays.asList("Sample item 1", "Sample item 2", "Sample item 3", "Sample item 4", "Sample item 5");
-       }
-}
\ No newline at end of file
diff --git a/SampleERCP/src/sampleercp/splashhandlers/ExtensibleSplashHandler.java b/SampleERCP/src/sampleercp/splashhandlers/ExtensibleSplashHandler.java
deleted file mode 100644 (file)
index 6581eb1..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-package sampleercp.splashhandlers;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.IExtension;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.eclipse.ui.splash.AbstractSplashHandler;
-
-/**
- * @since 3.3
- *
- */
-public class ExtensibleSplashHandler extends AbstractSplashHandler
-{
-
-       private ArrayList<Image> fImageList;
-
-       private ArrayList<String> fTooltipList;
-
-       private static final String F_SPLASH_EXTENSION_ID = "Sample.splashExtension"; // NON-NLS-1
-
-       private static final String F_ELEMENT_ICON = "icon"; // NON-NLS-1
-
-       private static final String F_ELEMENT_TOOLTIP = "tooltip"; // NON-NLS-1
-
-       private static final String F_DEFAULT_TOOLTIP = "Image"; // NON-NLS-1
-
-       private static final int F_IMAGE_WIDTH = 50;
-
-       private static final int F_IMAGE_HEIGHT = 50;
-
-       private static final int F_SPLASH_SCREEN_BEVEL = 5;
-
-       private Composite fIconPanel;
-
-       /**
-        * 
-        */
-       public ExtensibleSplashHandler()
-       {
-               fImageList = new ArrayList<>();
-               fTooltipList = new ArrayList<>();
-               fIconPanel = null;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.splash.AbstractSplashHandler#init(org.eclipse.swt.widgets. Shell)
-        */
-       @Override
-       public void init(Shell splash)
-       {
-               // Store the shell
-               super.init(splash);
-               // Configure the shell layout
-               configureUISplash();
-               // Load all splash extensions
-               loadSplashExtensions();
-               // If no splash extensions were loaded abort the splash handler
-               if (!hasSplashExtensions())
-               {
-                       return;
-               }
-               // Create UI
-               createUI();
-               // Configure the image panel bounds
-               configureUICompositeIconPanelBounds();
-               // Enter event loop and prevent the RCP application from
-               // loading until all work is done
-               doEventLoop();
-       }
-
-       /**
-        * @return
-        */
-       private boolean hasSplashExtensions()
-       {
-               return !fImageList.isEmpty();
-       }
-
-       /**
-        * 
-        */
-       private void createUI()
-       {
-               // Create the icon panel
-               createUICompositeIconPanel();
-               // Create the images
-               createUIImages();
-       }
-
-       /**
-        * 
-        */
-       private void createUIImages()
-       {
-               Iterator<Image> imageIterator = fImageList.iterator();
-               Iterator<String> tooltipIterator = fTooltipList.iterator();
-               int i = 1;
-               int columnCount = ((GridLayout) fIconPanel.getLayout()).numColumns;
-               // Create all the images
-               // Abort if we run out of columns (left-over images will not fit within
-               // the usable splash screen width)
-               while (imageIterator.hasNext() && (i <= columnCount))
-               {
-                       Image image = imageIterator.next();
-                       String tooltip = tooltipIterator.next();
-                       // Create the image using a label widget
-                       createUILabel(image, tooltip);
-                       i++;
-               }
-       }
-
-       /**
-        * @param image
-        * @param tooltip
-        */
-       private void createUILabel(Image image, String tooltip)
-       {
-               // Create the label (no text)
-               Label label = new Label(fIconPanel, SWT.NONE);
-               label.setImage(image);
-               label.setToolTipText(tooltip);
-       }
-
-       /**
-        * 
-        */
-       private void createUICompositeIconPanel()
-       {
-               Shell splash = getSplash();
-               // Create the composite
-               fIconPanel = new Composite(splash, SWT.NONE);
-               // Determine the maximum number of columns that can fit on the splash
-               // screen. One 50x50 image per column.
-               int maxColumnCount = getUsableSplashScreenWidth() / F_IMAGE_WIDTH;
-               // Limit size to the maximum number of columns if the number of images
-               // exceed this amount; otherwise, use the exact number of columns
-               // required.
-               int actualColumnCount = Math.min(fImageList.size(), maxColumnCount);
-               // Configure the layout
-               GridLayout layout = new GridLayout(actualColumnCount, true);
-               layout.horizontalSpacing = 0;
-               layout.verticalSpacing = 0;
-               layout.marginHeight = 0;
-               layout.marginWidth = 0;
-               fIconPanel.setLayout(layout);
-       }
-
-       /**
-        * 
-        */
-       private void configureUICompositeIconPanelBounds()
-       {
-               // Determine the size of the panel and position it at the bottom-right
-               // of the splash screen.
-               Point panelSize = fIconPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
-
-               int xCoord = getSplash().getSize().x - F_SPLASH_SCREEN_BEVEL - panelSize.x;
-               int yCoord = getSplash().getSize().y - F_SPLASH_SCREEN_BEVEL - panelSize.y;
-               int xWidth = panelSize.x;
-               int yWidth = panelSize.y;
-
-               fIconPanel.setBounds(xCoord, yCoord, xWidth, yWidth);
-       }
-
-       /**
-        * @return
-        */
-       private int getUsableSplashScreenWidth()
-       {
-               // Splash screen width minus two graphic border bevel widths
-               return getSplash().getSize().x - (F_SPLASH_SCREEN_BEVEL * 2);
-       }
-
-       /**
-        * 
-        */
-       private void loadSplashExtensions()
-       {
-               // Get all splash handler extensions
-               IExtension[] extensions = Platform.getExtensionRegistry().getExtensionPoint(F_SPLASH_EXTENSION_ID).getExtensions();
-               // Process all splash handler extensions
-               for (int i = 0; i < extensions.length; i++)
-               {
-                       processSplashExtension(extensions[i]);
-               }
-       }
-
-       /**
-        * @param extension
-        */
-       private void processSplashExtension(IExtension extension)
-       {
-               // Get all splash handler configuration elements
-               IConfigurationElement[] elements = extension.getConfigurationElements();
-               // Process all splash handler configuration elements
-               for (int j = 0; j < elements.length; j++)
-               {
-                       processSplashElements(elements[j]);
-               }
-       }
-
-       /**
-        * @param configurationElement
-        */
-       private void processSplashElements(IConfigurationElement configurationElement)
-       {
-               // Attribute: icon
-               processSplashElementIcon(configurationElement);
-               // Attribute: tooltip
-               processSplashElementTooltip(configurationElement);
-       }
-
-       /**
-        * @param configurationElement
-        */
-       private void processSplashElementTooltip(IConfigurationElement configurationElement)
-       {
-               // Get attribute tooltip
-               String tooltip = configurationElement.getAttribute(F_ELEMENT_TOOLTIP);
-               // If a tooltip is not defined, give it a default
-               if ((tooltip == null) || (tooltip.length() == 0))
-               {
-                       fTooltipList.add(F_DEFAULT_TOOLTIP);
-               } else
-               {
-                       fTooltipList.add(tooltip);
-               }
-       }
-
-       /**
-        * @param configurationElement
-        */
-       private void processSplashElementIcon(IConfigurationElement configurationElement)
-       {
-               // Get attribute icon
-               String iconImageFilePath = configurationElement.getAttribute(F_ELEMENT_ICON);
-               // Abort if an icon attribute was not specified
-               if ((iconImageFilePath == null) || (iconImageFilePath.length() == 0))
-               {
-                       return;
-               }
-               // Create a corresponding image descriptor
-               ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(configurationElement.getNamespaceIdentifier(),
-                               iconImageFilePath);
-               // Abort if no corresponding image was found
-               if (descriptor == null)
-               {
-                       return;
-               }
-               // Create the image
-               Image image = descriptor.createImage();
-               // Abort if image creation failed
-               if (image == null)
-               {
-                       return;
-               }
-               // Abort if the image does not have dimensions of 50x50
-               if ((image.getBounds().width != F_IMAGE_WIDTH) || (image.getBounds().height != F_IMAGE_HEIGHT))
-               {
-                       // Dipose of the image
-                       image.dispose();
-                       return;
-               }
-               // Store the image and tooltip
-               fImageList.add(image);
-       }
-
-       /**
-        * 
-        */
-       private void configureUISplash()
-       {
-               // Configure layout
-               GridLayout layout = new GridLayout(1, true);
-               getSplash().setLayout(layout);
-               // Force shell to inherit the splash background
-               getSplash().setBackgroundMode(SWT.INHERIT_DEFAULT);
-       }
-
-       /**
-        * 
-        */
-       private void doEventLoop()
-       {
-               Shell splash = getSplash();
-               if (!splash.getDisplay().readAndDispatch())
-               {
-                       splash.getDisplay().sleep();
-               }
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.splash.AbstractSplashHandler#dispose()
-        */
-       @Override
-       public void dispose()
-       {
-               super.dispose();
-               // Check to see if any images were defined
-               if ((fImageList == null) || fImageList.isEmpty())
-               {
-                       return;
-               }
-               // Dispose of all the images
-               Iterator<Image> iterator = fImageList.iterator();
-               while (iterator.hasNext())
-               {
-                       Image image = iterator.next();
-                       image.dispose();
-               }
-       }
-}
index 3b59be0..39cad77 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-       <name>era.mi</name>
+       <name>mograsim.logic.core</name>
        <comment></comment>
        <projects>
        </projects>
index 7ac9c4c..020d558 100644 (file)
@@ -9,6 +9,7 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul
 org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
 org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=10
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
 org.eclipse.jdt.core.compiler.compliance=10
index e383c7e..9465882 100644 (file)
@@ -1,6 +1,6 @@
 eclipse.preferences.version=1
 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
-formatter_profile=_ERA-MI
+formatter_profile=_MoGraSim
 formatter_settings_version=16
 sp_cleanup.add_default_serial_version_id=true
 sp_cleanup.add_generated_serial_version_id=false
index 47ff164..fad3aa8 100644 (file)
@@ -1,14 +1,14 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
-Bundle-Name: MI
-Bundle-SymbolicName: era.mi
+Bundle-Name: mograsim.logic.core
+Bundle-SymbolicName: mograsim.logic.core
 Bundle-Version: 1.0.0.qualifier
-Export-Package: era.mi.logic,
era.mi.logic.components,
era.mi.logic.components.gates,
era.mi.logic.tests,
era.mi.logic.timeline,
era.mi.logic.types,
era.mi.logic.wires
+Export-Package: mograsim.logic.core,
mograsim.logic.core.components,
mograsim.logic.core.components.gates,
mograsim.logic.core.tests,
mograsim.logic.core.timeline,
mograsim.logic.core.types,
mograsim.logic.core.wires
 Bundle-RequiredExecutionEnvironment: JavaSE-10
-Automatic-Module-Name: era.mi
+Automatic-Module-Name: mograsim.logic.core
diff --git a/era.mi/src/era/mi/logic/Util.java b/era.mi/src/era/mi/logic/Util.java
deleted file mode 100644 (file)
index d621a44..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-package era.mi.logic;
-
-import java.util.Arrays;
-
-import era.mi.logic.types.Bit;
-
-public final class Util
-{
-
-       @SuppressWarnings("unchecked")
-       public static <T> T[] concat(T[]... arrays)
-       {
-               if (arrays.length == 0)
-                       throw new IllegalArgumentException("Cannot concatenate 0 arrays.");
-
-               int length = 0;
-               for (T[] array : arrays)
-                       length += array.length;
-
-               T[] newArray = Arrays.copyOf(arrays[0], length);
-               int appendIndex = arrays[0].length;
-               for (int i = 1; i < arrays.length; i++)
-               {
-                       System.arraycopy(arrays[i], 0, newArray, appendIndex, arrays[i].length);
-                       appendIndex += arrays[i].length;
-               }
-
-               return newArray;
-       }
-
-//     @SuppressWarnings("unchecked")
-//     public static <T> T[][] split(T[] array, int... lengths)
-//     {
-//             //TODO: implement array split again; This version contains an illegal cast
-//             int totalLength = 0;
-//             for(int length : lengths)
-//                     totalLength += length;
-//             
-//             if(totalLength != array.length)
-//                     throw new IllegalArgumentException(); //TODO: add proper error message
-//             
-//             Object[][] newArray = new Object[lengths.length][];
-//             int splitIndex = 0;
-//             for(int i = 0; i < lengths.length; i++)
-//             {
-//                     System.arraycopy(array, splitIndex, newArray, 0, lengths[i]);
-//                     splitIndex += lengths[i];
-//             }
-//             
-//             return (T[][]) newArray;
-//     }
-
-       public static Bit[] and(Bit[] a, Bit[] b)
-       {
-               return binBitOp(a, b, Bit::and);
-       }
-
-       public static Bit[] or(Bit[] a, Bit[] b)
-       {
-               return binBitOp(a, b, Bit::or);
-       }
-
-       public static Bit[] xor(Bit[] a, Bit[] b)
-       {
-               return binBitOp(a, b, Bit::xor);
-       }
-
-       private static Bit[] binBitOp(Bit[] a, Bit[] b, BitOp op)
-       {
-               if (a.length != b.length)
-                       throw new IllegalArgumentException("Bit Arrays were not of equal length.");
-               Bit[] out = new Bit[a.length];
-               for (int i = 0; i < a.length; i++)
-               {
-                       out[i] = op.execute(a[i], b[i]);
-               }
-               return out;
-       }
-
-       public static Bit[] not(Bit[] a)
-       {
-               Bit[] out = new Bit[a.length];
-               for (int i = 0; i < a.length; i++)
-               {
-                       out[i] = a[i].not();
-               }
-               return out;
-       }
-
-       /**
-        * uses the {@link Bit#combineWith(Bit)} method, does not create a new array, the result is stored in the first array.
-        * 
-        * @author Christian Femers
-        */
-       public static Bit[] combineInto(Bit[] dest, Bit[] addition)
-       {
-               if (dest.length != addition.length)
-                       throw new IllegalArgumentException("Bit Arrays were not of equal length.");
-               for (int i = 0; i < addition.length; i++)
-               {
-                       dest[i] = dest[i].join(addition[i]);
-               }
-               return dest;
-       }
-
-       interface BitOp
-       {
-               Bit execute(Bit a, Bit b);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/BasicComponent.java b/era.mi/src/era/mi/logic/components/BasicComponent.java
deleted file mode 100644 (file)
index 47a3057..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package era.mi.logic.components;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.BitVector;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.WireObserver;
-
-/**
- * A basic component that recomputes all outputs (with a delay), when it is updated.
- * 
- * @author Fabian Stemmler
- */
-public abstract class BasicComponent extends Component implements WireObserver
-{
-       private int processTime;
-
-       /**
-        * 
-        * @param processTime Amount of time this component takes to update its outputs. Must be more than 0, otherwise 1 is assumed.
-        * 
-        * @author Fabian Stemmler
-        */
-       public BasicComponent(Timeline timeline, int processTime)
-       {
-               super(timeline);
-               this.processTime = processTime > 0 ? processTime : 1;
-       }
-
-       @Override
-       public void update(ReadEnd initiator, BitVector oldValues)
-       {
-               timeline.addEvent(e -> compute(), processTime);
-       }
-
-       protected abstract void compute();
-}
diff --git a/era.mi/src/era/mi/logic/components/BitDisplay.java b/era.mi/src/era/mi/logic/components/BitDisplay.java
deleted file mode 100644 (file)
index d8691f3..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.Bit;
-import era.mi.logic.types.BitVector;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public class BitDisplay extends BasicComponent
-{
-       private final ReadEnd in;
-       private BitVector displayedValue;
-
-       public BitDisplay(Timeline timeline, ReadEnd in)
-       {
-               super(timeline, 1);
-               this.in = in;
-               in.addObserver(this);
-               compute();
-       }
-
-       @Override
-       protected void compute()
-       {
-               displayedValue = in.getValues();
-       }
-
-       public BitVector getDisplayedValue()
-       {
-               return displayedValue;
-       }
-
-       public boolean isDisplaying(Bit... values)
-       {
-               return displayedValue.equals(BitVector.of(values));
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of(in);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of();
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/Clock.java b/era.mi/src/era/mi/logic/components/Clock.java
deleted file mode 100644 (file)
index 01795e0..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.timeline.TimelineEvent;
-import era.mi.logic.timeline.TimelineEventHandler;
-import era.mi.logic.types.Bit;
-import era.mi.logic.wires.Wire;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public class Clock extends Component implements TimelineEventHandler
-{
-       private boolean toggle = false;
-       private ReadWriteEnd out;
-       private int delta;
-
-       /**
-        * 
-        * @param out   {@link Wire} the clock's impulses are fed into
-        * @param delta ticks between rising and falling edge
-        */
-       public Clock(Timeline timeline, ReadWriteEnd out, int delta)
-       {
-               super(timeline);
-               this.delta = delta;
-               this.out = out;
-               addToTimeline();
-       }
-
-       @Override
-       public void handle(TimelineEvent e)
-       {
-               addToTimeline();
-               out.feedSignals(toggle ? Bit.ONE : Bit.ZERO);
-               toggle = !toggle;
-       }
-
-       public ReadWriteEnd getOut()
-       {
-               return out;
-       }
-
-       private void addToTimeline()
-       {
-               timeline.addEvent(this, delta);
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of();
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(out);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/Component.java b/era.mi/src/era/mi/logic/components/Component.java
deleted file mode 100644 (file)
index e26b6cd..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public abstract class Component
-{
-       protected Timeline timeline;
-
-       public Component(Timeline timeline)
-       {
-               this.timeline = timeline;
-       }
-
-       /**
-        * Returns immutable list of all inputs to the {@link Component} (including e.g. the select bits to a MUX). Intended for visualization
-        * in the UI.
-        */
-       public abstract List<ReadEnd> getAllInputs();
-
-       /**
-        * Returns immutable list of all outputs to the {@link Component}. Intended for visualization in the UI.
-        */
-       public abstract List<ReadWriteEnd> getAllOutputs();
-}
diff --git a/era.mi/src/era/mi/logic/components/Connector.java b/era.mi/src/era/mi/logic/components/Connector.java
deleted file mode 100644 (file)
index 5fd7ee4..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.BitVector;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-import era.mi.logic.wires.WireObserver;
-
-public class Connector extends Component implements WireObserver
-{
-       private boolean connected;
-       private final ReadWriteEnd a;
-       private final ReadWriteEnd b;
-
-       public Connector(Timeline timeline, ReadWriteEnd a, ReadWriteEnd b)
-       {
-               super(timeline);
-               if (a.length() != b.length())
-                       throw new IllegalArgumentException(String.format("WireArray width does not match: %d, %d", a.length(), b.length()));
-               this.a = a;
-               this.b = b;
-               a.addObserver(this);
-               b.addObserver(this);
-       }
-
-       public void connect()
-       {
-               connected = true;
-               update(a);
-               update(b);
-       }
-
-       public void disconnect()
-       {
-               connected = false;
-               a.clearSignals();
-               b.clearSignals();
-       }
-
-       public void setConnection(boolean connected)
-       {
-               if (connected)
-                       connect();
-               else
-                       disconnect();
-       }
-
-       @Override
-       public void update(ReadEnd initiator, BitVector oldValues)
-       {
-               if (connected)
-                       timeline.addEvent(e -> update(initiator), 1);
-       }
-
-       private void update(ReadEnd initiator)
-       {
-               if (initiator == a)
-                       b.feedSignals(a.wireValuesExcludingMe());
-               else
-                       a.feedSignals(b.wireValuesExcludingMe());
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of(a, b);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(a, b);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/Demux.java b/era.mi/src/era/mi/logic/components/Demux.java
deleted file mode 100644 (file)
index 3b267df..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-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;
-
-/**
- * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the
- * output.
- * 
- * @author Fabian Stemmler
- *
- */
-public class Demux extends BasicComponent
-{
-       private final ReadEnd select, in;
-       private final ReadWriteEnd[] outputs;
-       private final int outputSize;
-       private int selected = -1;
-
-       /**
-        * Output {@link Wire}s and in must be of uniform length
-        * 
-        * @param in      Must be of uniform length with all outputs.
-        * @param select  Indexes the output array to which the input is mapped. Must have enough bits to index all outputs.
-        * @param outputs One of these outputs receives the input signal, depending on the select bits
-        */
-       public Demux(Timeline timeline, int processTime, ReadEnd in, ReadEnd select, ReadWriteEnd... outputs)
-       {
-               super(timeline, processTime);
-               outputSize = in.length();
-
-               this.in = in;
-               this.outputs = outputs;
-               for (int i = 0; i < this.outputs.length; i++)
-               {
-                       if (outputs[i].length() != outputSize)
-                               throw new IllegalArgumentException("All DEMUX wire arrays must be of uniform length!");
-                       this.outputs[i] = outputs[i];
-               }
-
-               this.select = select;
-               select.addObserver(this);
-
-               int maxInputs = 1 << select.length();
-               if (this.outputs.length > maxInputs)
-                       throw new IllegalArgumentException("There are more outputs (" + this.outputs.length + ") to the DEMUX than supported by "
-                                       + select.length() + " select bits (" + maxInputs + ").");
-               in.addObserver(this);
-       }
-
-       @Override
-       public void compute()
-       {
-               int selectValue = select.hasNumericValue() ? (int) select.getUnsignedValue() : -1;
-               if (selectValue >= outputs.length)
-                       selectValue = -1;
-
-               if (selected != selectValue && selected != -1)
-                       outputs[selected].clearSignals();
-
-               selected = selectValue;
-
-               if (selectValue != -1)
-                       outputs[selectValue].feedSignals(in.getValues());
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of(in, select);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(outputs);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/ManualSwitch.java b/era.mi/src/era/mi/logic/components/ManualSwitch.java
deleted file mode 100644 (file)
index 9ae08eb..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-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;
-
-/**
- * This class models a simple on/off (ONE/ZERO) switch for user interaction.
- *
- * @author Christian Femers
- *
- */
-public class ManualSwitch extends Component
-{
-       private ReadWriteEnd output;
-       private boolean isOn;
-
-       public ManualSwitch(Timeline timeline, ReadWriteEnd output)
-       {
-               super(timeline);
-               if (output.length() != 1)
-                       throw new IllegalArgumentException("Switch output can be only a single wire");
-               this.output = output;
-       }
-
-       public void switchOn()
-       {
-               setState(true);
-       }
-
-       public void switchOff()
-       {
-               setState(false);
-       }
-
-       public void toggle()
-       {
-               setState(!isOn);
-       }
-
-       public void setState(boolean isOn)
-       {
-               if (this.isOn == isOn)
-                       return;
-               this.isOn = isOn;
-               output.feedSignals(getValue());
-       }
-
-       public boolean isOn()
-       {
-               return isOn;
-       }
-
-       public Bit getValue()
-       {
-               return isOn ? Bit.ONE : Bit.ZERO;
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of();
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(output);
-       }
-
-}
diff --git a/era.mi/src/era/mi/logic/components/Merger.java b/era.mi/src/era/mi/logic/components/Merger.java
deleted file mode 100644 (file)
index ab38066..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.BitVector;
-import era.mi.logic.wires.Wire;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-import era.mi.logic.wires.WireObserver;
-
-public class Merger extends Component implements WireObserver
-{
-       private ReadWriteEnd out;
-       private ReadEnd[] inputs;
-       private int[] beginningIndex;
-
-       /**
-        * 
-        * @param union  The output of merging n {@link Wire}s into one. Must have length = a1.length() + a2.length() + ... + an.length().
-        * @param inputs The inputs to be merged into the union
-        */
-       public Merger(Timeline timeline, ReadWriteEnd union, ReadEnd... inputs)
-       {
-               super(timeline);
-               this.inputs = inputs;
-               this.out = union;
-               this.beginningIndex = new int[inputs.length];
-
-               int length = 0;
-               for (int i = 0; i < inputs.length; i++)
-               {
-                       beginningIndex[i] = length;
-                       length += inputs[i].length();
-                       inputs[i].addObserver(this);
-               }
-
-               if (length != union.length())
-                       throw new IllegalArgumentException(
-                                       "The output of merging n WireArrays into one must have length = a1.length() + a2.length() + ... + an.length().");
-       }
-
-       public ReadEnd getInput(int index)
-       {
-               return inputs[index];
-       }
-
-       public ReadEnd getUnion()
-       {
-               return out;
-       }
-
-       @Override
-       public void update(ReadEnd initiator, BitVector oldValues)
-       {
-               int index = find(initiator);
-               int beginning = beginningIndex[index];
-               out.feedSignals(beginning, inputs[index].getValues());
-       }
-
-       private int find(ReadEnd r)
-       {
-               for (int i = 0; i < inputs.length; i++)
-                       if (inputs[i] == r)
-                               return i;
-               return -1;
-       }
-
-       public ReadEnd[] getInputs()
-       {
-               return inputs.clone();
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of(inputs);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(out);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/Mux.java b/era.mi/src/era/mi/logic/components/Mux.java
deleted file mode 100644 (file)
index 5391e65..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-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;
-
-/**
- * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the
- * output.
- * 
- * @author Fabian Stemmler
- *
- */
-public class Mux extends BasicComponent
-{
-       private ReadEnd select;
-       private ReadWriteEnd out;
-       private ReadEnd[] inputs;
-       private final int outputSize;
-
-       /**
-        * Input {@link Wire}s and out must be of uniform length
-        * 
-        * @param out    Must be of uniform length with all inputs.
-        * @param select Indexes the input array which is to be mapped to the output. Must have enough bits to index all inputs.
-        * @param inputs One of these inputs is mapped to the output, depending on the select bits
-        */
-       public Mux(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd select, ReadEnd... inputs)
-       {
-               super(timeline, processTime);
-               outputSize = out.length();
-
-               this.inputs = inputs.clone();
-               for (int i = 0; i < this.inputs.length; i++)
-               {
-                       if (inputs[i].length() != outputSize)
-                               throw new IllegalArgumentException("All MUX wire arrays must be of uniform length!");
-                       inputs[i].addObserver(this);
-               }
-
-               this.select = select;
-               select.addObserver(this);
-
-               int maxInputs = 1 << select.length();
-               if (this.inputs.length > maxInputs)
-                       throw new IllegalArgumentException("There are more inputs (" + this.inputs.length + ") to the MUX than supported by "
-                                       + select.length() + " select bits (" + maxInputs + ").");
-
-               this.out = out;
-       }
-
-       public ReadEnd getOut()
-       {
-               return out;
-       }
-
-       public ReadEnd getSelect()
-       {
-               return select;
-       }
-
-       @Override
-       public void compute()
-       {
-               int selectValue;
-               if (!select.hasNumericValue() || (selectValue = (int) select.getUnsignedValue()) >= inputs.length)
-               {
-                       out.clearSignals();
-                       return;
-               }
-
-               ReadEnd active = inputs[selectValue];
-               out.feedSignals(active.getValues());
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               ArrayList<ReadEnd> wires = new ArrayList<ReadEnd>(Arrays.asList(inputs));
-               wires.add(select);
-               return Collections.unmodifiableList(wires);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(out);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/Splitter.java b/era.mi/src/era/mi/logic/components/Splitter.java
deleted file mode 100644 (file)
index 8c54d0f..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.BitVector;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-import era.mi.logic.wires.WireObserver;
-
-public class Splitter extends Component implements WireObserver
-{
-       private ReadEnd input;
-       private ReadWriteEnd[] outputs;
-
-       public Splitter(Timeline timeline, ReadEnd input, ReadWriteEnd... outputs)
-       {
-               super(timeline);
-               this.input = input;
-               this.outputs = outputs;
-               input.addObserver(this);
-               int length = 0;
-               for (ReadEnd out : outputs)
-                       length += out.length();
-
-               if (input.length() != length)
-                       throw new IllegalArgumentException(
-                                       "The input of splitting one into n WireArrays must have length = a1.length() + a2.length() + ... + an.length().");
-       }
-
-       protected void compute()
-       {
-               BitVector inputBits = input.getValues();
-               int startIndex = 0;
-               for (int i = 0; i < outputs.length; i++)
-               {
-                       outputs[i].feedSignals(inputBits.subVector(startIndex, startIndex + outputs[i].length()));
-                       startIndex += outputs[i].length();
-               }
-       }
-
-       @Override
-       public void update(ReadEnd initiator, BitVector oldValues)
-       {
-               compute();
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of(input);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(outputs);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/TriStateBuffer.java b/era.mi/src/era/mi/logic/components/TriStateBuffer.java
deleted file mode 100644 (file)
index 123e2c5..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-package era.mi.logic.components;
-
-import java.util.List;
-
-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;
-
-public class TriStateBuffer extends BasicComponent
-{
-       ReadEnd in, enable;
-       ReadWriteEnd out;
-
-       public TriStateBuffer(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out, ReadEnd enable)
-       {
-               super(timeline, processTime);
-               if (in.length() != out.length())
-                       throw new IllegalArgumentException(
-                                       "Tri-state output must have the same amount of bits as the input. Input: " + in.length() + " Output: " + out.length());
-               if (enable.length() != 1)
-                       throw new IllegalArgumentException("Tri-state enable must have exactly one bit, not " + enable.length() + ".");
-               this.in = in;
-               in.addObserver(this);
-               this.enable = enable;
-               enable.addObserver(this);
-               this.out = out;
-       }
-
-       @Override
-       protected void compute()
-       {
-               if (enable.getValue() == Bit.ONE)
-                       out.feedSignals(in.getValues());
-               else
-                       out.clearSignals();
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of(in, enable);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(out);
-       }
-
-}
diff --git a/era.mi/src/era/mi/logic/components/gates/AndGate.java b/era.mi/src/era/mi/logic/components/gates/AndGate.java
deleted file mode 100644 (file)
index edd34d7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package era.mi.logic.components.gates;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.BitVector.BitVectorMutator;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public class AndGate extends MultiInputGate
-{
-       public AndGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)
-       {
-               super(timeline, processTime, BitVectorMutator::and, out, in);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/gates/MultiInputGate.java b/era.mi/src/era/mi/logic/components/gates/MultiInputGate.java
deleted file mode 100644 (file)
index 038e227..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-package era.mi.logic.components.gates;
-
-import java.util.List;
-
-import era.mi.logic.components.BasicComponent;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.BitVector.BitVectorMutator;
-import era.mi.logic.types.MutationOperation;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public abstract class MultiInputGate extends BasicComponent
-{
-       protected ReadEnd[] in;
-       protected ReadWriteEnd out;
-       protected final int length;
-       protected MutationOperation op;
-
-       protected MultiInputGate(Timeline timeline, int processTime, MutationOperation op, ReadWriteEnd out, ReadEnd... in)
-       {
-               super(timeline, processTime);
-               this.op = op;
-               length = out.length();
-               this.in = in.clone();
-               if (in.length < 1)
-                       throw new IllegalArgumentException(String.format("Cannot create gate with %d wires.", in.length));
-               for (ReadEnd w : in)
-               {
-                       if (w.length() != length)
-                               throw new IllegalArgumentException("All wires connected to the gate must be of uniform length.");
-                       w.addObserver(this);
-               }
-               this.out = out;
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of(in);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(out);
-       }
-
-       @Override
-       protected void compute()
-       {
-               BitVectorMutator mutator = BitVectorMutator.empty();
-               for (ReadEnd w : in)
-                       op.apply(mutator, w.getValues());
-               out.feedSignals(mutator.get());
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/gates/NotGate.java b/era.mi/src/era/mi/logic/components/gates/NotGate.java
deleted file mode 100644 (file)
index 685bc22..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-package era.mi.logic.components.gates;
-
-import java.util.List;
-
-import era.mi.logic.components.BasicComponent;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public class NotGate extends BasicComponent
-{
-       private ReadEnd in;
-       private ReadWriteEnd out;
-
-       public NotGate(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out)
-       {
-               super(timeline, processTime);
-               this.in = in;
-               in.addObserver(this);
-               this.out = out;
-       }
-
-       @Override
-       protected void compute()
-       {
-               out.feedSignals(in.getValues().not());
-       }
-
-       public ReadEnd getIn()
-       {
-               return in;
-       }
-
-       public ReadEnd getOut()
-       {
-               return out;
-       }
-
-       @Override
-       public List<ReadEnd> getAllInputs()
-       {
-               return List.of(in);
-       }
-
-       @Override
-       public List<ReadWriteEnd> getAllOutputs()
-       {
-               return List.of(out);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/gates/OrGate.java b/era.mi/src/era/mi/logic/components/gates/OrGate.java
deleted file mode 100644 (file)
index f34206f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package era.mi.logic.components.gates;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.BitVector.BitVectorMutator;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-public class OrGate extends MultiInputGate
-{
-       public OrGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)
-       {
-               super(timeline, processTime, BitVectorMutator::or, out, in);
-       }
-}
diff --git a/era.mi/src/era/mi/logic/components/gates/XorGate.java b/era.mi/src/era/mi/logic/components/gates/XorGate.java
deleted file mode 100644 (file)
index a177695..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-package era.mi.logic.components.gates;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.BitVector.BitVectorMutator;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-/**
- * Outputs 1 when the number of 1 inputs is odd.
- * 
- * @author Fabian Stemmler
- */
-public class XorGate extends MultiInputGate
-{
-       public XorGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)
-       {
-               super(timeline, processTime, BitVectorMutator::xor, out, in);
-       }
-
-}
diff --git a/era.mi/src/era/mi/logic/tests/ComponentTest.java b/era.mi/src/era/mi/logic/tests/ComponentTest.java
deleted file mode 100644 (file)
index 0e2b346..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-package era.mi.logic.tests;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
-
-import java.util.function.LongConsumer;
-
-import org.junit.jupiter.api.Test;
-
-import era.mi.logic.components.Connector;
-import era.mi.logic.components.Demux;
-import era.mi.logic.components.Merger;
-import era.mi.logic.components.Mux;
-import era.mi.logic.components.Splitter;
-import era.mi.logic.components.TriStateBuffer;
-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.components.gates.XorGate;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.Bit;
-import era.mi.logic.types.BitVector;
-import era.mi.logic.wires.Wire;
-import era.mi.logic.wires.Wire.ReadEnd;
-import era.mi.logic.wires.Wire.ReadWriteEnd;
-
-class ComponentTest
-{
-       private Timeline t = new Timeline(11);
-
-       @Test
-       void circuitExampleTest()
-       {
-               Wire a = new Wire(t, 1, 1), b = new Wire(t, 1, 1), c = new Wire(t, 1, 10), d = new Wire(t, 2, 1), e = new Wire(t, 1, 1),
-                               f = new Wire(t, 1, 1), g = new Wire(t, 1, 1), h = new Wire(t, 2, 1), i = new Wire(t, 2, 1), j = new Wire(t, 1, 1),
-                               k = new Wire(t, 1, 1);
-               new AndGate(t, 1, f.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
-               new NotGate(t, 1, f.createReadOnlyEnd(), g.createReadWriteEnd());
-               new Merger(t, h.createReadWriteEnd(), c.createReadOnlyEnd(), g.createReadOnlyEnd());
-               new Mux(t, 1, i.createReadWriteEnd(), e.createReadOnlyEnd(), h.createReadOnlyEnd(), d.createReadOnlyEnd());
-               new Splitter(t, i.createReadOnlyEnd(), k.createReadWriteEnd(), j.createReadWriteEnd());
-
-               a.createReadWriteEnd().feedSignals(Bit.ZERO);
-               b.createReadWriteEnd().feedSignals(Bit.ONE);
-               c.createReadWriteEnd().feedSignals(Bit.ZERO);
-               d.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE);
-               e.createReadWriteEnd().feedSignals(Bit.ZERO);
-
-               t.executeAll();
-
-               assertEquals(Bit.ONE, j.getValue());
-               assertEquals(Bit.ZERO, k.getValue());
-       }
-
-       @Test
-       void splitterTest()
-       {
-               t.reset();
-               Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), in = new Wire(t, 8, 1);
-               in.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
-               new Splitter(t, in.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(), c.createReadWriteEnd());
-
-               t.executeAll();
-
-               assertBitArrayEquals(a.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO);
-               assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO);
-               assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE);
-       }
-
-       @Test
-       void mergerTest()
-       {
-               t.reset();
-               Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), out = new Wire(t, 8, 1);
-               a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO);
-               b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO);
-               c.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
-
-               new Merger(t, out.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
-
-               t.executeAll();
-
-               assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
-       }
-
-       @Test
-       void triStateBufferTest()
-       {
-               Wire a = new Wire(t, 1, 1), b = new Wire(t, 1, 1), en = new Wire(t, 1, 1), notEn = new Wire(t, 1, 1);
-               new NotGate(t, 1, en.createReadOnlyEnd(), notEn.createReadWriteEnd());
-               new TriStateBuffer(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd(), en.createReadOnlyEnd());
-               new TriStateBuffer(t, 1, b.createReadOnlyEnd(), a.createReadWriteEnd(), notEn.createReadOnlyEnd());
-
-               ReadWriteEnd enI = en.createReadWriteEnd(), aI = a.createReadWriteEnd(), bI = b.createReadWriteEnd();
-               enI.feedSignals(Bit.ONE);
-               aI.feedSignals(Bit.ONE);
-               bI.feedSignals(Bit.Z);
-
-               t.executeAll();
-
-               assertEquals(Bit.ONE, b.getValue());
-
-               bI.feedSignals(Bit.ZERO);
-
-               t.executeAll();
-
-               assertEquals(Bit.X, b.getValue());
-               assertEquals(Bit.ONE, a.getValue());
-
-               aI.clearSignals();
-               enI.feedSignals(Bit.ZERO);
-
-               t.executeAll();
-
-               assertEquals(Bit.ZERO, a.getValue());
-
-       }
-
-       @Test
-       void muxTest()
-       {
-               t.reset();
-               Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), out = new Wire(t, 4, 1);
-               ReadWriteEnd selectIn = select.createReadWriteEnd();
-
-               selectIn.feedSignals(Bit.ZERO, Bit.ZERO);
-               a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
-               c.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
-
-               new Mux(t, 1, out.createReadWriteEnd(), select.createReadOnlyEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(),
-                               c.createReadOnlyEnd());
-               t.executeAll();
-
-               assertBitArrayEquals(out.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
-               selectIn.feedSignals(Bit.ZERO, Bit.ONE);
-               t.executeAll();
-
-               assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
-
-               selectIn.feedSignals(Bit.ONE, Bit.ONE);
-               t.executeAll();
-
-               assertBitArrayEquals(out.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
-
-       }
-
-       @Test
-       void demuxTest()
-       {
-               t.reset();
-               Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), in = new Wire(t, 4, 1);
-               ReadWriteEnd selectIn = select.createReadWriteEnd();
-
-               selectIn.feedSignals(Bit.ZERO, Bit.ZERO);
-               in.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
-
-               new Demux(t, 1, in.createReadOnlyEnd(), select.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(),
-                               c.createReadWriteEnd());
-               t.executeAll();
-
-               assertBitArrayEquals(a.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
-               assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
-               assertBitArrayEquals(c.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
-               selectIn.feedSignals(Bit.ZERO, Bit.ONE);
-               t.executeAll();
-
-               assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
-               assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
-               assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
-
-               selectIn.feedSignals(Bit.ONE, Bit.ONE);
-               t.executeAll();
-
-               assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
-               assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
-               assertBitArrayEquals(c.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
-
-       }
-
-       @Test
-       void andTest()
-       {
-               t.reset();
-               Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);
-               new AndGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
-               a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
-               b.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
-
-               t.executeAll();
-
-               assertBitArrayEquals(c.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ZERO);
-       }
-
-       @Test
-       void orTest()
-       {
-               t.reset();
-               Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);
-               new OrGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
-               a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
-               b.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
-
-               t.executeAll();
-
-               assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ONE);
-       }
-
-       @Test
-       void xorTest()
-       {
-               t.reset();
-               Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2), c = new Wire(t, 3, 1), d = new Wire(t, 3, 1);
-               new XorGate(t, 1, d.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
-               a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);
-               b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
-               c.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
-
-               t.executeAll();
-
-               assertBitArrayEquals(d.getValues(), Bit.ZERO, Bit.ONE, Bit.ONE);
-       }
-
-       @Test
-       void notTest()
-       {
-               t.reset();
-               Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2);
-               new NotGate(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd());
-               a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);
-
-               t.executeAll();
-
-               assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO, Bit.ZERO);
-       }
-
-       @Test
-       void rsLatchCircuitTest()
-       {
-               t.reset();
-               Wire r = new Wire(t, 1, 1), s = new Wire(t, 1, 1), t1 = new Wire(t, 1, 15), t2 = new Wire(t, 1, 1), q = new Wire(t, 1, 1),
-                               nq = new Wire(t, 1, 1);
-
-               new OrGate(t, 1, t2.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());
-               new OrGate(t, 1, t1.createReadWriteEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());
-               new NotGate(t, 1, t2.createReadOnlyEnd(), q.createReadWriteEnd());
-               new NotGate(t, 1, t1.createReadOnlyEnd(), nq.createReadWriteEnd());
-
-               ReadWriteEnd sIn = s.createReadWriteEnd(), rIn = r.createReadWriteEnd();
-
-               sIn.feedSignals(Bit.ONE);
-               rIn.feedSignals(Bit.ZERO);
-
-               t.executeAll();
-
-               assertEquals(Bit.ONE, q.getValue());
-               assertEquals(Bit.ZERO, nq.getValue());
-
-               sIn.feedSignals(Bit.ZERO);
-
-               t.executeAll();
-               assertEquals(Bit.ONE, q.getValue());
-               assertEquals(Bit.ZERO, nq.getValue());
-
-               rIn.feedSignals(Bit.ONE);
-
-               t.executeAll();
-
-               assertEquals(Bit.ZERO, q.getValue());
-               assertEquals(Bit.ONE, nq.getValue());
-       }
-
-       @Test
-       void numericValueTest()
-       {
-               t.reset();
-
-               Wire a = new Wire(t, 4, 1);
-               a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE);
-
-               t.executeAll();
-
-               assertEquals(15, a.getUnsignedValue());
-               assertEquals(-1, a.getSignedValue());
-       }
-
-       boolean flag = false;
-
-       @Test
-       void simpleTimelineTest()
-       {
-               Timeline t = new Timeline(3);
-               flag = false;
-               t.addEvent((e) ->
-               {
-                       if (!flag)
-                               fail();
-                       flag = false;
-               }, 15);
-               t.addEvent((e) ->
-               {
-                       if (flag)
-                               fail();
-                       flag = true;
-               }, 10);
-               t.addEvent((e) ->
-               {
-                       if (flag)
-                               fail();
-                       flag = true;
-               }, 20);
-               t.addEvent((e) ->
-               {
-                       fail("Only supposed to execute until timestamp 20, not 25");
-               }, 25);
-
-               t.executeUntil(t.laterThan(20), 100);
-
-               if (!flag)
-                       fail();
-       }
-
-       @Test
-       void multipleInputs()
-       {
-               t.reset();
-               Wire w = new Wire(t, 2, 1);
-               ReadWriteEnd wI1 = w.createReadWriteEnd(), wI2 = w.createReadWriteEnd();
-               wI1.feedSignals(Bit.ONE, Bit.Z);
-               wI2.feedSignals(Bit.Z, Bit.X);
-               t.executeAll();
-               assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.X);
-
-               wI2.feedSignals(Bit.ZERO, Bit.Z);
-               t.executeAll();
-               assertBitArrayEquals(w.getValues(), Bit.X, Bit.Z);
-
-               wI2.feedSignals(Bit.Z, Bit.Z);
-               t.executeAll();
-               assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);
-
-               wI2.feedSignals(Bit.ONE, Bit.Z);
-               ReadEnd rE = w.createReadOnlyEnd();
-               rE.addObserver((i, oldValues) -> fail("WireEnd notified observer, although value did not change."));
-               t.executeAll();
-               rE.close();
-               wI1.feedSignals(Bit.X, Bit.X);
-               t.executeAll();
-               wI1.addObserver((i, oldValues) -> fail("WireEnd notified observer, although it was closed."));
-               wI1.close();
-               assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);
-       }
-
-       @Test
-       void wireConnections()
-       {
-               // Nur ein Experiment, was Ã¼ber mehrere 'passive' Bausteine hinweg passieren würde
-
-               t.reset();
-
-               Wire a = new Wire(t, 1, 2);
-               Wire b = new Wire(t, 1, 2);
-               Wire c = new Wire(t, 1, 2);
-               ReadWriteEnd aI = a.createReadWriteEnd();
-               ReadWriteEnd bI = b.createReadWriteEnd();
-               ReadWriteEnd cI = c.createReadWriteEnd();
-
-               TestBitDisplay test = new TestBitDisplay(t, c.createReadOnlyEnd());
-               TestBitDisplay test2 = new TestBitDisplay(t, a.createReadOnlyEnd());
-               LongConsumer print = time -> System.out.format("Time %2d\n   a: %s\n   b: %s\n   c: %s\n", time, a, b, c);
-
-               cI.feedSignals(Bit.ONE);
-               test.assertAfterSimulationIs(print, Bit.ONE);
-
-               cI.feedSignals(Bit.X);
-               test.assertAfterSimulationIs(print, Bit.X);
-
-               cI.feedSignals(Bit.X);
-               cI.feedSignals(Bit.Z);
-               test.assertAfterSimulationIs(print, Bit.Z);
-
-               new Connector(t, b.createReadWriteEnd(), c.createReadWriteEnd()).connect();
-               test.assertAfterSimulationIs(print, Bit.Z);
-               System.err.println("ONE");
-               bI.feedSignals(Bit.ONE);
-               test.assertAfterSimulationIs(print, Bit.ONE);
-               System.err.println("ZERO");
-               bI.feedSignals(Bit.ZERO);
-               test.assertAfterSimulationIs(print, Bit.ZERO);
-               System.err.println("Z");
-               bI.feedSignals(Bit.Z);
-               test.assertAfterSimulationIs(print, Bit.Z);
-
-               new Connector(t, a.createReadWriteEnd(), b.createReadWriteEnd()).connect();
-               System.err.println("Z 2");
-               aI.feedSignals(Bit.Z);
-               test.assertAfterSimulationIs(print, Bit.Z);
-               test2.assertAfterSimulationIs(Bit.Z);
-               System.err.println("ONE 2");
-               aI.feedSignals(Bit.ONE);
-               test.assertAfterSimulationIs(print, Bit.ONE);
-               test2.assertAfterSimulationIs(Bit.ONE);
-               System.err.println("ZERO 2");
-               aI.feedSignals(Bit.ZERO);
-               test.assertAfterSimulationIs(print, Bit.ZERO);
-               test2.assertAfterSimulationIs(Bit.ZERO);
-               System.err.println("Z 2 II");
-               aI.feedSignals(Bit.Z);
-               test.assertAfterSimulationIs(print, Bit.Z);
-               test2.assertAfterSimulationIs(Bit.Z);
-
-               System.err.println("No Conflict yet");
-               bI.feedSignals(Bit.ONE);
-               test.assertAfterSimulationIs(print, Bit.ONE);
-               test2.assertAfterSimulationIs(Bit.ONE);
-               aI.feedSignals(Bit.ONE);
-               test.assertAfterSimulationIs(print, Bit.ONE);
-               test2.assertAfterSimulationIs(Bit.ONE);
-               System.err.println("Conflict");
-               aI.feedSignals(Bit.ZERO);
-               test.assertAfterSimulationIs(print, Bit.X);
-               test2.assertAfterSimulationIs(Bit.X);
-               aI.feedSignals(Bit.ONE);
-               test.assertAfterSimulationIs(print, Bit.ONE);
-               test2.assertAfterSimulationIs(Bit.ONE);
-       }
-
-       private static void assertBitArrayEquals(BitVector actual, Bit... expected)
-       {
-               assertArrayEquals(expected, actual.getBits());
-       }
-}
diff --git a/era.mi/src/era/mi/logic/tests/GUITest.java b/era.mi/src/era/mi/logic/tests/GUITest.java
deleted file mode 100644 (file)
index 0581812..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-package era.mi.logic.tests;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-import javax.swing.WindowConstants;
-
-import era.mi.logic.components.ManualSwitch;
-import era.mi.logic.components.gates.NotGate;
-import era.mi.logic.components.gates.OrGate;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.timeline.Timeline.ExecutionResult;
-import era.mi.logic.wires.Wire;
-
-public class GUITest extends JPanel
-{
-
-       private static final long serialVersionUID = 1L;
-
-       private static final int WIRE_DELAY = 40;
-       private static final int OR_DELAY = 100;
-       private static final int NOT_DELAY = 100;
-
-       private Timeline t = new Timeline(11);
-
-       Wire r = new Wire(t, 1, WIRE_DELAY);
-       Wire s = new Wire(t, 1, WIRE_DELAY);
-       Wire t1 = new Wire(t, 1, WIRE_DELAY);
-       Wire t2 = new Wire(t, 1, WIRE_DELAY);
-       Wire q = new Wire(t, 1, WIRE_DELAY);
-       Wire nq = new Wire(t, 1, WIRE_DELAY);
-
-       ManualSwitch rIn = new ManualSwitch(t, r.createReadWriteEnd());
-       ManualSwitch sIn = new ManualSwitch(t, s.createReadWriteEnd());
-
-       OrGate or1 = new OrGate(t, OR_DELAY, t2.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());
-       OrGate or2 = new OrGate(t, OR_DELAY, t1.createReadWriteEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());
-       NotGate not1 = new NotGate(t, NOT_DELAY, t2.createReadOnlyEnd(), q.createReadWriteEnd());
-       NotGate not2 = new NotGate(t, NOT_DELAY, t1.createReadOnlyEnd(), nq.createReadWriteEnd());
-
-       Map<ManualSwitch, Rectangle> switchMap = new HashMap<>();
-
-       int height;
-       int width;
-       boolean sizeChanged;
-
-       public GUITest()
-       {
-               addMouseListener(new MouseListener()
-               {
-
-                       @Override
-                       public void mouseReleased(MouseEvent e)
-                       {
-                               for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())
-                               {
-                                       if (dim.getValue().contains(e.getPoint()))
-                                       {
-                                               dim.getKey().switchOff();
-                                               repaint();
-                                       }
-                               }
-                       }
-
-                       @Override
-                       public void mousePressed(MouseEvent e)
-                       {
-                               for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())
-                               {
-                                       if (dim.getValue().contains(e.getPoint()))
-                                       {
-                                               dim.getKey().switchOn();
-                                               repaint();
-                                       }
-                               }
-                       }
-
-                       @Override
-                       public void mouseExited(MouseEvent e)
-                       {
-                               // none
-                       }
-
-                       @Override
-                       public void mouseEntered(MouseEvent e)
-                       {
-                               // none
-                       }
-
-                       @Override
-                       public void mouseClicked(MouseEvent e)
-                       {
-                               // If you want toggle buttons, use this code instead
-//                             for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet()) {
-//                                     if (dim.getValue().contains(e.getPoint())) {
-//                                             dim.getKey().toggle();
-//                                             repaint();
-//                                     }
-//                             }
-                       }
-               });
-       }
-
-       public Timeline getTimeline()
-       {
-               return t;
-       };
-
-       @Override
-       public void paint(Graphics some_g)
-       {
-               super.paint(some_g);
-               Graphics2D g = ((Graphics2D) some_g);
-               g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
-               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-               g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
-
-               checkSizeChange();
-               adaptFont(g);
-
-               drawWire(g, r, "r", 2, 9, 4, 9);
-
-               drawWire(g, s, "s", 2, 3, 4, 3);
-
-               drawWire(g, t2, "t2", 5, 8.5, 6, 8.5);
-
-               drawWire(g, t1, "t1", 5, 3.5, 6, 3.5);
-
-               drawWire(g, q, "q", 7, 8.5, 9, 8.5);
-
-               drawWire(g, nq, "nq", 7, 3.5, 9, 3.5);
-
-               drawWire(g, q, "", 7.5, 8.5, 7.5, 7.5);
-               drawWire(g, q, "", 7.5, 7.5, 3, 4.5);
-               drawWire(g, q, "", 3, 4.5, 3, 4);
-               drawWire(g, q, "q", 3, 4, 4, 4);
-
-               drawWire(g, nq, "", 7.5, 3.5, 7.5, 4.5);
-               drawWire(g, nq, "", 7.5, 4.5, 3, 7.5);
-               drawWire(g, nq, "", 3, 7.5, 3, 8);
-               drawWire(g, nq, "nq", 3, 8, 4, 8);
-
-               drawSquare(g, 4, 8, "OR");
-               drawSquare(g, 4, 3, "OR");
-
-               drawSquare(g, 6, 8, "NOT");
-               drawSquare(g, 6, 3, "NOT");
-
-               drawSwitch(g, rIn, "Switch R", 0.5, 8.25, 2, 9.75);
-               drawSwitch(g, sIn, "Switch S", 0.5, 2.25, 2, 3.75);
-
-               drawString(g, "Hint: drag the cursor out of the pressed switch to keep it's state", 5, 0, 0.0, 1.0);
-       }
-
-       private void checkSizeChange()
-       {
-               sizeChanged = height != getHeight() || width != getWidth();
-               if (sizeChanged)
-               {
-                       height = getHeight();
-                       width = getWidth();
-               }
-       }
-
-       private void adaptFont(Graphics g)
-       {
-               g.setFont(g.getFont().deriveFont(Math.min(height, width) / 40f));
-       }
-
-       private void drawString(Graphics g, String s, int x, int y, double anchorX, double anchorY)
-       {
-               int h = g.getFontMetrics().getAscent();
-               int w = g.getFontMetrics().stringWidth(s);
-               g.drawString(s, x - (int) (w * anchorX), y + (int) (h * anchorY));
-       }
-
-       private void drawWire(Graphics g, Wire wa, String name, double x1, double y1, double x2, double y2)
-       {
-               setTo(g, wa);
-               g.drawLine(gX(x1), gY(y1), gX(x2), gY(y2));
-               drawString(g, name, (gX(x1) + gX(x2)) / 2, (gY(y1) + gY(y2)) / 2 - 5, 0, 0);
-       }
-
-       private void drawSquare(Graphics g, int posX, int posY, String text)
-       {
-               int x1 = gX(posX) - 5;
-               int x2 = gX(posX + 1) + 5;
-               int y1 = gY(posY) - 5;
-               int y2 = gY(posY + 1) + 5;
-
-               g.setColor(Color.WHITE);
-               g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
-               setBlack(g);
-               g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
-               drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);
-
-       }
-
-       private void drawSwitch(Graphics g, ManualSwitch ms, String text, double posX1, double posY1, double posX2, double posY2)
-       {
-               int x1 = gX(posX1) - 5;
-               int x2 = gX(posX2) + 5;
-               int y1 = gY(posY1) - 5;
-               int y2 = gY(posY2) + 5;
-
-               if (sizeChanged)
-               {
-                       Rectangle r = new Rectangle(x1, y1, x2 - x1, y2 - y1);
-                       switchMap.put(ms, r);
-               }
-
-               g.setColor(ms.isOn() ? Color.getHSBColor(.3f, .5f, 1f) : Color.WHITE);
-               g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
-               setBlack(g);
-               g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
-               drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);
-       }
-
-       private static void setBlack(Graphics g)
-       {
-               g.setColor(Color.BLACK);
-       }
-
-       private static void setTo(Graphics g, Wire wa)
-       {
-               switch (wa.getValue())
-               {
-               case ONE:
-                       g.setColor(Color.GREEN);
-                       break;
-               case X:
-                       g.setColor(Color.RED);
-                       break;
-               case Z:
-                       g.setColor(Color.DARK_GRAY);
-                       break;
-               case ZERO:
-                       g.setColor(Color.BLACK);
-                       break;
-               case U:
-                       g.setColor(Color.MAGENTA);
-                       break;
-               default:
-                       throw new IllegalArgumentException();
-               }
-       }
-
-       private int gY(double pos)
-       {
-               return (int) (pos * height / 11);
-       }
-
-       private int gX(double pos)
-       {
-               return (int) (pos * width / 11) + 50;
-       }
-
-       public static void main(String[] args)
-       {
-               JFrame f = new JFrame("Test circuit 1.0.0");
-               GUITest gt = new GUITest();
-               f.add(gt);
-               f.setSize(800, 600);
-               f.setLocation(500, 400);
-               f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
-               f.setVisible(true);
-
-               long begin = System.currentTimeMillis();
-
-               long lastFrame = begin;
-               long updateT = 16;
-
-               while (f.isVisible())
-               {
-                       ExecutionResult er = gt.getTimeline().executeUntil(gt.getTimeline().laterThan((lastFrame - begin) * 3), lastFrame + 14);
-//                             if (t.hasNext()) 
-//                             t.executeNext();
-                       if (er != ExecutionResult.NOTHING_DONE)
-                               gt.repaint(12);
-                       try
-                       {
-                               Thread.sleep(Math.max(updateT - System.currentTimeMillis() + lastFrame, 0));
-                       }
-                       catch (Exception e)
-                       {
-                               e.printStackTrace();
-                       }
-                       lastFrame = System.currentTimeMillis();
-               }
-       }
-}
diff --git a/era.mi/src/era/mi/logic/tests/TestBitDisplay.java b/era.mi/src/era/mi/logic/tests/TestBitDisplay.java
deleted file mode 100644 (file)
index 28dc1cc..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-package era.mi.logic.tests;
-
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-
-import java.util.function.LongConsumer;
-
-import era.mi.logic.components.BitDisplay;
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.Bit;
-import era.mi.logic.wires.Wire.ReadEnd;
-
-public final class TestBitDisplay extends BitDisplay
-{
-
-       public TestBitDisplay(Timeline timeline, ReadEnd in)
-       {
-               super(timeline, in);
-       }
-
-       public void assertDisplays(Bit... expected)
-       {
-               assertArrayEquals(expected, getDisplayedValue().getBits());
-       }
-
-       public void assertAfterSimulationIs(Bit... expected)
-       {
-               timeline.executeAll();
-               assertDisplays(expected);
-       }
-
-       public void assertAfterSimulationIs(LongConsumer r, Bit... expected)
-       {
-               while (timeline.hasNext())
-               {
-                       timeline.executeNext();
-                       r.accept(timeline.getSimulationTime());
-               }
-               assertDisplays(expected);
-       }
-
-       @Override
-       protected void compute()
-       {
-               super.compute();
-               System.out.println("update: value is " + getDisplayedValue());
-       }
-}
diff --git a/era.mi/src/era/mi/logic/timeline/Timeline.java b/era.mi/src/era/mi/logic/timeline/Timeline.java
deleted file mode 100644 (file)
index c010063..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-package era.mi.logic.timeline;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.PriorityQueue;
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-import java.util.function.LongSupplier;
-
-/**
- * Orders Events by the time they are due to be executed. Can execute Events individually.
- * 
- * @author Fabian Stemmler
- *
- */
-public class Timeline
-{
-       private PriorityQueue<InnerEvent> events;
-       private LongSupplier time;
-       private long lastTimeUpdated = 0;
-
-       private final List<Consumer<TimelineEvent>> eventAddedListener;
-
-       public Timeline(int initCapacity)
-       {
-               events = new PriorityQueue<InnerEvent>(initCapacity);
-
-               eventAddedListener = new ArrayList<>();
-               time = () -> lastTimeUpdated;
-       }
-
-       /**
-        * @param timestamp exclusive
-        * @return true if the first event is later than the timestamp
-        */
-       public BooleanSupplier laterThan(long timestamp)
-       {
-               return () -> timeCmp(events.peek().getTiming(), timestamp) > 0;
-       }
-
-       public boolean hasNext()
-       {
-               return !events.isEmpty();
-       }
-
-       /**
-        * Executes all events at the next timestamp, at which there are any
-        */
-       public void executeNext()
-       {
-               InnerEvent first = events.peek();
-               if (first != null)
-                       executeUntil(laterThan(first.getTiming()), -1);
-       }
-
-       public void executeAll()
-       {
-               while (hasNext())
-                       executeNext();
-       }
-
-       /**
-        * Executes all events until a given condition is met. The simulation process can be constrained by a real world timestamp.
-        * 
-        * @param condition  the condition until which the events are be processed
-        * @param stopMillis the System.currentTimeMillis() when simulation definitely needs to stop. A value of -1 means no timeout.
-        * @return State of the event execution
-        * @formatter:off
-        * <code>NOTHING_DONE</code> if the {@link Timeline} was already empty
-        * <code>EXEC_OUT_OF_TIME</code> if the given maximum time was reached
-        * <code>EXEC_UNTIL_CONDITION</code> if the condition was met
-        * <code>EXEC_UNTIL_EMPTY</code> if events were executed until the {@link Timeline} was empty
-        * @formatter:on
-        * @author Christian Femers, Fabian Stemmler
-        */
-       public ExecutionResult executeUntil(BooleanSupplier condition, long stopMillis)
-       {
-               if (events.isEmpty())
-               {
-                       lastTimeUpdated = getSimulationTime();
-                       return ExecutionResult.NOTHING_DONE;
-               }
-               int checkStop = 0;
-               InnerEvent first = events.peek();
-               while (hasNext() && !condition.getAsBoolean())
-               {
-                       events.remove();
-                       lastTimeUpdated = first.getTiming();
-                       first.run();
-                       // Don't check after every run
-                       checkStop = (checkStop + 1) % 10;
-                       if (checkStop == 0 && System.currentTimeMillis() >= stopMillis)
-                               return ExecutionResult.EXEC_OUT_OF_TIME;
-                       first = events.peek();
-               }
-               lastTimeUpdated = getSimulationTime();
-               return hasNext() ? ExecutionResult.EXEC_UNTIL_EMPTY : ExecutionResult.EXEC_UNTIL_CONDITION;
-       }
-
-       public void setTimeFunction(LongSupplier time)
-       {
-               this.time = time;
-       }
-
-       public long getSimulationTime()
-       {
-               return time.getAsLong();
-       }
-
-       public long nextEventTime()
-       {
-               if (!hasNext())
-                       return -1;
-               return events.peek().getTiming();
-       }
-
-       public void reset()
-       {
-               events.clear();
-               lastTimeUpdated = 0;
-       }
-
-       public void addEventAddedListener(Consumer<TimelineEvent> listener)
-       {
-               eventAddedListener.add(listener);
-       }
-
-       public void removeEventAddedListener(Consumer<TimelineEvent> listener)
-       {
-               eventAddedListener.remove(listener);
-       }
-
-       /**
-        * Adds an Event to the {@link Timeline}
-        * 
-        * @param function       The {@link TimelineEventHandler} that will be executed, when the {@link InnerEvent} occurs on the timeline.
-        * @param relativeTiming The amount of MI ticks in which the {@link InnerEvent} is called, starting from the current time.
-        */
-       public void addEvent(TimelineEventHandler function, int relativeTiming)
-       {
-               long timing = getSimulationTime() + relativeTiming;
-               TimelineEvent event = new TimelineEvent(timing);
-               events.add(new InnerEvent(function, event));
-               eventAddedListener.forEach(l -> l.accept(event));
-       }
-
-       private class InnerEvent implements Runnable, Comparable<InnerEvent>
-       {
-               private final TimelineEventHandler function;
-               private final TimelineEvent event;
-
-               /**
-                * Creates an {@link InnerEvent}
-                * 
-                * @param function {@link TimelineEventHandler} to be executed when the {@link InnerEvent} occurs
-                * @param timing   Point in the MI simulation {@link Timeline}, at which the {@link InnerEvent} is executed;
-                */
-               InnerEvent(TimelineEventHandler function, TimelineEvent event)
-               {
-                       this.function = function;
-                       this.event = event;
-               }
-
-               public long getTiming()
-               {
-                       return event.getTiming();
-               }
-
-               @Override
-               public void run()
-               {
-                       function.handle(event);
-               }
-
-               @Override
-               public String toString()
-               {
-                       return event.toString();
-               }
-
-               @Override
-               public int compareTo(InnerEvent o)
-               {
-                       return timeCmp(getTiming(), o.getTiming());
-               }
-       }
-
-       public static int timeCmp(long a, long b)
-       {
-               return Long.signum(a - b);
-       }
-
-       @Override
-       public String toString()
-       {
-               return String.format("Simulation time: %s, Last update: %d, Events: %s", getSimulationTime(), lastTimeUpdated, events.toString());
-       }
-
-       public enum ExecutionResult
-       {
-               NOTHING_DONE, EXEC_UNTIL_EMPTY, EXEC_UNTIL_CONDITION, EXEC_OUT_OF_TIME
-       }
-}
\ No newline at end of file
diff --git a/era.mi/src/era/mi/logic/timeline/TimelineEvent.java b/era.mi/src/era/mi/logic/timeline/TimelineEvent.java
deleted file mode 100644 (file)
index 46decf5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-package era.mi.logic.timeline;
-
-/**
- * A class that stores all relevant information about an event in the {@link Timeline}. Currently, there is not much relevant information to
- * store.
- * 
- * @author Fabian Stemmler
- *
- */
-public class TimelineEvent
-{
-       private final long timing;
-
-       TimelineEvent(long timing)
-       {
-               super();
-               this.timing = timing;
-       }
-
-       public long getTiming()
-       {
-               return timing;
-       }
-
-       @Override
-       public String toString()
-       {
-               return "timestamp: " + timing;
-       }
-}
\ No newline at end of file
diff --git a/era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java b/era.mi/src/era/mi/logic/timeline/TimelineEventHandler.java
deleted file mode 100644 (file)
index 921ad1b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package era.mi.logic.timeline;
-
-@FunctionalInterface
-public interface TimelineEventHandler
-{
-       public void handle(TimelineEvent e);
-}
\ No newline at end of file
diff --git a/era.mi/src/era/mi/logic/types/Bit.java b/era.mi/src/era/mi/logic/types/Bit.java
deleted file mode 100644 (file)
index 6674f9a..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-package era.mi.logic.types;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * stdlogic according to IEEE 1164
- */
-public enum Bit implements StrictLogicType<Bit>
-{
-       U("U"), X("X"), ZERO("0"), ONE("1"), Z("Z");
-
-       private final String symbol;
-
-       private Bit(String symbol)
-       {
-               this.symbol = symbol;
-       }
-
-       @Override
-       public Bit and(Bit other)
-       {
-               return fromTable(AND_TABLE, this, other);
-       }
-
-       @Override
-       public Bit or(Bit other)
-       {
-               return fromTable(OR_TABLE, this, other);
-       }
-
-       @Override
-       public Bit xor(Bit other)
-       {
-               return fromTable(XOR_TABLE, this, other);
-       }
-
-       @Override
-       public Bit not()
-       {
-               switch (this)
-               {
-               case U:
-                       return U;
-               case ONE:
-                       return ZERO;
-               case ZERO:
-                       return ONE;
-               default:
-                       return X;
-               }
-       }
-
-       public Bit[] makeArray(int length)
-       {
-               Bit[] bits = new Bit[length];
-               Arrays.fill(bits, this);
-               return bits;
-       }
-
-       public BitVector toVector(int length)
-       {
-               return BitVector.of(this, length);
-       }
-
-       @Override
-       public Bit join(Bit other)
-       {
-               return fromTable(JOIN_TABLE, this, other);
-       }
-
-       @Override
-       public String toString()
-       {
-               return getSymbol();
-       }
-
-       public String getSymbol()
-       {
-               return symbol;
-       }
-
-       public static Bit parse(String s)
-       {
-               Bit bit = SYMBOL_MAP.get(s);
-               Objects.requireNonNull(bit, "No Bit found for symbol " + s);
-               return bit;
-       }
-
-       public static Bit parse(String s, int symbolPosition)
-       {
-               return parse(s.substring(symbolPosition, symbolPosition + 1));
-       }
-
-       private static Bit fromTable(Bit[][] table, Bit a, Bit b)
-       {
-               return table[a.ordinal()][b.ordinal()];
-       }
-
-       static final Map<String, Bit> SYMBOL_MAP = Map.of(U.symbol, U, X.symbol, X, ZERO.symbol, ZERO, ONE.symbol, ONE, Z.symbol, Z);
-
-       // @formatter:off
-       private static final Bit[][] JOIN_TABLE = 
-               { { U, U, U,    U,   U    }, 
-                 { U, X, X,    X,   X    }, 
-                 { U, X, ZERO, X,   ZERO },
-                 { U, X, X,    ONE, ONE  }, 
-                 { U, X, ZERO, ONE, Z    } };
-
-       private static final Bit[][] AND_TABLE = 
-               { { U,    U,    ZERO, U,    U    }, 
-                 { U,    X,    ZERO, X,    X    },
-                 { ZERO, ZERO, ZERO, ZERO, ZERO }, 
-                 { U,    X,    ZERO, ONE,  X    }, 
-                 { U,    X,    ZERO, X,    X    } };
-
-       private static final Bit[][] OR_TABLE =
-       { { U,   U,   U,    ONE, U    },    
-         { U,   X,   X,    ONE, X    },    
-         { U,   X,   ZERO, ONE, X    },    
-         { ONE, ONE, ONE,  ONE, ONE  },    
-         { U,   X,   X,    ONE, X    } };
-       
-       private static final Bit[][] XOR_TABLE =
-       { { U, U, U,    U,    U },    
-         { U, X, X,    X,    X },    
-         { U, X, ZERO, ONE,  X },    
-         { U, X, ONE,  ZERO, X },    
-         { U, X, X,    X,    X } }; 
-       // @formatter:on
-}
\ No newline at end of file
diff --git a/era.mi/src/era/mi/logic/types/BitVector.java b/era.mi/src/era/mi/logic/types/BitVector.java
deleted file mode 100644 (file)
index 38d7d26..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-package era.mi.logic.types;
-
-import static java.lang.String.format;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.RandomAccess;
-import java.util.function.BinaryOperator;
-import java.util.function.UnaryOperator;
-
-/**
- * Immutable class representing a {@link Bit}Vector
- *
- *
- * @author Christian Femers
- *
- */
-public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
-{
-       private final Bit[] bits;
-
-       private BitVector(Bit[] bits)
-       {
-               this.bits = Objects.requireNonNull(bits);
-       }
-
-       public static BitVector of(Bit... bits)
-       {
-               return new BitVector(bits.clone());
-       }
-
-       public static BitVector of(Bit bit, int length)
-       {
-               return new BitVector(bit.makeArray(length));
-       }
-
-       public BitVectorMutator mutator()
-       {
-               return BitVectorMutator.of(this);
-       }
-
-       public Bit getBit(int bitIndex)
-       {
-               return bits[bitIndex];
-       }
-
-       public Bit[] getBits()
-       {
-               return bits.clone();
-       }
-
-       @Override
-       public BitVector join(BitVector t)
-       {
-               checkCompatibility(t);
-               return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
-       }
-
-       @Override
-       public BitVector and(BitVector t)
-       {
-               checkCompatibility(t);
-               return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
-       }
-
-       @Override
-       public BitVector or(BitVector t)
-       {
-               checkCompatibility(t);
-               return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
-       }
-
-       @Override
-       public BitVector xor(BitVector t)
-       {
-               checkCompatibility(t);
-               return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
-       }
-
-       @Override
-       public BitVector not()
-       {
-               return new BitVector(unOp(bits.clone(), Bit::not));
-       }
-
-       public int length()
-       {
-               return bits.length;
-       }
-
-       public BitVector concat(BitVector other)
-       {
-               Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
-               System.arraycopy(other.bits, 0, newBits, length(), other.length());
-               return new BitVector(newBits);
-       }
-
-       public BitVector subVector(int start)
-       {
-               return new BitVector(Arrays.copyOfRange(bits, start, length()));
-       }
-
-       public BitVector subVector(int start, int end)
-       {
-               return new BitVector(Arrays.copyOfRange(bits, start, end));
-       }
-
-       private void checkCompatibility(BitVector bv)
-       {
-               if (length() != bv.length())
-                       throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
-       }
-
-       static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
-       {
-               if (dest == null)
-                       return second.clone();
-               for (int i = 0; i < dest.length; i++)
-               {
-                       dest[i] = op.apply(dest[i], second[i]);
-               }
-               return dest;
-       }
-
-       static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
-       {
-               if (dest == null)
-                       return null;
-               for (int i = 0; i < dest.length; i++)
-               {
-                       dest[i] = op.apply(dest[i]);
-               }
-               return dest;
-       }
-
-       /**
-        * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
-        *
-        * @author Christian Femers
-        */
-       @SuppressWarnings("synthetic-access")
-       public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
-       {
-               private Bit[] bits;
-
-               private BitVectorMutator(Bit[] bits)
-               {
-                       this.bits = bits;
-               }
-
-               static BitVectorMutator of(BitVector bv)
-               {
-                       return new BitVectorMutator(bv.getBits());
-               }
-
-               /**
-                * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
-                * 
-                */
-               public static BitVectorMutator empty()
-               {
-                       return new BitVectorMutator(null);
-               }
-
-               /**
-                * Produces the resulting, immutable {@link BitVector}<br>
-                * 
-                * @throws IllegalStateException if the mutator is (still) empty
-                */
-               public BitVector get()
-               {
-                       if (bits == null)
-                               throw new IllegalStateException("cannot create a BitVector from an empty mutator");
-                       return new BitVector(bits);
-               }
-
-               @Override
-               public BitVectorMutator join(BitVector t)
-               {
-                       checkCompatibility(t);
-                       bits = binOp(bits, t.bits, Bit::join);
-                       return this;
-               }
-
-               @Override
-               public BitVectorMutator and(BitVector t)
-               {
-                       checkCompatibility(t);
-                       bits = binOp(bits, t.bits, Bit::and);
-                       return this;
-               }
-
-               @Override
-               public BitVectorMutator or(BitVector t)
-               {
-                       checkCompatibility(t);
-                       bits = binOp(bits, t.bits, Bit::or);
-                       return this;
-               }
-
-               @Override
-               public BitVectorMutator xor(BitVector t)
-               {
-                       checkCompatibility(t);
-                       bits = binOp(bits, t.bits, Bit::xor);
-                       return this;
-               }
-
-               @Override
-               public BitVectorMutator not()
-               {
-                       unOp(bits, Bit::not);
-                       return this;
-               }
-
-               private void checkCompatibility(BitVector bv)
-               {
-                       if (bits != null && bits.length != bv.length())
-                               throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
-               }
-       }
-
-       /**
-        * @see Arrays#hashCode(Object[])
-        */
-       @Override
-       public int hashCode()
-       {
-               return Arrays.hashCode(bits);
-       }
-
-       /**
-        * Does test for equality of values/content
-        * 
-        * @see Object#equals(Object)
-        */
-       @Override
-       public boolean equals(Object obj)
-       {
-               if (this == obj)
-                       return true;
-               if (!(obj instanceof BitVector))
-                       return false;
-               BitVector other = (BitVector) obj;
-               return Arrays.equals(bits, other.bits);
-       }
-
-       /**
-        * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
-        * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
-        * 
-        * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
-        * 
-        * @see Object#equals(Object)
-        */
-       public boolean equalsWithOffset(BitVector other, int offset)
-       {
-               if (other == null)
-                       return false;
-               return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
-       }
-
-       /**
-        * All {@link Bit}s symbols concatenated together
-        * 
-        * @see #parse(String)
-        */
-       @Override
-       public String toString()
-       {
-               StringBuilder sb = new StringBuilder(bits.length);
-               for (Bit bit : bits)
-                       sb.append(bit);
-               return sb.toString();
-       }
-
-       /**
-        * Parses a String containing solely {@link Bit} symbols
-        * 
-        * @see #toString()
-        */
-       public static BitVector parse(String s)
-       {
-               Bit[] values = new Bit[s.length()];
-               for (int i = 0; i < s.length(); i++)
-               {
-                       values[i] = Bit.parse(s, i);
-               }
-               return new BitVector(values);
-       }
-
-       @Override
-       public Iterator<Bit> iterator()
-       {
-               return new Iterator<>()
-               {
-                       private int pos = 0;
-
-                       @Override
-                       public Bit next()
-                       {
-                               if (!hasNext())
-                                       throw new NoSuchElementException();
-                               return getBit(pos++);
-                       }
-
-                       @Override
-                       public boolean hasNext()
-                       {
-                               return pos != length();
-                       }
-               };
-       }
-}
diff --git a/era.mi/src/era/mi/logic/types/BitVectorFormatter.java b/era.mi/src/era/mi/logic/types/BitVectorFormatter.java
deleted file mode 100644 (file)
index 6dab1d7..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-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
deleted file mode 100644 (file)
index b9e851f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-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).
- * <p>
- * A {@link ColorDefinition} is defined either by a {@link BuiltInColor} constant, in which case <code>r==g==b==-1</code>, or by red / green
- * / blue components, in which case <code>builtInColor==null</code>
- */
-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
diff --git a/era.mi/src/era/mi/logic/types/LogicType.java b/era.mi/src/era/mi/logic/types/LogicType.java
deleted file mode 100644 (file)
index 9a3180e..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-package era.mi.logic.types;
-
-/**
- * Interface for types that support the basic logic operations
- *
- * @author Christian Femers
- *
- * @param <T> the logic type itself, to make the operations closed in T
- * @param <S> the operand type, may be the same as T, see {@link StrictLogicType}
- */
-public interface LogicType<T extends LogicType<T, S>, S>
-{
-       /**
-        * Determines the result when two signals meet each other directly, also called resolution (IEEE 1164)
-        * 
-        * For example:
-        * 
-        * <pre>
-        * 0 joined 0 == 0
-        * 1 joined 0 == X
-        * 0 joined 1 == X
-        * 1 joined 1 == 1
-        * </pre>
-        * 
-        * @param t the second logic signal
-        * @return the resulting value
-        * @author Christian Femers
-        */
-       T join(S t);
-
-       /**
-        * Classical logic AND
-        * 
-        * For example:
-        * 
-        * <pre>
-        * 0 AND 0 == 0
-        * 1 AND 0 == 0
-        * 0 AND 1 == 0
-        * 1 AND 1 == 1
-        * </pre>
-        * 
-        * @param t the second logic signal
-        * @return the resulting value
-        * @author Christian Femers
-        */
-       T and(S t);
-
-       /**
-        * Classical logic OR
-        *
-        * For example:
-        * 
-        * <pre>
-        * 0 OR 0 == 0
-        * 1 OR 0 == 1
-        * 0 OR 1 == 1
-        * 1 OR 1 == 1
-        * </pre>
-        * 
-        * @param t the second logic signal
-        * @return the resulting value
-        * @author Christian Femers
-        */
-       T or(S t);
-
-       /**
-        * Classical logic XOR (exclusive OR)
-        * 
-        * For example:
-        * 
-        * <pre>
-        * 0 XOR 0 == 0
-        * 1 XOR 0 == 1
-        * 0 XOR 1 == 1
-        * 1 XOR 1 == 0
-        * </pre>
-        * 
-        * @param t the second logic signal
-        * @return the resulting value
-        * @author Christian Femers
-        */
-       T xor(S t);
-
-       /**
-        * Classical logic NOT (logical negation)
-        * 
-        * For example:
-        * 
-        * <pre>
-        * NOT 0 == 1
-        * NOT 1 == 0
-        * </pre>
-        * 
-        * @return the resulting value
-        * @author Christian Femers
-        */
-       T not();
-
-       /**
-        * {@link #and(Object) AND} and then {@link #not() NOT}
-        * 
-        * @author Christian Femers
-        */
-       default T nand(S t)
-       {
-               return and(t).not();
-       }
-
-       /**
-        * {@link #or(Object) OR} and then {@link #not() NOT}
-        * 
-        * @author Christian Femers
-        */
-       default T nor(S t)
-       {
-               return or(t).not();
-       }
-
-       /**
-        * {@link #xor(Object) XOR} and then {@link #not() NOT}<br>
-        * Used to determine equality (alias parity, consistency)
-        * 
-        * @author Christian Femers
-        */
-       default T xnor(S t)
-       {
-               return xor(t).not();
-       }
-}
diff --git a/era.mi/src/era/mi/logic/types/MutationOperation.java b/era.mi/src/era/mi/logic/types/MutationOperation.java
deleted file mode 100644 (file)
index 2ed9dc2..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package era.mi.logic.types;
-
-import java.util.function.BiFunction;
-
-import era.mi.logic.types.BitVector.BitVectorMutator;
-
-@FunctionalInterface
-public interface MutationOperation extends BiFunction<BitVectorMutator, BitVector, BitVectorMutator>
-{
-       // no changes necessary, only for convenience and readability
-}
diff --git a/era.mi/src/era/mi/logic/types/StrictLogicType.java b/era.mi/src/era/mi/logic/types/StrictLogicType.java
deleted file mode 100644 (file)
index 560bb96..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package era.mi.logic.types;
-
-/**
- * Interface for types that support the basic logic operations only among themselves, making it mathematically closed
- * 
- * @author Christian Femers
- * @see LogicType
- *
- * @param <T> the logic type itself to make the operations closed
- */
-public interface StrictLogicType<T extends StrictLogicType<T>> extends LogicType<T, T>
-{
-       // this is just a matter of type parameters
-}
diff --git a/era.mi/src/era/mi/logic/wires/Wire.java b/era.mi/src/era/mi/logic/wires/Wire.java
deleted file mode 100644 (file)
index 9a17387..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-package era.mi.logic.wires;
-
-import static era.mi.logic.types.Bit.U;
-import static era.mi.logic.types.Bit.Z;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import era.mi.logic.timeline.Timeline;
-import era.mi.logic.types.Bit;
-import era.mi.logic.types.BitVector;
-import era.mi.logic.types.BitVector.BitVectorMutator;
-
-/**
- * Represents an array of wires that can store n bits of information.
- * 
- * @author Fabian Stemmler
- *
- */
-public class Wire
-{
-       private BitVector values;
-       public final int travelTime;
-       private List<ReadEnd> attached = new ArrayList<ReadEnd>();
-       public final int length;
-       private List<ReadWriteEnd> inputs = new ArrayList<ReadWriteEnd>();
-       private Timeline timeline;
-
-       public Wire(Timeline timeline, int length, int travelTime)
-       {
-               if (length < 1)
-                       throw new IllegalArgumentException(
-                                       String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));
-               this.timeline = timeline;
-               this.length = length;
-               this.travelTime = travelTime;
-               initValues();
-       }
-
-       private void initValues()
-       {
-               values = U.toVector(length);
-       }
-
-       private void recalculateSingleInput()
-       {
-               setNewValues(inputs.get(0).getInputValues());
-       }
-
-       private void recalculateMultipleInputs()
-       {
-               BitVectorMutator mutator = BitVectorMutator.empty();
-               for (ReadWriteEnd wireArrayEnd : inputs)
-                       mutator.join(wireArrayEnd.getInputValues());
-               setNewValues(mutator.get());
-       }
-
-       private void setNewValues(BitVector newValues)
-       {
-               if (values.equals(newValues))
-                       return;
-               BitVector oldValues = values;
-               values = newValues;
-               notifyObservers(oldValues);
-       }
-
-       private void recalculate()
-       {
-               switch (inputs.size())
-               {
-               case 0:
-                       return;
-               case 1:
-                       recalculateSingleInput();
-                       break;
-               default:
-                       recalculateMultipleInputs();
-               }
-       }
-
-       /**
-        * The {@link Wire} is interpreted as an unsigned integer with n bits.
-        * 
-        * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the same
-        *         value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
-        * 
-        * @author Fabian Stemmler
-        */
-       public boolean hasNumericValue()
-       {
-               for (Bit b : values)
-               {
-                       if (b != Bit.ZERO && b != Bit.ONE)
-                               return false;
-               }
-               return true;
-       }
-
-       /**
-        * The {@link Wire} is interpreted as an unsigned integer with n bits.
-        * 
-        * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
-        * 
-        * @author Fabian Stemmler
-        */
-       public long getUnsignedValue()
-       {
-               long val = 0;
-               long mask = 1;
-               for (Bit bit : values)
-               {
-                       switch (bit)
-                       {
-                       default:
-                       case Z:
-                       case X:
-                               return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;
-                       case ONE:
-                               val |= mask;
-                               break;
-                       case ZERO:
-                       }
-                       mask = mask << 1;
-               }
-               return val;
-       }
-
-       /**
-        * The {@link Wire} is interpreted as a signed integer with n bits.
-        * 
-        * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
-        * 
-        * @author Fabian Stemmler
-        */
-       public long getSignedValue()
-       {
-               long val = getUnsignedValue();
-               long mask = 1 << (length - 1);
-               if ((mask & val) != 0)
-               {
-                       int shifts = 64 - length;
-                       return (val << shifts) >> shifts;
-               }
-               return val;
-       }
-
-       public Bit getValue()
-       {
-               return getValue(0);
-       }
-
-       public Bit getValue(int index)
-       {
-               return values.getBit(index);
-       }
-
-       public BitVector getValues(int start, int end)
-       {
-               return values.subVector(start, end);
-       }
-
-       public BitVector getValues()
-       {
-               return values;
-       }
-
-       /**
-        * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} is updated.
-        * 
-        * @param ob The {@link WireObserver} to be notified of changes.
-        * @return true if the given {@link WireObserver} was not already registered, false otherwise
-        * 
-        * @author Fabian Stemmler
-        */
-       private void attachEnd(ReadEnd end)
-       {
-               attached.add(end);
-       }
-
-       private void detachEnd(ReadEnd end)
-       {
-               attached.remove(end);
-       }
-
-       private void notifyObservers(BitVector oldValues)
-       {
-               for (ReadEnd o : attached)
-                       o.update(oldValues);
-       }
-
-       /**
-        * Create and register a {@link ReadWriteEnd} object, which is tied to this {@link Wire}. This {@link ReadWriteEnd} can be written to.
-        */
-       public ReadWriteEnd createReadWriteEnd()
-       {
-               return new ReadWriteEnd();
-       }
-
-       /**
-        * Create a {@link ReadEnd} object, which is tied to this {@link Wire}. This {@link ReadEnd} cannot be written to.
-        */
-       public ReadEnd createReadOnlyEnd()
-       {
-               return new ReadEnd();
-       }
-
-       private void registerInput(ReadWriteEnd toRegister)
-       {
-               inputs.add(toRegister);
-       }
-
-       /**
-        * A {@link ReadEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the
-        * {@link Wire}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs than Z 0
-        * and 1 turn into X when they are mixed
-        * 
-        * @author Fabian Stemmler
-        */
-       public class ReadEnd
-       {
-               private List<WireObserver> observers = new ArrayList<WireObserver>();
-
-               private ReadEnd()
-               {
-                       super();
-                       Wire.this.attachEnd(this);
-               }
-
-               public void update(BitVector oldValues)
-               {
-                       for (WireObserver ob : observers)
-                               ob.update(this, oldValues);
-               }
-
-               /**
-                * Included for convenient use on {@link Wire}s of length 1.
-                * 
-                * @return The value of bit 0.
-                * 
-                * @author Fabian Stemmler
-                */
-               public Bit getValue()
-               {
-                       return Wire.this.getValue();
-               }
-
-               /**
-                * @param index Index of the requested bit.
-                * @return The value of the indexed bit.
-                * 
-                * @author Fabian Stemmler
-                */
-               public Bit getValue(int index)
-               {
-                       return Wire.this.getValue(index);
-               }
-
-               /**
-                * @param index Index of the requested bit.
-                * @return The value of the indexed bit.
-                * 
-                * @author Fabian Stemmler
-                */
-               public BitVector getValues()
-               {
-                       return Wire.this.getValues();
-               }
-
-               /**
-                * @param start Start of the wanted segment. (inclusive)
-                * @param end   End of the wanted segment. (exclusive)
-                * @return The values of the segment of {@link Bit}s indexed.
-                * 
-                * @author Fabian Stemmler
-                */
-               public BitVector getValues(int start, int end)
-               {
-                       return Wire.this.getValues(start, end);
-               }
-
-               /**
-                * The {@link Wire} is interpreted as an unsigned integer with n bits.
-                * 
-                * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the
-                *         same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
-                * 
-                * @author Fabian Stemmler
-                */
-               public boolean hasNumericValue()
-               {
-                       return Wire.this.hasNumericValue();
-               }
-
-               /**
-                * The {@link Wire} is interpreted as an unsigned integer with n bits.
-                * 
-                * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
-                * 
-                * @author Fabian Stemmler
-                */
-               public long getUnsignedValue()
-               {
-                       return Wire.this.getUnsignedValue();
-               }
-
-               /**
-                * The {@link Wire} is interpreted as a signed integer with n bits.
-                * 
-                * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
-                * 
-                * @author Fabian Stemmler
-                */
-               public long getSignedValue()
-               {
-                       return Wire.this.getSignedValue();
-               }
-
-               @Override
-               public String toString()
-               {
-                       return Wire.this.toString();
-               }
-
-               public void close()
-               {
-                       inputs.remove(this);
-                       detachEnd(this);
-                       recalculate();
-               }
-
-               public int length()
-               {
-                       return length;
-               }
-
-               public boolean addObserver(WireObserver ob)
-               {
-                       return observers.add(ob);
-               }
-
-               public Wire getWire()
-               {
-                       return Wire.this;
-               }
-       }
-
-       public class ReadWriteEnd extends ReadEnd
-       {
-               private boolean open;
-               private BitVector inputValues;
-
-               private ReadWriteEnd()
-               {
-                       super();
-                       open = true;
-                       initValues();
-                       registerInput(this);
-               }
-
-               private void initValues()
-               {
-                       inputValues = U.toVector(length);
-               }
-
-               /**
-                * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.
-                * 
-                * @param newValues The new values the wires should take on.
-                * 
-                * @author Fabian Stemmler
-                */
-               public void feedSignals(Bit... newValues)
-               {
-                       feedSignals(BitVector.of(newValues));
-               }
-
-               public void feedSignals(BitVector newValues)
-               {
-                       if (newValues.length() != length)
-                               throw new IllegalArgumentException(
-                                               String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));
-                       if (!open)
-                               throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
-                       timeline.addEvent(e -> setValues(newValues), travelTime);
-               }
-
-               /**
-                * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
-                * 
-                * @param bitVector   The new values the wires should take on.
-                * @param startingBit The first index of the subarray of wires.
-                * 
-                * @author Fabian Stemmler
-                */
-               public void feedSignals(int startingBit, BitVector bitVector)
-               {
-                       if (!open)
-                               throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
-                       timeline.addEvent(e -> setValues(startingBit, bitVector), travelTime);
-               }
-
-               private void setValues(int startingBit, BitVector newValues)
-               {
-                       // index check covered in equals
-                       if (!inputValues.equalsWithOffset(newValues, startingBit))
-                       {
-                               Bit[] vals = inputValues.getBits();
-                               System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());
-                               inputValues = BitVector.of(vals);
-                               Wire.this.recalculate();
-                       }
-               }
-
-               private void setValues(BitVector newValues)
-               {
-                       if (inputValues.equals(newValues))
-                               return;
-                       inputValues = newValues;
-                       Wire.this.recalculate();
-               }
-
-               /**
-                * @return The value (of bit 0) the {@link ReadEnd} is currently feeding into the associated {@link Wire}.
-                */
-               public Bit getInputValue()
-               {
-                       return getInputValue(0);
-               }
-
-               /**
-                * @return The value which the {@link ReadEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.
-                */
-               public Bit getInputValue(int index)
-               {
-                       return inputValues.getBit(index);
-               }
-
-               /**
-                * @return A copy (safe to modify) of the values the {@link ReadEnd} is currently feeding into the associated {@link Wire}.
-                */
-               public BitVector getInputValues()
-               {
-                       return getInputValues(0, length);
-               }
-
-               public BitVector getInputValues(int start, int end)
-               {
-                       return inputValues.subVector(start, end);
-               }
-
-               /**
-                * {@link ReadEnd} now feeds Z into the associated {@link Wire}.
-                */
-               public void clearSignals()
-               {
-                       feedSignals(Z.toVector(length));
-               }
-
-               public BitVector wireValuesExcludingMe()
-               {
-                       BitVectorMutator mutator = BitVectorMutator.empty();
-                       for (ReadWriteEnd wireEnd : inputs)
-                       {
-                               if (wireEnd == this)
-                                       continue;
-                               mutator.join(wireEnd.inputValues);
-                       }
-                       return mutator.get();
-               }
-
-               @Override
-               public String toString()
-               {
-                       return inputValues.toString();
-               }
-       }
-
-       @Override
-       public String toString()
-       {
-               return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), values, inputs);
-               // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)
-       }
-
-       public static ReadEnd[] extractEnds(Wire[] w)
-       {
-               ReadEnd[] inputs = new ReadEnd[w.length];
-               for (int i = 0; i < w.length; i++)
-                       inputs[i] = w[i].createReadWriteEnd();
-               return inputs;
-       }
-}
\ No newline at end of file
diff --git a/era.mi/src/era/mi/logic/wires/WireObserver.java b/era.mi/src/era/mi/logic/wires/WireObserver.java
deleted file mode 100644 (file)
index 4c4bce0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-package era.mi.logic.wires;
-
-import era.mi.logic.types.BitVector;
-import era.mi.logic.wires.Wire.ReadEnd;
-
-public interface WireObserver
-{
-       public void update(ReadEnd initiator, BitVector oldValues);
-}
diff --git a/era.mi/src/mograsim/logic/core/Util.java b/era.mi/src/mograsim/logic/core/Util.java
new file mode 100644 (file)
index 0000000..5f88e83
--- /dev/null
@@ -0,0 +1,110 @@
+package mograsim.logic.core;
+
+import java.util.Arrays;
+
+import mograsim.logic.core.types.Bit;
+
+public final class Util
+{
+
+       @SuppressWarnings("unchecked")
+       public static <T> T[] concat(T[]... arrays)
+       {
+               if (arrays.length == 0)
+                       throw new IllegalArgumentException("Cannot concatenate 0 arrays.");
+
+               int length = 0;
+               for (T[] array : arrays)
+                       length += array.length;
+
+               T[] newArray = Arrays.copyOf(arrays[0], length);
+               int appendIndex = arrays[0].length;
+               for (int i = 1; i < arrays.length; i++)
+               {
+                       System.arraycopy(arrays[i], 0, newArray, appendIndex, arrays[i].length);
+                       appendIndex += arrays[i].length;
+               }
+
+               return newArray;
+       }
+
+//     @SuppressWarnings("unchecked")
+//     public static <T> T[][] split(T[] array, int... lengths)
+//     {
+//             //TODO: implement array split again; This version contains an illegal cast
+//             int totalLength = 0;
+//             for(int length : lengths)
+//                     totalLength += length;
+//             
+//             if(totalLength != array.length)
+//                     throw new IllegalArgumentException(); //TODO: add proper error message
+//             
+//             Object[][] newArray = new Object[lengths.length][];
+//             int splitIndex = 0;
+//             for(int i = 0; i < lengths.length; i++)
+//             {
+//                     System.arraycopy(array, splitIndex, newArray, 0, lengths[i]);
+//                     splitIndex += lengths[i];
+//             }
+//             
+//             return (T[][]) newArray;
+//     }
+
+       public static Bit[] and(Bit[] a, Bit[] b)
+       {
+               return binBitOp(a, b, Bit::and);
+       }
+
+       public static Bit[] or(Bit[] a, Bit[] b)
+       {
+               return binBitOp(a, b, Bit::or);
+       }
+
+       public static Bit[] xor(Bit[] a, Bit[] b)
+       {
+               return binBitOp(a, b, Bit::xor);
+       }
+
+       private static Bit[] binBitOp(Bit[] a, Bit[] b, BitOp op)
+       {
+               if (a.length != b.length)
+                       throw new IllegalArgumentException("Bit Arrays were not of equal length.");
+               Bit[] out = new Bit[a.length];
+               for (int i = 0; i < a.length; i++)
+               {
+                       out[i] = op.execute(a[i], b[i]);
+               }
+               return out;
+       }
+
+       public static Bit[] not(Bit[] a)
+       {
+               Bit[] out = new Bit[a.length];
+               for (int i = 0; i < a.length; i++)
+               {
+                       out[i] = a[i].not();
+               }
+               return out;
+       }
+
+       /**
+        * uses the {@link Bit#combineWith(Bit)} method, does not create a new array, the result is stored in the first array.
+        * 
+        * @author Christian Femers
+        */
+       public static Bit[] combineInto(Bit[] dest, Bit[] addition)
+       {
+               if (dest.length != addition.length)
+                       throw new IllegalArgumentException("Bit Arrays were not of equal length.");
+               for (int i = 0; i < addition.length; i++)
+               {
+                       dest[i] = dest[i].join(addition[i]);
+               }
+               return dest;
+       }
+
+       interface BitOp
+       {
+               Bit execute(Bit a, Bit b);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/BasicComponent.java b/era.mi/src/mograsim/logic/core/components/BasicComponent.java
new file mode 100644 (file)
index 0000000..720c125
--- /dev/null
@@ -0,0 +1,36 @@
+package mograsim.logic.core.components;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.BitVector;
+import mograsim.logic.core.wires.WireObserver;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+
+/**
+ * A basic component that recomputes all outputs (with a delay), when it is updated.
+ * 
+ * @author Fabian Stemmler
+ */
+public abstract class BasicComponent extends Component implements WireObserver
+{
+       private int processTime;
+
+       /**
+        * 
+        * @param processTime Amount of time this component takes to update its outputs. Must be more than 0, otherwise 1 is assumed.
+        * 
+        * @author Fabian Stemmler
+        */
+       public BasicComponent(Timeline timeline, int processTime)
+       {
+               super(timeline);
+               this.processTime = processTime > 0 ? processTime : 1;
+       }
+
+       @Override
+       public void update(ReadEnd initiator, BitVector oldValues)
+       {
+               timeline.addEvent(e -> compute(), processTime);
+       }
+
+       protected abstract void compute();
+}
diff --git a/era.mi/src/mograsim/logic/core/components/BitDisplay.java b/era.mi/src/mograsim/logic/core/components/BitDisplay.java
new file mode 100644 (file)
index 0000000..0d398da
--- /dev/null
@@ -0,0 +1,51 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.Bit;
+import mograsim.logic.core.types.BitVector;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class BitDisplay extends BasicComponent
+{
+       private final ReadEnd in;
+       private BitVector displayedValue;
+
+       public BitDisplay(Timeline timeline, ReadEnd in)
+       {
+               super(timeline, 1);
+               this.in = in;
+               in.addObserver(this);
+               compute();
+       }
+
+       @Override
+       protected void compute()
+       {
+               displayedValue = in.getValues();
+       }
+
+       public BitVector getDisplayedValue()
+       {
+               return displayedValue;
+       }
+
+       public boolean isDisplaying(Bit... values)
+       {
+               return displayedValue.equals(BitVector.of(values));
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of(in);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of();
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/Clock.java b/era.mi/src/mograsim/logic/core/components/Clock.java
new file mode 100644 (file)
index 0000000..4b15ed3
--- /dev/null
@@ -0,0 +1,61 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.timeline.TimelineEvent;
+import mograsim.logic.core.timeline.TimelineEventHandler;
+import mograsim.logic.core.types.Bit;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class Clock extends Component implements TimelineEventHandler
+{
+       private boolean toggle = false;
+       private ReadWriteEnd out;
+       private int delta;
+
+       /**
+        * 
+        * @param out   {@link Wire} the clock's impulses are fed into
+        * @param delta ticks between rising and falling edge
+        */
+       public Clock(Timeline timeline, ReadWriteEnd out, int delta)
+       {
+               super(timeline);
+               this.delta = delta;
+               this.out = out;
+               addToTimeline();
+       }
+
+       @Override
+       public void handle(TimelineEvent e)
+       {
+               addToTimeline();
+               out.feedSignals(toggle ? Bit.ONE : Bit.ZERO);
+               toggle = !toggle;
+       }
+
+       public ReadWriteEnd getOut()
+       {
+               return out;
+       }
+
+       private void addToTimeline()
+       {
+               timeline.addEvent(this, delta);
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of();
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(out);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/Component.java b/era.mi/src/mograsim/logic/core/components/Component.java
new file mode 100644 (file)
index 0000000..54109df
--- /dev/null
@@ -0,0 +1,28 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public abstract class Component
+{
+       protected Timeline timeline;
+
+       public Component(Timeline timeline)
+       {
+               this.timeline = timeline;
+       }
+
+       /**
+        * Returns immutable list of all inputs to the {@link Component} (including e.g. the select bits to a MUX). Intended for visualization
+        * in the UI.
+        */
+       public abstract List<ReadEnd> getAllInputs();
+
+       /**
+        * Returns immutable list of all outputs to the {@link Component}. Intended for visualization in the UI.
+        */
+       public abstract List<ReadWriteEnd> getAllOutputs();
+}
diff --git a/era.mi/src/mograsim/logic/core/components/Connector.java b/era.mi/src/mograsim/logic/core/components/Connector.java
new file mode 100644 (file)
index 0000000..0972cfa
--- /dev/null
@@ -0,0 +1,76 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.BitVector;
+import mograsim.logic.core.wires.WireObserver;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class Connector extends Component implements WireObserver
+{
+       private boolean connected;
+       private final ReadWriteEnd a;
+       private final ReadWriteEnd b;
+
+       public Connector(Timeline timeline, ReadWriteEnd a, ReadWriteEnd b)
+       {
+               super(timeline);
+               if (a.length() != b.length())
+                       throw new IllegalArgumentException(String.format("WireArray width does not match: %d, %d", a.length(), b.length()));
+               this.a = a;
+               this.b = b;
+               a.addObserver(this);
+               b.addObserver(this);
+       }
+
+       public void connect()
+       {
+               connected = true;
+               update(a);
+               update(b);
+       }
+
+       public void disconnect()
+       {
+               connected = false;
+               a.clearSignals();
+               b.clearSignals();
+       }
+
+       public void setConnection(boolean connected)
+       {
+               if (connected)
+                       connect();
+               else
+                       disconnect();
+       }
+
+       @Override
+       public void update(ReadEnd initiator, BitVector oldValues)
+       {
+               if (connected)
+                       timeline.addEvent(e -> update(initiator), 1);
+       }
+
+       private void update(ReadEnd initiator)
+       {
+               if (initiator == a)
+                       b.feedSignals(a.wireValuesExcludingMe());
+               else
+                       a.feedSignals(b.wireValuesExcludingMe());
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of(a, b);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(a, b);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/Demux.java b/era.mi/src/mograsim/logic/core/components/Demux.java
new file mode 100644 (file)
index 0000000..f1efb72
--- /dev/null
@@ -0,0 +1,82 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+/**
+ * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the
+ * output.
+ * 
+ * @author Fabian Stemmler
+ *
+ */
+public class Demux extends BasicComponent
+{
+       private final ReadEnd select, in;
+       private final ReadWriteEnd[] outputs;
+       private final int outputSize;
+       private int selected = -1;
+
+       /**
+        * Output {@link Wire}s and in must be of uniform length
+        * 
+        * @param in      Must be of uniform length with all outputs.
+        * @param select  Indexes the output array to which the input is mapped. Must have enough bits to index all outputs.
+        * @param outputs One of these outputs receives the input signal, depending on the select bits
+        */
+       public Demux(Timeline timeline, int processTime, ReadEnd in, ReadEnd select, ReadWriteEnd... outputs)
+       {
+               super(timeline, processTime);
+               outputSize = in.length();
+
+               this.in = in;
+               this.outputs = outputs;
+               for (int i = 0; i < this.outputs.length; i++)
+               {
+                       if (outputs[i].length() != outputSize)
+                               throw new IllegalArgumentException("All DEMUX wire arrays must be of uniform length!");
+                       this.outputs[i] = outputs[i];
+               }
+
+               this.select = select;
+               select.addObserver(this);
+
+               int maxInputs = 1 << select.length();
+               if (this.outputs.length > maxInputs)
+                       throw new IllegalArgumentException("There are more outputs (" + this.outputs.length + ") to the DEMUX than supported by "
+                                       + select.length() + " select bits (" + maxInputs + ").");
+               in.addObserver(this);
+       }
+
+       @Override
+       public void compute()
+       {
+               int selectValue = select.hasNumericValue() ? (int) select.getUnsignedValue() : -1;
+               if (selectValue >= outputs.length)
+                       selectValue = -1;
+
+               if (selected != selectValue && selected != -1)
+                       outputs[selected].clearSignals();
+
+               selected = selectValue;
+
+               if (selectValue != -1)
+                       outputs[selectValue].feedSignals(in.getValues());
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of(in, select);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(outputs);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/ManualSwitch.java b/era.mi/src/mograsim/logic/core/components/ManualSwitch.java
new file mode 100644 (file)
index 0000000..5012761
--- /dev/null
@@ -0,0 +1,74 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.Bit;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+/**
+ * This class models a simple on/off (ONE/ZERO) switch for user interaction.
+ *
+ * @author Christian Femers
+ *
+ */
+public class ManualSwitch extends Component
+{
+       private ReadWriteEnd output;
+       private boolean isOn;
+
+       public ManualSwitch(Timeline timeline, ReadWriteEnd output)
+       {
+               super(timeline);
+               if (output.length() != 1)
+                       throw new IllegalArgumentException("Switch output can be only a single wire");
+               this.output = output;
+       }
+
+       public void switchOn()
+       {
+               setState(true);
+       }
+
+       public void switchOff()
+       {
+               setState(false);
+       }
+
+       public void toggle()
+       {
+               setState(!isOn);
+       }
+
+       public void setState(boolean isOn)
+       {
+               if (this.isOn == isOn)
+                       return;
+               this.isOn = isOn;
+               output.feedSignals(getValue());
+       }
+
+       public boolean isOn()
+       {
+               return isOn;
+       }
+
+       public Bit getValue()
+       {
+               return isOn ? Bit.ONE : Bit.ZERO;
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of();
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(output);
+       }
+
+}
diff --git a/era.mi/src/mograsim/logic/core/components/Merger.java b/era.mi/src/mograsim/logic/core/components/Merger.java
new file mode 100644 (file)
index 0000000..114dbe7
--- /dev/null
@@ -0,0 +1,85 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.BitVector;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.WireObserver;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class Merger extends Component implements WireObserver
+{
+       private ReadWriteEnd out;
+       private ReadEnd[] inputs;
+       private int[] beginningIndex;
+
+       /**
+        * 
+        * @param union  The output of merging n {@link Wire}s into one. Must have length = a1.length() + a2.length() + ... + an.length().
+        * @param inputs The inputs to be merged into the union
+        */
+       public Merger(Timeline timeline, ReadWriteEnd union, ReadEnd... inputs)
+       {
+               super(timeline);
+               this.inputs = inputs;
+               this.out = union;
+               this.beginningIndex = new int[inputs.length];
+
+               int length = 0;
+               for (int i = 0; i < inputs.length; i++)
+               {
+                       beginningIndex[i] = length;
+                       length += inputs[i].length();
+                       inputs[i].addObserver(this);
+               }
+
+               if (length != union.length())
+                       throw new IllegalArgumentException(
+                                       "The output of merging n WireArrays into one must have length = a1.length() + a2.length() + ... + an.length().");
+       }
+
+       public ReadEnd getInput(int index)
+       {
+               return inputs[index];
+       }
+
+       public ReadEnd getUnion()
+       {
+               return out;
+       }
+
+       @Override
+       public void update(ReadEnd initiator, BitVector oldValues)
+       {
+               int index = find(initiator);
+               int beginning = beginningIndex[index];
+               out.feedSignals(beginning, inputs[index].getValues());
+       }
+
+       private int find(ReadEnd r)
+       {
+               for (int i = 0; i < inputs.length; i++)
+                       if (inputs[i] == r)
+                               return i;
+               return -1;
+       }
+
+       public ReadEnd[] getInputs()
+       {
+               return inputs.clone();
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of(inputs);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(out);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/Mux.java b/era.mi/src/mograsim/logic/core/components/Mux.java
new file mode 100644 (file)
index 0000000..44c2a1d
--- /dev/null
@@ -0,0 +1,95 @@
+package mograsim.logic.core.components;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+/**
+ * Models a multiplexer. Takes an arbitrary amount of input {@link Wire}s, one of which, as determined by select, is put through to the
+ * output.
+ * 
+ * @author Fabian Stemmler
+ *
+ */
+public class Mux extends BasicComponent
+{
+       private ReadEnd select;
+       private ReadWriteEnd out;
+       private ReadEnd[] inputs;
+       private final int outputSize;
+
+       /**
+        * Input {@link Wire}s and out must be of uniform length
+        * 
+        * @param out    Must be of uniform length with all inputs.
+        * @param select Indexes the input array which is to be mapped to the output. Must have enough bits to index all inputs.
+        * @param inputs One of these inputs is mapped to the output, depending on the select bits
+        */
+       public Mux(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd select, ReadEnd... inputs)
+       {
+               super(timeline, processTime);
+               outputSize = out.length();
+
+               this.inputs = inputs.clone();
+               for (int i = 0; i < this.inputs.length; i++)
+               {
+                       if (inputs[i].length() != outputSize)
+                               throw new IllegalArgumentException("All MUX wire arrays must be of uniform length!");
+                       inputs[i].addObserver(this);
+               }
+
+               this.select = select;
+               select.addObserver(this);
+
+               int maxInputs = 1 << select.length();
+               if (this.inputs.length > maxInputs)
+                       throw new IllegalArgumentException("There are more inputs (" + this.inputs.length + ") to the MUX than supported by "
+                                       + select.length() + " select bits (" + maxInputs + ").");
+
+               this.out = out;
+       }
+
+       public ReadEnd getOut()
+       {
+               return out;
+       }
+
+       public ReadEnd getSelect()
+       {
+               return select;
+       }
+
+       @Override
+       public void compute()
+       {
+               int selectValue;
+               if (!select.hasNumericValue() || (selectValue = (int) select.getUnsignedValue()) >= inputs.length)
+               {
+                       out.clearSignals();
+                       return;
+               }
+
+               ReadEnd active = inputs[selectValue];
+               out.feedSignals(active.getValues());
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               ArrayList<ReadEnd> wires = new ArrayList<ReadEnd>(Arrays.asList(inputs));
+               wires.add(select);
+               return Collections.unmodifiableList(wires);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(out);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/Splitter.java b/era.mi/src/mograsim/logic/core/components/Splitter.java
new file mode 100644 (file)
index 0000000..3474952
--- /dev/null
@@ -0,0 +1,59 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.BitVector;
+import mograsim.logic.core.wires.WireObserver;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class Splitter extends Component implements WireObserver
+{
+       private ReadEnd input;
+       private ReadWriteEnd[] outputs;
+
+       public Splitter(Timeline timeline, ReadEnd input, ReadWriteEnd... outputs)
+       {
+               super(timeline);
+               this.input = input;
+               this.outputs = outputs;
+               input.addObserver(this);
+               int length = 0;
+               for (ReadEnd out : outputs)
+                       length += out.length();
+
+               if (input.length() != length)
+                       throw new IllegalArgumentException(
+                                       "The input of splitting one into n WireArrays must have length = a1.length() + a2.length() + ... + an.length().");
+       }
+
+       protected void compute()
+       {
+               BitVector inputBits = input.getValues();
+               int startIndex = 0;
+               for (int i = 0; i < outputs.length; i++)
+               {
+                       outputs[i].feedSignals(inputBits.subVector(startIndex, startIndex + outputs[i].length()));
+                       startIndex += outputs[i].length();
+               }
+       }
+
+       @Override
+       public void update(ReadEnd initiator, BitVector oldValues)
+       {
+               compute();
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of(input);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(outputs);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/TriStateBuffer.java b/era.mi/src/mograsim/logic/core/components/TriStateBuffer.java
new file mode 100644 (file)
index 0000000..b8ba065
--- /dev/null
@@ -0,0 +1,51 @@
+package mograsim.logic.core.components;
+
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.Bit;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class TriStateBuffer extends BasicComponent
+{
+       ReadEnd in, enable;
+       ReadWriteEnd out;
+
+       public TriStateBuffer(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out, ReadEnd enable)
+       {
+               super(timeline, processTime);
+               if (in.length() != out.length())
+                       throw new IllegalArgumentException(
+                                       "Tri-state output must have the same amount of bits as the input. Input: " + in.length() + " Output: " + out.length());
+               if (enable.length() != 1)
+                       throw new IllegalArgumentException("Tri-state enable must have exactly one bit, not " + enable.length() + ".");
+               this.in = in;
+               in.addObserver(this);
+               this.enable = enable;
+               enable.addObserver(this);
+               this.out = out;
+       }
+
+       @Override
+       protected void compute()
+       {
+               if (enable.getValue() == Bit.ONE)
+                       out.feedSignals(in.getValues());
+               else
+                       out.clearSignals();
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of(in, enable);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(out);
+       }
+
+}
diff --git a/era.mi/src/mograsim/logic/core/components/gates/AndGate.java b/era.mi/src/mograsim/logic/core/components/gates/AndGate.java
new file mode 100644 (file)
index 0000000..1f02a19
--- /dev/null
@@ -0,0 +1,14 @@
+package mograsim.logic.core.components.gates;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.BitVector.BitVectorMutator;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class AndGate extends MultiInputGate
+{
+       public AndGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)
+       {
+               super(timeline, processTime, BitVectorMutator::and, out, in);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/gates/MultiInputGate.java b/era.mi/src/mograsim/logic/core/components/gates/MultiInputGate.java
new file mode 100644 (file)
index 0000000..40b1078
--- /dev/null
@@ -0,0 +1,56 @@
+package mograsim.logic.core.components.gates;
+
+import java.util.List;
+
+import mograsim.logic.core.components.BasicComponent;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.MutationOperation;
+import mograsim.logic.core.types.BitVector.BitVectorMutator;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public abstract class MultiInputGate extends BasicComponent
+{
+       protected ReadEnd[] in;
+       protected ReadWriteEnd out;
+       protected final int length;
+       protected MutationOperation op;
+
+       protected MultiInputGate(Timeline timeline, int processTime, MutationOperation op, ReadWriteEnd out, ReadEnd... in)
+       {
+               super(timeline, processTime);
+               this.op = op;
+               length = out.length();
+               this.in = in.clone();
+               if (in.length < 1)
+                       throw new IllegalArgumentException(String.format("Cannot create gate with %d wires.", in.length));
+               for (ReadEnd w : in)
+               {
+                       if (w.length() != length)
+                               throw new IllegalArgumentException("All wires connected to the gate must be of uniform length.");
+                       w.addObserver(this);
+               }
+               this.out = out;
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of(in);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(out);
+       }
+
+       @Override
+       protected void compute()
+       {
+               BitVectorMutator mutator = BitVectorMutator.empty();
+               for (ReadEnd w : in)
+                       op.apply(mutator, w.getValues());
+               out.feedSignals(mutator.get());
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/gates/NotGate.java b/era.mi/src/mograsim/logic/core/components/gates/NotGate.java
new file mode 100644 (file)
index 0000000..ebad7e3
--- /dev/null
@@ -0,0 +1,50 @@
+package mograsim.logic.core.components.gates;
+
+import java.util.List;
+
+import mograsim.logic.core.components.BasicComponent;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class NotGate extends BasicComponent
+{
+       private ReadEnd in;
+       private ReadWriteEnd out;
+
+       public NotGate(Timeline timeline, int processTime, ReadEnd in, ReadWriteEnd out)
+       {
+               super(timeline, processTime);
+               this.in = in;
+               in.addObserver(this);
+               this.out = out;
+       }
+
+       @Override
+       protected void compute()
+       {
+               out.feedSignals(in.getValues().not());
+       }
+
+       public ReadEnd getIn()
+       {
+               return in;
+       }
+
+       public ReadEnd getOut()
+       {
+               return out;
+       }
+
+       @Override
+       public List<ReadEnd> getAllInputs()
+       {
+               return List.of(in);
+       }
+
+       @Override
+       public List<ReadWriteEnd> getAllOutputs()
+       {
+               return List.of(out);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/gates/OrGate.java b/era.mi/src/mograsim/logic/core/components/gates/OrGate.java
new file mode 100644 (file)
index 0000000..69d6411
--- /dev/null
@@ -0,0 +1,14 @@
+package mograsim.logic.core.components.gates;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.BitVector.BitVectorMutator;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+public class OrGate extends MultiInputGate
+{
+       public OrGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)
+       {
+               super(timeline, processTime, BitVectorMutator::or, out, in);
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/components/gates/XorGate.java b/era.mi/src/mograsim/logic/core/components/gates/XorGate.java
new file mode 100644 (file)
index 0000000..ea96036
--- /dev/null
@@ -0,0 +1,20 @@
+package mograsim.logic.core.components.gates;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.BitVector.BitVectorMutator;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+/**
+ * Outputs 1 when the number of 1 inputs is odd.
+ * 
+ * @author Fabian Stemmler
+ */
+public class XorGate extends MultiInputGate
+{
+       public XorGate(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd... in)
+       {
+               super(timeline, processTime, BitVectorMutator::xor, out, in);
+       }
+
+}
diff --git a/era.mi/src/mograsim/logic/core/tests/ComponentTest.java b/era.mi/src/mograsim/logic/core/tests/ComponentTest.java
new file mode 100644 (file)
index 0000000..c080d1a
--- /dev/null
@@ -0,0 +1,433 @@
+package mograsim.logic.core.tests;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.function.LongConsumer;
+
+import org.junit.jupiter.api.Test;
+
+import mograsim.logic.core.components.Connector;
+import mograsim.logic.core.components.Demux;
+import mograsim.logic.core.components.Merger;
+import mograsim.logic.core.components.Mux;
+import mograsim.logic.core.components.Splitter;
+import mograsim.logic.core.components.TriStateBuffer;
+import mograsim.logic.core.components.gates.AndGate;
+import mograsim.logic.core.components.gates.NotGate;
+import mograsim.logic.core.components.gates.OrGate;
+import mograsim.logic.core.components.gates.XorGate;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.Bit;
+import mograsim.logic.core.types.BitVector;
+import mograsim.logic.core.wires.Wire;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+import mograsim.logic.core.wires.Wire.ReadWriteEnd;
+
+class ComponentTest
+{
+       private Timeline t = new Timeline(11);
+
+       @Test
+       void circuitExampleTest()
+       {
+               Wire a = new Wire(t, 1, 1), b = new Wire(t, 1, 1), c = new Wire(t, 1, 10), d = new Wire(t, 2, 1), e = new Wire(t, 1, 1),
+                               f = new Wire(t, 1, 1), g = new Wire(t, 1, 1), h = new Wire(t, 2, 1), i = new Wire(t, 2, 1), j = new Wire(t, 1, 1),
+                               k = new Wire(t, 1, 1);
+               new AndGate(t, 1, f.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
+               new NotGate(t, 1, f.createReadOnlyEnd(), g.createReadWriteEnd());
+               new Merger(t, h.createReadWriteEnd(), c.createReadOnlyEnd(), g.createReadOnlyEnd());
+               new Mux(t, 1, i.createReadWriteEnd(), e.createReadOnlyEnd(), h.createReadOnlyEnd(), d.createReadOnlyEnd());
+               new Splitter(t, i.createReadOnlyEnd(), k.createReadWriteEnd(), j.createReadWriteEnd());
+
+               a.createReadWriteEnd().feedSignals(Bit.ZERO);
+               b.createReadWriteEnd().feedSignals(Bit.ONE);
+               c.createReadWriteEnd().feedSignals(Bit.ZERO);
+               d.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE);
+               e.createReadWriteEnd().feedSignals(Bit.ZERO);
+
+               t.executeAll();
+
+               assertEquals(Bit.ONE, j.getValue());
+               assertEquals(Bit.ZERO, k.getValue());
+       }
+
+       @Test
+       void splitterTest()
+       {
+               t.reset();
+               Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), in = new Wire(t, 8, 1);
+               in.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+               new Splitter(t, in.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(), c.createReadWriteEnd());
+
+               t.executeAll();
+
+               assertBitArrayEquals(a.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO);
+               assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO);
+               assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE);
+       }
+
+       @Test
+       void mergerTest()
+       {
+               t.reset();
+               Wire a = new Wire(t, 3, 1), b = new Wire(t, 2, 1), c = new Wire(t, 3, 1), out = new Wire(t, 8, 1);
+               a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO);
+               b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO);
+               c.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
+
+               new Merger(t, out.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
+
+               t.executeAll();
+
+               assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+       }
+
+       @Test
+       void triStateBufferTest()
+       {
+               Wire a = new Wire(t, 1, 1), b = new Wire(t, 1, 1), en = new Wire(t, 1, 1), notEn = new Wire(t, 1, 1);
+               new NotGate(t, 1, en.createReadOnlyEnd(), notEn.createReadWriteEnd());
+               new TriStateBuffer(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd(), en.createReadOnlyEnd());
+               new TriStateBuffer(t, 1, b.createReadOnlyEnd(), a.createReadWriteEnd(), notEn.createReadOnlyEnd());
+
+               ReadWriteEnd enI = en.createReadWriteEnd(), aI = a.createReadWriteEnd(), bI = b.createReadWriteEnd();
+               enI.feedSignals(Bit.ONE);
+               aI.feedSignals(Bit.ONE);
+               bI.feedSignals(Bit.Z);
+
+               t.executeAll();
+
+               assertEquals(Bit.ONE, b.getValue());
+
+               bI.feedSignals(Bit.ZERO);
+
+               t.executeAll();
+
+               assertEquals(Bit.X, b.getValue());
+               assertEquals(Bit.ONE, a.getValue());
+
+               aI.clearSignals();
+               enI.feedSignals(Bit.ZERO);
+
+               t.executeAll();
+
+               assertEquals(Bit.ZERO, a.getValue());
+
+       }
+
+       @Test
+       void muxTest()
+       {
+               t.reset();
+               Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), out = new Wire(t, 4, 1);
+               ReadWriteEnd selectIn = select.createReadWriteEnd();
+
+               selectIn.feedSignals(Bit.ZERO, Bit.ZERO);
+               a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+               c.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+
+               new Mux(t, 1, out.createReadWriteEnd(), select.createReadOnlyEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(),
+                               c.createReadOnlyEnd());
+               t.executeAll();
+
+               assertBitArrayEquals(out.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+               selectIn.feedSignals(Bit.ZERO, Bit.ONE);
+               t.executeAll();
+
+               assertBitArrayEquals(out.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+
+               selectIn.feedSignals(Bit.ONE, Bit.ONE);
+               t.executeAll();
+
+               assertBitArrayEquals(out.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
+
+       }
+
+       @Test
+       void demuxTest()
+       {
+               t.reset();
+               Wire a = new Wire(t, 4, 3), b = new Wire(t, 4, 6), c = new Wire(t, 4, 4), select = new Wire(t, 2, 5), in = new Wire(t, 4, 1);
+               ReadWriteEnd selectIn = select.createReadWriteEnd();
+
+               selectIn.feedSignals(Bit.ZERO, Bit.ZERO);
+               in.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+
+               new Demux(t, 1, in.createReadOnlyEnd(), select.createReadOnlyEnd(), a.createReadWriteEnd(), b.createReadWriteEnd(),
+                               c.createReadWriteEnd());
+               t.executeAll();
+
+               assertBitArrayEquals(a.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+               assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
+               assertBitArrayEquals(c.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
+               selectIn.feedSignals(Bit.ZERO, Bit.ONE);
+               t.executeAll();
+
+               assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
+               assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
+               assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ZERO, Bit.ONE, Bit.ZERO);
+
+               selectIn.feedSignals(Bit.ONE, Bit.ONE);
+               t.executeAll();
+
+               assertBitArrayEquals(a.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
+               assertBitArrayEquals(b.getValues(), Bit.U, Bit.U, Bit.U, Bit.U);
+               assertBitArrayEquals(c.getValues(), Bit.Z, Bit.Z, Bit.Z, Bit.Z);
+
+       }
+
+       @Test
+       void andTest()
+       {
+               t.reset();
+               Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);
+               new AndGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
+               a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
+               b.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+
+               t.executeAll();
+
+               assertBitArrayEquals(c.getValues(), Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ZERO);
+       }
+
+       @Test
+       void orTest()
+       {
+               t.reset();
+               Wire a = new Wire(t, 4, 1), b = new Wire(t, 4, 3), c = new Wire(t, 4, 1);
+               new OrGate(t, 1, c.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd());
+               a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ZERO);
+               b.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ZERO, Bit.ONE);
+
+               t.executeAll();
+
+               assertBitArrayEquals(c.getValues(), Bit.ONE, Bit.ONE, Bit.ZERO, Bit.ONE);
+       }
+
+       @Test
+       void xorTest()
+       {
+               t.reset();
+               Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2), c = new Wire(t, 3, 1), d = new Wire(t, 3, 1);
+               new XorGate(t, 1, d.createReadWriteEnd(), a.createReadOnlyEnd(), b.createReadOnlyEnd(), c.createReadOnlyEnd());
+               a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);
+               b.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
+               c.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ZERO, Bit.ONE);
+
+               t.executeAll();
+
+               assertBitArrayEquals(d.getValues(), Bit.ZERO, Bit.ONE, Bit.ONE);
+       }
+
+       @Test
+       void notTest()
+       {
+               t.reset();
+               Wire a = new Wire(t, 3, 1), b = new Wire(t, 3, 2);
+               new NotGate(t, 1, a.createReadOnlyEnd(), b.createReadWriteEnd());
+               a.createReadWriteEnd().feedSignals(Bit.ZERO, Bit.ONE, Bit.ONE);
+
+               t.executeAll();
+
+               assertBitArrayEquals(b.getValues(), Bit.ONE, Bit.ZERO, Bit.ZERO);
+       }
+
+       @Test
+       void rsLatchCircuitTest()
+       {
+               t.reset();
+               Wire r = new Wire(t, 1, 1), s = new Wire(t, 1, 1), t1 = new Wire(t, 1, 15), t2 = new Wire(t, 1, 1), q = new Wire(t, 1, 1),
+                               nq = new Wire(t, 1, 1);
+
+               new OrGate(t, 1, t2.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());
+               new OrGate(t, 1, t1.createReadWriteEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());
+               new NotGate(t, 1, t2.createReadOnlyEnd(), q.createReadWriteEnd());
+               new NotGate(t, 1, t1.createReadOnlyEnd(), nq.createReadWriteEnd());
+
+               ReadWriteEnd sIn = s.createReadWriteEnd(), rIn = r.createReadWriteEnd();
+
+               sIn.feedSignals(Bit.ONE);
+               rIn.feedSignals(Bit.ZERO);
+
+               t.executeAll();
+
+               assertEquals(Bit.ONE, q.getValue());
+               assertEquals(Bit.ZERO, nq.getValue());
+
+               sIn.feedSignals(Bit.ZERO);
+
+               t.executeAll();
+               assertEquals(Bit.ONE, q.getValue());
+               assertEquals(Bit.ZERO, nq.getValue());
+
+               rIn.feedSignals(Bit.ONE);
+
+               t.executeAll();
+
+               assertEquals(Bit.ZERO, q.getValue());
+               assertEquals(Bit.ONE, nq.getValue());
+       }
+
+       @Test
+       void numericValueTest()
+       {
+               t.reset();
+
+               Wire a = new Wire(t, 4, 1);
+               a.createReadWriteEnd().feedSignals(Bit.ONE, Bit.ONE, Bit.ONE, Bit.ONE);
+
+               t.executeAll();
+
+               assertEquals(15, a.getUnsignedValue());
+               assertEquals(-1, a.getSignedValue());
+       }
+
+       boolean flag = false;
+
+       @Test
+       void simpleTimelineTest()
+       {
+               Timeline t = new Timeline(3);
+               flag = false;
+               t.addEvent((e) ->
+               {
+                       if (!flag)
+                               fail();
+                       flag = false;
+               }, 15);
+               t.addEvent((e) ->
+               {
+                       if (flag)
+                               fail();
+                       flag = true;
+               }, 10);
+               t.addEvent((e) ->
+               {
+                       if (flag)
+                               fail();
+                       flag = true;
+               }, 20);
+               t.addEvent((e) ->
+               {
+                       fail("Only supposed to execute until timestamp 20, not 25");
+               }, 25);
+
+               t.executeUntil(t.laterThan(20), 100);
+
+               if (!flag)
+                       fail();
+       }
+
+       @Test
+       void multipleInputs()
+       {
+               t.reset();
+               Wire w = new Wire(t, 2, 1);
+               ReadWriteEnd wI1 = w.createReadWriteEnd(), wI2 = w.createReadWriteEnd();
+               wI1.feedSignals(Bit.ONE, Bit.Z);
+               wI2.feedSignals(Bit.Z, Bit.X);
+               t.executeAll();
+               assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.X);
+
+               wI2.feedSignals(Bit.ZERO, Bit.Z);
+               t.executeAll();
+               assertBitArrayEquals(w.getValues(), Bit.X, Bit.Z);
+
+               wI2.feedSignals(Bit.Z, Bit.Z);
+               t.executeAll();
+               assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);
+
+               wI2.feedSignals(Bit.ONE, Bit.Z);
+               ReadEnd rE = w.createReadOnlyEnd();
+               rE.addObserver((i, oldValues) -> fail("WireEnd notified observer, although value did not change."));
+               t.executeAll();
+               rE.close();
+               wI1.feedSignals(Bit.X, Bit.X);
+               t.executeAll();
+               wI1.addObserver((i, oldValues) -> fail("WireEnd notified observer, although it was closed."));
+               wI1.close();
+               assertBitArrayEquals(w.getValues(), Bit.ONE, Bit.Z);
+       }
+
+       @Test
+       void wireConnections()
+       {
+               // Nur ein Experiment, was Ã¼ber mehrere 'passive' Bausteine hinweg passieren würde
+
+               t.reset();
+
+               Wire a = new Wire(t, 1, 2);
+               Wire b = new Wire(t, 1, 2);
+               Wire c = new Wire(t, 1, 2);
+               ReadWriteEnd aI = a.createReadWriteEnd();
+               ReadWriteEnd bI = b.createReadWriteEnd();
+               ReadWriteEnd cI = c.createReadWriteEnd();
+
+               TestBitDisplay test = new TestBitDisplay(t, c.createReadOnlyEnd());
+               TestBitDisplay test2 = new TestBitDisplay(t, a.createReadOnlyEnd());
+               LongConsumer print = time -> System.out.format("Time %2d\n   a: %s\n   b: %s\n   c: %s\n", time, a, b, c);
+
+               cI.feedSignals(Bit.ONE);
+               test.assertAfterSimulationIs(print, Bit.ONE);
+
+               cI.feedSignals(Bit.X);
+               test.assertAfterSimulationIs(print, Bit.X);
+
+               cI.feedSignals(Bit.X);
+               cI.feedSignals(Bit.Z);
+               test.assertAfterSimulationIs(print, Bit.Z);
+
+               new Connector(t, b.createReadWriteEnd(), c.createReadWriteEnd()).connect();
+               test.assertAfterSimulationIs(print, Bit.Z);
+               System.err.println("ONE");
+               bI.feedSignals(Bit.ONE);
+               test.assertAfterSimulationIs(print, Bit.ONE);
+               System.err.println("ZERO");
+               bI.feedSignals(Bit.ZERO);
+               test.assertAfterSimulationIs(print, Bit.ZERO);
+               System.err.println("Z");
+               bI.feedSignals(Bit.Z);
+               test.assertAfterSimulationIs(print, Bit.Z);
+
+               new Connector(t, a.createReadWriteEnd(), b.createReadWriteEnd()).connect();
+               System.err.println("Z 2");
+               aI.feedSignals(Bit.Z);
+               test.assertAfterSimulationIs(print, Bit.Z);
+               test2.assertAfterSimulationIs(Bit.Z);
+               System.err.println("ONE 2");
+               aI.feedSignals(Bit.ONE);
+               test.assertAfterSimulationIs(print, Bit.ONE);
+               test2.assertAfterSimulationIs(Bit.ONE);
+               System.err.println("ZERO 2");
+               aI.feedSignals(Bit.ZERO);
+               test.assertAfterSimulationIs(print, Bit.ZERO);
+               test2.assertAfterSimulationIs(Bit.ZERO);
+               System.err.println("Z 2 II");
+               aI.feedSignals(Bit.Z);
+               test.assertAfterSimulationIs(print, Bit.Z);
+               test2.assertAfterSimulationIs(Bit.Z);
+
+               System.err.println("No Conflict yet");
+               bI.feedSignals(Bit.ONE);
+               test.assertAfterSimulationIs(print, Bit.ONE);
+               test2.assertAfterSimulationIs(Bit.ONE);
+               aI.feedSignals(Bit.ONE);
+               test.assertAfterSimulationIs(print, Bit.ONE);
+               test2.assertAfterSimulationIs(Bit.ONE);
+               System.err.println("Conflict");
+               aI.feedSignals(Bit.ZERO);
+               test.assertAfterSimulationIs(print, Bit.X);
+               test2.assertAfterSimulationIs(Bit.X);
+               aI.feedSignals(Bit.ONE);
+               test.assertAfterSimulationIs(print, Bit.ONE);
+               test2.assertAfterSimulationIs(Bit.ONE);
+       }
+
+       private static void assertBitArrayEquals(BitVector actual, Bit... expected)
+       {
+               assertArrayEquals(expected, actual.getBits());
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/tests/GUITest.java b/era.mi/src/mograsim/logic/core/tests/GUITest.java
new file mode 100644 (file)
index 0000000..0a0929c
--- /dev/null
@@ -0,0 +1,301 @@
+package mograsim.logic.core.tests;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.WindowConstants;
+
+import mograsim.logic.core.components.ManualSwitch;
+import mograsim.logic.core.components.gates.NotGate;
+import mograsim.logic.core.components.gates.OrGate;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.timeline.Timeline.ExecutionResult;
+import mograsim.logic.core.wires.Wire;
+
+public class GUITest extends JPanel
+{
+
+       private static final long serialVersionUID = 1L;
+
+       private static final int WIRE_DELAY = 40;
+       private static final int OR_DELAY = 100;
+       private static final int NOT_DELAY = 100;
+
+       private Timeline t = new Timeline(11);
+
+       Wire r = new Wire(t, 1, WIRE_DELAY);
+       Wire s = new Wire(t, 1, WIRE_DELAY);
+       Wire t1 = new Wire(t, 1, WIRE_DELAY);
+       Wire t2 = new Wire(t, 1, WIRE_DELAY);
+       Wire q = new Wire(t, 1, WIRE_DELAY);
+       Wire nq = new Wire(t, 1, WIRE_DELAY);
+
+       ManualSwitch rIn = new ManualSwitch(t, r.createReadWriteEnd());
+       ManualSwitch sIn = new ManualSwitch(t, s.createReadWriteEnd());
+
+       OrGate or1 = new OrGate(t, OR_DELAY, t2.createReadWriteEnd(), r.createReadOnlyEnd(), nq.createReadOnlyEnd());
+       OrGate or2 = new OrGate(t, OR_DELAY, t1.createReadWriteEnd(), s.createReadOnlyEnd(), q.createReadOnlyEnd());
+       NotGate not1 = new NotGate(t, NOT_DELAY, t2.createReadOnlyEnd(), q.createReadWriteEnd());
+       NotGate not2 = new NotGate(t, NOT_DELAY, t1.createReadOnlyEnd(), nq.createReadWriteEnd());
+
+       Map<ManualSwitch, Rectangle> switchMap = new HashMap<>();
+
+       int height;
+       int width;
+       boolean sizeChanged;
+
+       public GUITest()
+       {
+               addMouseListener(new MouseListener()
+               {
+
+                       @Override
+                       public void mouseReleased(MouseEvent e)
+                       {
+                               for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())
+                               {
+                                       if (dim.getValue().contains(e.getPoint()))
+                                       {
+                                               dim.getKey().switchOff();
+                                               repaint();
+                                       }
+                               }
+                       }
+
+                       @Override
+                       public void mousePressed(MouseEvent e)
+                       {
+                               for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet())
+                               {
+                                       if (dim.getValue().contains(e.getPoint()))
+                                       {
+                                               dim.getKey().switchOn();
+                                               repaint();
+                                       }
+                               }
+                       }
+
+                       @Override
+                       public void mouseExited(MouseEvent e)
+                       {
+                               // none
+                       }
+
+                       @Override
+                       public void mouseEntered(MouseEvent e)
+                       {
+                               // none
+                       }
+
+                       @Override
+                       public void mouseClicked(MouseEvent e)
+                       {
+                               // If you want toggle buttons, use this code instead
+//                             for (Entry<ManualSwitch, Rectangle> dim : switchMap.entrySet()) {
+//                                     if (dim.getValue().contains(e.getPoint())) {
+//                                             dim.getKey().toggle();
+//                                             repaint();
+//                                     }
+//                             }
+                       }
+               });
+       }
+
+       public Timeline getTimeline()
+       {
+               return t;
+       };
+
+       @Override
+       public void paint(Graphics some_g)
+       {
+               super.paint(some_g);
+               Graphics2D g = ((Graphics2D) some_g);
+               g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+               g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+
+               checkSizeChange();
+               adaptFont(g);
+
+               drawWire(g, r, "r", 2, 9, 4, 9);
+
+               drawWire(g, s, "s", 2, 3, 4, 3);
+
+               drawWire(g, t2, "t2", 5, 8.5, 6, 8.5);
+
+               drawWire(g, t1, "t1", 5, 3.5, 6, 3.5);
+
+               drawWire(g, q, "q", 7, 8.5, 9, 8.5);
+
+               drawWire(g, nq, "nq", 7, 3.5, 9, 3.5);
+
+               drawWire(g, q, "", 7.5, 8.5, 7.5, 7.5);
+               drawWire(g, q, "", 7.5, 7.5, 3, 4.5);
+               drawWire(g, q, "", 3, 4.5, 3, 4);
+               drawWire(g, q, "q", 3, 4, 4, 4);
+
+               drawWire(g, nq, "", 7.5, 3.5, 7.5, 4.5);
+               drawWire(g, nq, "", 7.5, 4.5, 3, 7.5);
+               drawWire(g, nq, "", 3, 7.5, 3, 8);
+               drawWire(g, nq, "nq", 3, 8, 4, 8);
+
+               drawSquare(g, 4, 8, "OR");
+               drawSquare(g, 4, 3, "OR");
+
+               drawSquare(g, 6, 8, "NOT");
+               drawSquare(g, 6, 3, "NOT");
+
+               drawSwitch(g, rIn, "Switch R", 0.5, 8.25, 2, 9.75);
+               drawSwitch(g, sIn, "Switch S", 0.5, 2.25, 2, 3.75);
+
+               drawString(g, "Hint: drag the cursor out of the pressed switch to keep it's state", 5, 0, 0.0, 1.0);
+       }
+
+       private void checkSizeChange()
+       {
+               sizeChanged = height != getHeight() || width != getWidth();
+               if (sizeChanged)
+               {
+                       height = getHeight();
+                       width = getWidth();
+               }
+       }
+
+       private void adaptFont(Graphics g)
+       {
+               g.setFont(g.getFont().deriveFont(Math.min(height, width) / 40f));
+       }
+
+       private void drawString(Graphics g, String s, int x, int y, double anchorX, double anchorY)
+       {
+               int h = g.getFontMetrics().getAscent();
+               int w = g.getFontMetrics().stringWidth(s);
+               g.drawString(s, x - (int) (w * anchorX), y + (int) (h * anchorY));
+       }
+
+       private void drawWire(Graphics g, Wire wa, String name, double x1, double y1, double x2, double y2)
+       {
+               setTo(g, wa);
+               g.drawLine(gX(x1), gY(y1), gX(x2), gY(y2));
+               drawString(g, name, (gX(x1) + gX(x2)) / 2, (gY(y1) + gY(y2)) / 2 - 5, 0, 0);
+       }
+
+       private void drawSquare(Graphics g, int posX, int posY, String text)
+       {
+               int x1 = gX(posX) - 5;
+               int x2 = gX(posX + 1) + 5;
+               int y1 = gY(posY) - 5;
+               int y2 = gY(posY + 1) + 5;
+
+               g.setColor(Color.WHITE);
+               g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+               setBlack(g);
+               g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+               drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);
+
+       }
+
+       private void drawSwitch(Graphics g, ManualSwitch ms, String text, double posX1, double posY1, double posX2, double posY2)
+       {
+               int x1 = gX(posX1) - 5;
+               int x2 = gX(posX2) + 5;
+               int y1 = gY(posY1) - 5;
+               int y2 = gY(posY2) + 5;
+
+               if (sizeChanged)
+               {
+                       Rectangle r = new Rectangle(x1, y1, x2 - x1, y2 - y1);
+                       switchMap.put(ms, r);
+               }
+
+               g.setColor(ms.isOn() ? Color.getHSBColor(.3f, .5f, 1f) : Color.WHITE);
+               g.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+               setBlack(g);
+               g.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+               drawString(g, text, (x1 + x2) / 2, (y1 + y2) / 2, 0.5, 0.5);
+       }
+
+       private static void setBlack(Graphics g)
+       {
+               g.setColor(Color.BLACK);
+       }
+
+       private static void setTo(Graphics g, Wire wa)
+       {
+               switch (wa.getValue())
+               {
+               case ONE:
+                       g.setColor(Color.GREEN);
+                       break;
+               case X:
+                       g.setColor(Color.RED);
+                       break;
+               case Z:
+                       g.setColor(Color.DARK_GRAY);
+                       break;
+               case ZERO:
+                       g.setColor(Color.BLACK);
+                       break;
+               case U:
+                       g.setColor(Color.MAGENTA);
+                       break;
+               default:
+                       throw new IllegalArgumentException();
+               }
+       }
+
+       private int gY(double pos)
+       {
+               return (int) (pos * height / 11);
+       }
+
+       private int gX(double pos)
+       {
+               return (int) (pos * width / 11) + 50;
+       }
+
+       public static void main(String[] args)
+       {
+               JFrame f = new JFrame("Test circuit 1.0.0");
+               GUITest gt = new GUITest();
+               f.add(gt);
+               f.setSize(800, 600);
+               f.setLocation(500, 400);
+               f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+               f.setVisible(true);
+
+               long begin = System.currentTimeMillis();
+
+               long lastFrame = begin;
+               long updateT = 16;
+
+               while (f.isVisible())
+               {
+                       ExecutionResult er = gt.getTimeline().executeUntil(gt.getTimeline().laterThan((lastFrame - begin) * 3), lastFrame + 14);
+//                             if (t.hasNext()) 
+//                             t.executeNext();
+                       if (er != ExecutionResult.NOTHING_DONE)
+                               gt.repaint(12);
+                       try
+                       {
+                               Thread.sleep(Math.max(updateT - System.currentTimeMillis() + lastFrame, 0));
+                       }
+                       catch (Exception e)
+                       {
+                               e.printStackTrace();
+                       }
+                       lastFrame = System.currentTimeMillis();
+               }
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/tests/TestBitDisplay.java b/era.mi/src/mograsim/logic/core/tests/TestBitDisplay.java
new file mode 100644 (file)
index 0000000..80eef5f
--- /dev/null
@@ -0,0 +1,47 @@
+package mograsim.logic.core.tests;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import java.util.function.LongConsumer;
+
+import mograsim.logic.core.components.BitDisplay;
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.Bit;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+
+public final class TestBitDisplay extends BitDisplay
+{
+
+       public TestBitDisplay(Timeline timeline, ReadEnd in)
+       {
+               super(timeline, in);
+       }
+
+       public void assertDisplays(Bit... expected)
+       {
+               assertArrayEquals(expected, getDisplayedValue().getBits());
+       }
+
+       public void assertAfterSimulationIs(Bit... expected)
+       {
+               timeline.executeAll();
+               assertDisplays(expected);
+       }
+
+       public void assertAfterSimulationIs(LongConsumer r, Bit... expected)
+       {
+               while (timeline.hasNext())
+               {
+                       timeline.executeNext();
+                       r.accept(timeline.getSimulationTime());
+               }
+               assertDisplays(expected);
+       }
+
+       @Override
+       protected void compute()
+       {
+               super.compute();
+               System.out.println("update: value is " + getDisplayedValue());
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/timeline/Timeline.java b/era.mi/src/mograsim/logic/core/timeline/Timeline.java
new file mode 100644 (file)
index 0000000..1a380b4
--- /dev/null
@@ -0,0 +1,203 @@
+package mograsim.logic.core.timeline;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.PriorityQueue;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.LongSupplier;
+
+/**
+ * Orders Events by the time they are due to be executed. Can execute Events individually.
+ * 
+ * @author Fabian Stemmler
+ *
+ */
+public class Timeline
+{
+       private PriorityQueue<InnerEvent> events;
+       private LongSupplier time;
+       private long lastTimeUpdated = 0;
+
+       private final List<Consumer<TimelineEvent>> eventAddedListener;
+
+       public Timeline(int initCapacity)
+       {
+               events = new PriorityQueue<InnerEvent>(initCapacity);
+
+               eventAddedListener = new ArrayList<>();
+               time = () -> lastTimeUpdated;
+       }
+
+       /**
+        * @param timestamp exclusive
+        * @return true if the first event is later than the timestamp
+        */
+       public BooleanSupplier laterThan(long timestamp)
+       {
+               return () -> timeCmp(events.peek().getTiming(), timestamp) > 0;
+       }
+
+       public boolean hasNext()
+       {
+               return !events.isEmpty();
+       }
+
+       /**
+        * Executes all events at the next timestamp, at which there are any
+        */
+       public void executeNext()
+       {
+               InnerEvent first = events.peek();
+               if (first != null)
+                       executeUntil(laterThan(first.getTiming()), -1);
+       }
+
+       public void executeAll()
+       {
+               while (hasNext())
+                       executeNext();
+       }
+
+       /**
+        * Executes all events until a given condition is met. The simulation process can be constrained by a real world timestamp.
+        * 
+        * @param condition  the condition until which the events are be processed
+        * @param stopMillis the System.currentTimeMillis() when simulation definitely needs to stop. A value of -1 means no timeout.
+        * @return State of the event execution
+        * @formatter:off
+        * <code>NOTHING_DONE</code> if the {@link Timeline} was already empty
+        * <code>EXEC_OUT_OF_TIME</code> if the given maximum time was reached
+        * <code>EXEC_UNTIL_CONDITION</code> if the condition was met
+        * <code>EXEC_UNTIL_EMPTY</code> if events were executed until the {@link Timeline} was empty
+        * @formatter:on
+        * @author Christian Femers, Fabian Stemmler
+        */
+       public ExecutionResult executeUntil(BooleanSupplier condition, long stopMillis)
+       {
+               if (events.isEmpty())
+               {
+                       lastTimeUpdated = getSimulationTime();
+                       return ExecutionResult.NOTHING_DONE;
+               }
+               int checkStop = 0;
+               InnerEvent first = events.peek();
+               while (hasNext() && !condition.getAsBoolean())
+               {
+                       events.remove();
+                       lastTimeUpdated = first.getTiming();
+                       first.run();
+                       // Don't check after every run
+                       checkStop = (checkStop + 1) % 10;
+                       if (checkStop == 0 && System.currentTimeMillis() >= stopMillis)
+                               return ExecutionResult.EXEC_OUT_OF_TIME;
+                       first = events.peek();
+               }
+               lastTimeUpdated = getSimulationTime();
+               return hasNext() ? ExecutionResult.EXEC_UNTIL_EMPTY : ExecutionResult.EXEC_UNTIL_CONDITION;
+       }
+
+       public void setTimeFunction(LongSupplier time)
+       {
+               this.time = time;
+       }
+
+       public long getSimulationTime()
+       {
+               return time.getAsLong();
+       }
+
+       public long nextEventTime()
+       {
+               if (!hasNext())
+                       return -1;
+               return events.peek().getTiming();
+       }
+
+       public void reset()
+       {
+               events.clear();
+               lastTimeUpdated = 0;
+       }
+
+       public void addEventAddedListener(Consumer<TimelineEvent> listener)
+       {
+               eventAddedListener.add(listener);
+       }
+
+       public void removeEventAddedListener(Consumer<TimelineEvent> listener)
+       {
+               eventAddedListener.remove(listener);
+       }
+
+       /**
+        * Adds an Event to the {@link Timeline}
+        * 
+        * @param function       The {@link TimelineEventHandler} that will be executed, when the {@link InnerEvent} occurs on the timeline.
+        * @param relativeTiming The amount of MI ticks in which the {@link InnerEvent} is called, starting from the current time.
+        */
+       public void addEvent(TimelineEventHandler function, int relativeTiming)
+       {
+               long timing = getSimulationTime() + relativeTiming;
+               TimelineEvent event = new TimelineEvent(timing);
+               events.add(new InnerEvent(function, event));
+               eventAddedListener.forEach(l -> l.accept(event));
+       }
+
+       private class InnerEvent implements Runnable, Comparable<InnerEvent>
+       {
+               private final TimelineEventHandler function;
+               private final TimelineEvent event;
+
+               /**
+                * Creates an {@link InnerEvent}
+                * 
+                * @param function {@link TimelineEventHandler} to be executed when the {@link InnerEvent} occurs
+                * @param timing   Point in the MI simulation {@link Timeline}, at which the {@link InnerEvent} is executed;
+                */
+               InnerEvent(TimelineEventHandler function, TimelineEvent event)
+               {
+                       this.function = function;
+                       this.event = event;
+               }
+
+               public long getTiming()
+               {
+                       return event.getTiming();
+               }
+
+               @Override
+               public void run()
+               {
+                       function.handle(event);
+               }
+
+               @Override
+               public String toString()
+               {
+                       return event.toString();
+               }
+
+               @Override
+               public int compareTo(InnerEvent o)
+               {
+                       return timeCmp(getTiming(), o.getTiming());
+               }
+       }
+
+       public static int timeCmp(long a, long b)
+       {
+               return Long.signum(a - b);
+       }
+
+       @Override
+       public String toString()
+       {
+               return String.format("Simulation time: %s, Last update: %d, Events: %s", getSimulationTime(), lastTimeUpdated, events.toString());
+       }
+
+       public enum ExecutionResult
+       {
+               NOTHING_DONE, EXEC_UNTIL_EMPTY, EXEC_UNTIL_CONDITION, EXEC_OUT_OF_TIME
+       }
+}
\ No newline at end of file
diff --git a/era.mi/src/mograsim/logic/core/timeline/TimelineEvent.java b/era.mi/src/mograsim/logic/core/timeline/TimelineEvent.java
new file mode 100644 (file)
index 0000000..6372bde
--- /dev/null
@@ -0,0 +1,30 @@
+package mograsim.logic.core.timeline;
+
+/**
+ * A class that stores all relevant information about an event in the {@link Timeline}. Currently, there is not much relevant information to
+ * store.
+ * 
+ * @author Fabian Stemmler
+ *
+ */
+public class TimelineEvent
+{
+       private final long timing;
+
+       TimelineEvent(long timing)
+       {
+               super();
+               this.timing = timing;
+       }
+
+       public long getTiming()
+       {
+               return timing;
+       }
+
+       @Override
+       public String toString()
+       {
+               return "timestamp: " + timing;
+       }
+}
\ No newline at end of file
diff --git a/era.mi/src/mograsim/logic/core/timeline/TimelineEventHandler.java b/era.mi/src/mograsim/logic/core/timeline/TimelineEventHandler.java
new file mode 100644 (file)
index 0000000..dd58c0b
--- /dev/null
@@ -0,0 +1,7 @@
+package mograsim.logic.core.timeline;
+
+@FunctionalInterface
+public interface TimelineEventHandler
+{
+       public void handle(TimelineEvent e);
+}
\ No newline at end of file
diff --git a/era.mi/src/mograsim/logic/core/types/Bit.java b/era.mi/src/mograsim/logic/core/types/Bit.java
new file mode 100644 (file)
index 0000000..60c4e19
--- /dev/null
@@ -0,0 +1,132 @@
+package mograsim.logic.core.types;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * stdlogic according to IEEE 1164
+ */
+public enum Bit implements StrictLogicType<Bit>
+{
+       U("U"), X("X"), ZERO("0"), ONE("1"), Z("Z");
+
+       private final String symbol;
+
+       private Bit(String symbol)
+       {
+               this.symbol = symbol;
+       }
+
+       @Override
+       public Bit and(Bit other)
+       {
+               return fromTable(AND_TABLE, this, other);
+       }
+
+       @Override
+       public Bit or(Bit other)
+       {
+               return fromTable(OR_TABLE, this, other);
+       }
+
+       @Override
+       public Bit xor(Bit other)
+       {
+               return fromTable(XOR_TABLE, this, other);
+       }
+
+       @Override
+       public Bit not()
+       {
+               switch (this)
+               {
+               case U:
+                       return U;
+               case ONE:
+                       return ZERO;
+               case ZERO:
+                       return ONE;
+               default:
+                       return X;
+               }
+       }
+
+       public Bit[] makeArray(int length)
+       {
+               Bit[] bits = new Bit[length];
+               Arrays.fill(bits, this);
+               return bits;
+       }
+
+       public BitVector toVector(int length)
+       {
+               return BitVector.of(this, length);
+       }
+
+       @Override
+       public Bit join(Bit other)
+       {
+               return fromTable(JOIN_TABLE, this, other);
+       }
+
+       @Override
+       public String toString()
+       {
+               return getSymbol();
+       }
+
+       public String getSymbol()
+       {
+               return symbol;
+       }
+
+       public static Bit parse(String s)
+       {
+               Bit bit = SYMBOL_MAP.get(s);
+               Objects.requireNonNull(bit, "No Bit found for symbol " + s);
+               return bit;
+       }
+
+       public static Bit parse(String s, int symbolPosition)
+       {
+               return parse(s.substring(symbolPosition, symbolPosition + 1));
+       }
+
+       private static Bit fromTable(Bit[][] table, Bit a, Bit b)
+       {
+               return table[a.ordinal()][b.ordinal()];
+       }
+
+       static final Map<String, Bit> SYMBOL_MAP = Map.of(U.symbol, U, X.symbol, X, ZERO.symbol, ZERO, ONE.symbol, ONE, Z.symbol, Z);
+
+       // @formatter:off
+       private static final Bit[][] JOIN_TABLE = 
+               { { U, U, U,    U,   U    }, 
+                 { U, X, X,    X,   X    }, 
+                 { U, X, ZERO, X,   ZERO },
+                 { U, X, X,    ONE, ONE  }, 
+                 { U, X, ZERO, ONE, Z    } };
+
+       private static final Bit[][] AND_TABLE = 
+               { { U,    U,    ZERO, U,    U    }, 
+                 { U,    X,    ZERO, X,    X    },
+                 { ZERO, ZERO, ZERO, ZERO, ZERO }, 
+                 { U,    X,    ZERO, ONE,  X    }, 
+                 { U,    X,    ZERO, X,    X    } };
+
+       private static final Bit[][] OR_TABLE =
+       { { U,   U,   U,    ONE, U    },    
+         { U,   X,   X,    ONE, X    },    
+         { U,   X,   ZERO, ONE, X    },    
+         { ONE, ONE, ONE,  ONE, ONE  },    
+         { U,   X,   X,    ONE, X    } };
+       
+       private static final Bit[][] XOR_TABLE =
+       { { U, U, U,    U,    U },    
+         { U, X, X,    X,    X },    
+         { U, X, ZERO, ONE,  X },    
+         { U, X, ONE,  ZERO, X },    
+         { U, X, X,    X,    X } }; 
+       // @formatter:on
+}
\ No newline at end of file
diff --git a/era.mi/src/mograsim/logic/core/types/BitVector.java b/era.mi/src/mograsim/logic/core/types/BitVector.java
new file mode 100644 (file)
index 0000000..2d28b2c
--- /dev/null
@@ -0,0 +1,316 @@
+package mograsim.logic.core.types;
+
+import static java.lang.String.format;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.RandomAccess;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * Immutable class representing a {@link Bit}Vector
+ *
+ *
+ * @author Christian Femers
+ *
+ */
+public final class BitVector implements StrictLogicType<BitVector>, Iterable<Bit>, RandomAccess
+{
+       private final Bit[] bits;
+
+       private BitVector(Bit[] bits)
+       {
+               this.bits = Objects.requireNonNull(bits);
+       }
+
+       public static BitVector of(Bit... bits)
+       {
+               return new BitVector(bits.clone());
+       }
+
+       public static BitVector of(Bit bit, int length)
+       {
+               return new BitVector(bit.makeArray(length));
+       }
+
+       public BitVectorMutator mutator()
+       {
+               return BitVectorMutator.of(this);
+       }
+
+       public Bit getBit(int bitIndex)
+       {
+               return bits[bitIndex];
+       }
+
+       public Bit[] getBits()
+       {
+               return bits.clone();
+       }
+
+       @Override
+       public BitVector join(BitVector t)
+       {
+               checkCompatibility(t);
+               return new BitVector(binOp(bits.clone(), t.bits, Bit::join));
+       }
+
+       @Override
+       public BitVector and(BitVector t)
+       {
+               checkCompatibility(t);
+               return new BitVector(binOp(bits.clone(), t.bits, Bit::and));
+       }
+
+       @Override
+       public BitVector or(BitVector t)
+       {
+               checkCompatibility(t);
+               return new BitVector(binOp(bits.clone(), t.bits, Bit::or));
+       }
+
+       @Override
+       public BitVector xor(BitVector t)
+       {
+               checkCompatibility(t);
+               return new BitVector(binOp(bits.clone(), t.bits, Bit::xor));
+       }
+
+       @Override
+       public BitVector not()
+       {
+               return new BitVector(unOp(bits.clone(), Bit::not));
+       }
+
+       public int length()
+       {
+               return bits.length;
+       }
+
+       public BitVector concat(BitVector other)
+       {
+               Bit[] newBits = Arrays.copyOf(bits, length() + other.length());
+               System.arraycopy(other.bits, 0, newBits, length(), other.length());
+               return new BitVector(newBits);
+       }
+
+       public BitVector subVector(int start)
+       {
+               return new BitVector(Arrays.copyOfRange(bits, start, length()));
+       }
+
+       public BitVector subVector(int start, int end)
+       {
+               return new BitVector(Arrays.copyOfRange(bits, start, end));
+       }
+
+       private void checkCompatibility(BitVector bv)
+       {
+               if (length() != bv.length())
+                       throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", length(), bv.length()));
+       }
+
+       static Bit[] binOp(Bit[] dest, Bit[] second, BinaryOperator<Bit> op)
+       {
+               if (dest == null)
+                       return second.clone();
+               for (int i = 0; i < dest.length; i++)
+               {
+                       dest[i] = op.apply(dest[i], second[i]);
+               }
+               return dest;
+       }
+
+       static Bit[] unOp(Bit[] dest, UnaryOperator<Bit> op)
+       {
+               if (dest == null)
+                       return null;
+               for (int i = 0; i < dest.length; i++)
+               {
+                       dest[i] = op.apply(dest[i]);
+               }
+               return dest;
+       }
+
+       /**
+        * Class for comfortable and efficient manipulation of {@link BitVector}s, similar to {@link StringBuilder}
+        *
+        * @author Christian Femers
+        */
+       @SuppressWarnings("synthetic-access")
+       public static final class BitVectorMutator implements LogicType<BitVectorMutator, BitVector>
+       {
+               private Bit[] bits;
+
+               private BitVectorMutator(Bit[] bits)
+               {
+                       this.bits = bits;
+               }
+
+               static BitVectorMutator of(BitVector bv)
+               {
+                       return new BitVectorMutator(bv.getBits());
+               }
+
+               /**
+                * Returns an empty mutator which has no bits set and will simply copy the values from the first binary operation performed.
+                * 
+                */
+               public static BitVectorMutator empty()
+               {
+                       return new BitVectorMutator(null);
+               }
+
+               /**
+                * Produces the resulting, immutable {@link BitVector}<br>
+                * 
+                * @throws IllegalStateException if the mutator is (still) empty
+                */
+               public BitVector get()
+               {
+                       if (bits == null)
+                               throw new IllegalStateException("cannot create a BitVector from an empty mutator");
+                       return new BitVector(bits);
+               }
+
+               @Override
+               public BitVectorMutator join(BitVector t)
+               {
+                       checkCompatibility(t);
+                       bits = binOp(bits, t.bits, Bit::join);
+                       return this;
+               }
+
+               @Override
+               public BitVectorMutator and(BitVector t)
+               {
+                       checkCompatibility(t);
+                       bits = binOp(bits, t.bits, Bit::and);
+                       return this;
+               }
+
+               @Override
+               public BitVectorMutator or(BitVector t)
+               {
+                       checkCompatibility(t);
+                       bits = binOp(bits, t.bits, Bit::or);
+                       return this;
+               }
+
+               @Override
+               public BitVectorMutator xor(BitVector t)
+               {
+                       checkCompatibility(t);
+                       bits = binOp(bits, t.bits, Bit::xor);
+                       return this;
+               }
+
+               @Override
+               public BitVectorMutator not()
+               {
+                       unOp(bits, Bit::not);
+                       return this;
+               }
+
+               private void checkCompatibility(BitVector bv)
+               {
+                       if (bits != null && bits.length != bv.length())
+                               throw new IllegalArgumentException(format("BitVector length does not match: %d and %d", bits.length, bv.length()));
+               }
+       }
+
+       /**
+        * @see Arrays#hashCode(Object[])
+        */
+       @Override
+       public int hashCode()
+       {
+               return Arrays.hashCode(bits);
+       }
+
+       /**
+        * Does test for equality of values/content
+        * 
+        * @see Object#equals(Object)
+        */
+       @Override
+       public boolean equals(Object obj)
+       {
+               if (this == obj)
+                       return true;
+               if (!(obj instanceof BitVector))
+                       return false;
+               BitVector other = (BitVector) obj;
+               return Arrays.equals(bits, other.bits);
+       }
+
+       /**
+        * Does test for equality of values/content, shifting the other BitVector by <code>offset</code> to the right.<br>
+        * Therefore <code>offset + other.length() <= this.length()</code> needs to be true.
+        * 
+        * @throws ArrayIndexOutOfBoundsException if <code>offset + other.length() > this.length()</code>
+        * 
+        * @see Object#equals(Object)
+        */
+       public boolean equalsWithOffset(BitVector other, int offset)
+       {
+               if (other == null)
+                       return false;
+               return Arrays.equals(bits, offset, offset + other.length(), other.bits, 0, other.length());
+       }
+
+       /**
+        * All {@link Bit}s symbols concatenated together
+        * 
+        * @see #parse(String)
+        */
+       @Override
+       public String toString()
+       {
+               StringBuilder sb = new StringBuilder(bits.length);
+               for (Bit bit : bits)
+                       sb.append(bit);
+               return sb.toString();
+       }
+
+       /**
+        * Parses a String containing solely {@link Bit} symbols
+        * 
+        * @see #toString()
+        */
+       public static BitVector parse(String s)
+       {
+               Bit[] values = new Bit[s.length()];
+               for (int i = 0; i < s.length(); i++)
+               {
+                       values[i] = Bit.parse(s, i);
+               }
+               return new BitVector(values);
+       }
+
+       @Override
+       public Iterator<Bit> iterator()
+       {
+               return new Iterator<>()
+               {
+                       private int pos = 0;
+
+                       @Override
+                       public Bit next()
+                       {
+                               if (!hasNext())
+                                       throw new NoSuchElementException();
+                               return getBit(pos++);
+                       }
+
+                       @Override
+                       public boolean hasNext()
+                       {
+                               return pos != length();
+                       }
+               };
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/types/BitVectorFormatter.java b/era.mi/src/mograsim/logic/core/types/BitVectorFormatter.java
new file mode 100644 (file)
index 0000000..9a61c11
--- /dev/null
@@ -0,0 +1,53 @@
+package mograsim.logic.core.types;
+
+import mograsim.logic.core.types.ColorDefinition.BuiltInColor;
+import mograsim.logic.core.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/mograsim/logic/core/types/ColorDefinition.java b/era.mi/src/mograsim/logic/core/types/ColorDefinition.java
new file mode 100644 (file)
index 0000000..7d69837
--- /dev/null
@@ -0,0 +1,54 @@
+package mograsim.logic.core.types;
+
+/**
+ * A way to define a color with the possibility to use colors built into the system (called "system colors" in SWT).
+ * <p>
+ * A {@link ColorDefinition} is defined either by a {@link BuiltInColor} constant, in which case <code>r==g==b==-1</code>, or by red / green
+ * / blue components, in which case <code>builtInColor==null</code>
+ */
+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
diff --git a/era.mi/src/mograsim/logic/core/types/LogicType.java b/era.mi/src/mograsim/logic/core/types/LogicType.java
new file mode 100644 (file)
index 0000000..b4e4efb
--- /dev/null
@@ -0,0 +1,130 @@
+package mograsim.logic.core.types;
+
+/**
+ * Interface for types that support the basic logic operations
+ *
+ * @author Christian Femers
+ *
+ * @param <T> the logic type itself, to make the operations closed in T
+ * @param <S> the operand type, may be the same as T, see {@link StrictLogicType}
+ */
+public interface LogicType<T extends LogicType<T, S>, S>
+{
+       /**
+        * Determines the result when two signals meet each other directly, also called resolution (IEEE 1164)
+        * 
+        * For example:
+        * 
+        * <pre>
+        * 0 joined 0 == 0
+        * 1 joined 0 == X
+        * 0 joined 1 == X
+        * 1 joined 1 == 1
+        * </pre>
+        * 
+        * @param t the second logic signal
+        * @return the resulting value
+        * @author Christian Femers
+        */
+       T join(S t);
+
+       /**
+        * Classical logic AND
+        * 
+        * For example:
+        * 
+        * <pre>
+        * 0 AND 0 == 0
+        * 1 AND 0 == 0
+        * 0 AND 1 == 0
+        * 1 AND 1 == 1
+        * </pre>
+        * 
+        * @param t the second logic signal
+        * @return the resulting value
+        * @author Christian Femers
+        */
+       T and(S t);
+
+       /**
+        * Classical logic OR
+        *
+        * For example:
+        * 
+        * <pre>
+        * 0 OR 0 == 0
+        * 1 OR 0 == 1
+        * 0 OR 1 == 1
+        * 1 OR 1 == 1
+        * </pre>
+        * 
+        * @param t the second logic signal
+        * @return the resulting value
+        * @author Christian Femers
+        */
+       T or(S t);
+
+       /**
+        * Classical logic XOR (exclusive OR)
+        * 
+        * For example:
+        * 
+        * <pre>
+        * 0 XOR 0 == 0
+        * 1 XOR 0 == 1
+        * 0 XOR 1 == 1
+        * 1 XOR 1 == 0
+        * </pre>
+        * 
+        * @param t the second logic signal
+        * @return the resulting value
+        * @author Christian Femers
+        */
+       T xor(S t);
+
+       /**
+        * Classical logic NOT (logical negation)
+        * 
+        * For example:
+        * 
+        * <pre>
+        * NOT 0 == 1
+        * NOT 1 == 0
+        * </pre>
+        * 
+        * @return the resulting value
+        * @author Christian Femers
+        */
+       T not();
+
+       /**
+        * {@link #and(Object) AND} and then {@link #not() NOT}
+        * 
+        * @author Christian Femers
+        */
+       default T nand(S t)
+       {
+               return and(t).not();
+       }
+
+       /**
+        * {@link #or(Object) OR} and then {@link #not() NOT}
+        * 
+        * @author Christian Femers
+        */
+       default T nor(S t)
+       {
+               return or(t).not();
+       }
+
+       /**
+        * {@link #xor(Object) XOR} and then {@link #not() NOT}<br>
+        * Used to determine equality (alias parity, consistency)
+        * 
+        * @author Christian Femers
+        */
+       default T xnor(S t)
+       {
+               return xor(t).not();
+       }
+}
diff --git a/era.mi/src/mograsim/logic/core/types/MutationOperation.java b/era.mi/src/mograsim/logic/core/types/MutationOperation.java
new file mode 100644 (file)
index 0000000..998e597
--- /dev/null
@@ -0,0 +1,11 @@
+package mograsim.logic.core.types;
+
+import java.util.function.BiFunction;
+
+import mograsim.logic.core.types.BitVector.BitVectorMutator;
+
+@FunctionalInterface
+public interface MutationOperation extends BiFunction<BitVectorMutator, BitVector, BitVectorMutator>
+{
+       // no changes necessary, only for convenience and readability
+}
diff --git a/era.mi/src/mograsim/logic/core/types/StrictLogicType.java b/era.mi/src/mograsim/logic/core/types/StrictLogicType.java
new file mode 100644 (file)
index 0000000..91cb10f
--- /dev/null
@@ -0,0 +1,14 @@
+package mograsim.logic.core.types;
+
+/**
+ * Interface for types that support the basic logic operations only among themselves, making it mathematically closed
+ * 
+ * @author Christian Femers
+ * @see LogicType
+ *
+ * @param <T> the logic type itself to make the operations closed
+ */
+public interface StrictLogicType<T extends StrictLogicType<T>> extends LogicType<T, T>
+{
+       // this is just a matter of type parameters
+}
diff --git a/era.mi/src/mograsim/logic/core/wires/Wire.java b/era.mi/src/mograsim/logic/core/wires/Wire.java
new file mode 100644 (file)
index 0000000..746e926
--- /dev/null
@@ -0,0 +1,492 @@
+package mograsim.logic.core.wires;
+
+import static mograsim.logic.core.types.Bit.U;
+import static mograsim.logic.core.types.Bit.Z;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import mograsim.logic.core.timeline.Timeline;
+import mograsim.logic.core.types.Bit;
+import mograsim.logic.core.types.BitVector;
+import mograsim.logic.core.types.BitVector.BitVectorMutator;
+
+/**
+ * Represents an array of wires that can store n bits of information.
+ * 
+ * @author Fabian Stemmler
+ *
+ */
+public class Wire
+{
+       private BitVector values;
+       public final int travelTime;
+       private List<ReadEnd> attached = new ArrayList<ReadEnd>();
+       public final int length;
+       private List<ReadWriteEnd> inputs = new ArrayList<ReadWriteEnd>();
+       private Timeline timeline;
+
+       public Wire(Timeline timeline, int length, int travelTime)
+       {
+               if (length < 1)
+                       throw new IllegalArgumentException(
+                                       String.format("Tried to create an array of wires with length %d, but a length of less than 1 makes no sense.", length));
+               this.timeline = timeline;
+               this.length = length;
+               this.travelTime = travelTime;
+               initValues();
+       }
+
+       private void initValues()
+       {
+               values = U.toVector(length);
+       }
+
+       private void recalculateSingleInput()
+       {
+               setNewValues(inputs.get(0).getInputValues());
+       }
+
+       private void recalculateMultipleInputs()
+       {
+               BitVectorMutator mutator = BitVectorMutator.empty();
+               for (ReadWriteEnd wireArrayEnd : inputs)
+                       mutator.join(wireArrayEnd.getInputValues());
+               setNewValues(mutator.get());
+       }
+
+       private void setNewValues(BitVector newValues)
+       {
+               if (values.equals(newValues))
+                       return;
+               BitVector oldValues = values;
+               values = newValues;
+               notifyObservers(oldValues);
+       }
+
+       private void recalculate()
+       {
+               switch (inputs.size())
+               {
+               case 0:
+                       return;
+               case 1:
+                       recalculateSingleInput();
+                       break;
+               default:
+                       recalculateMultipleInputs();
+               }
+       }
+
+       /**
+        * The {@link Wire} is interpreted as an unsigned integer with n bits.
+        * 
+        * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the same
+        *         value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
+        * 
+        * @author Fabian Stemmler
+        */
+       public boolean hasNumericValue()
+       {
+               for (Bit b : values)
+               {
+                       if (b != Bit.ZERO && b != Bit.ONE)
+                               return false;
+               }
+               return true;
+       }
+
+       /**
+        * The {@link Wire} is interpreted as an unsigned integer with n bits.
+        * 
+        * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
+        * 
+        * @author Fabian Stemmler
+        */
+       public long getUnsignedValue()
+       {
+               long val = 0;
+               long mask = 1;
+               for (Bit bit : values)
+               {
+                       switch (bit)
+                       {
+                       default:
+                       case Z:
+                       case X:
+                               return 0; // TODO: Proper handling for getUnsignedValue(), if not all bits are 1 or 0;
+                       case ONE:
+                               val |= mask;
+                               break;
+                       case ZERO:
+                       }
+                       mask = mask << 1;
+               }
+               return val;
+       }
+
+       /**
+        * The {@link Wire} is interpreted as a signed integer with n bits.
+        * 
+        * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
+        * 
+        * @author Fabian Stemmler
+        */
+       public long getSignedValue()
+       {
+               long val = getUnsignedValue();
+               long mask = 1 << (length - 1);
+               if ((mask & val) != 0)
+               {
+                       int shifts = 64 - length;
+                       return (val << shifts) >> shifts;
+               }
+               return val;
+       }
+
+       public Bit getValue()
+       {
+               return getValue(0);
+       }
+
+       public Bit getValue(int index)
+       {
+               return values.getBit(index);
+       }
+
+       public BitVector getValues(int start, int end)
+       {
+               return values.subVector(start, end);
+       }
+
+       public BitVector getValues()
+       {
+               return values;
+       }
+
+       /**
+        * Adds an {@link WireObserver}, who will be notified when the value of the {@link Wire} is updated.
+        * 
+        * @param ob The {@link WireObserver} to be notified of changes.
+        * @return true if the given {@link WireObserver} was not already registered, false otherwise
+        * 
+        * @author Fabian Stemmler
+        */
+       private void attachEnd(ReadEnd end)
+       {
+               attached.add(end);
+       }
+
+       private void detachEnd(ReadEnd end)
+       {
+               attached.remove(end);
+       }
+
+       private void notifyObservers(BitVector oldValues)
+       {
+               for (ReadEnd o : attached)
+                       o.update(oldValues);
+       }
+
+       /**
+        * Create and register a {@link ReadWriteEnd} object, which is tied to this {@link Wire}. This {@link ReadWriteEnd} can be written to.
+        */
+       public ReadWriteEnd createReadWriteEnd()
+       {
+               return new ReadWriteEnd();
+       }
+
+       /**
+        * Create a {@link ReadEnd} object, which is tied to this {@link Wire}. This {@link ReadEnd} cannot be written to.
+        */
+       public ReadEnd createReadOnlyEnd()
+       {
+               return new ReadEnd();
+       }
+
+       private void registerInput(ReadWriteEnd toRegister)
+       {
+               inputs.add(toRegister);
+       }
+
+       /**
+        * A {@link ReadEnd} feeds a constant signal into the {@link Wire} it is tied to. The combination of all inputs determines the
+        * {@link Wire}s final value. X dominates all other inputs Z does not affect the final value, unless there are no other inputs than Z 0
+        * and 1 turn into X when they are mixed
+        * 
+        * @author Fabian Stemmler
+        */
+       public class ReadEnd
+       {
+               private List<WireObserver> observers = new ArrayList<WireObserver>();
+
+               private ReadEnd()
+               {
+                       super();
+                       Wire.this.attachEnd(this);
+               }
+
+               public void update(BitVector oldValues)
+               {
+                       for (WireObserver ob : observers)
+                               ob.update(this, oldValues);
+               }
+
+               /**
+                * Included for convenient use on {@link Wire}s of length 1.
+                * 
+                * @return The value of bit 0.
+                * 
+                * @author Fabian Stemmler
+                */
+               public Bit getValue()
+               {
+                       return Wire.this.getValue();
+               }
+
+               /**
+                * @param index Index of the requested bit.
+                * @return The value of the indexed bit.
+                * 
+                * @author Fabian Stemmler
+                */
+               public Bit getValue(int index)
+               {
+                       return Wire.this.getValue(index);
+               }
+
+               /**
+                * @param index Index of the requested bit.
+                * @return The value of the indexed bit.
+                * 
+                * @author Fabian Stemmler
+                */
+               public BitVector getValues()
+               {
+                       return Wire.this.getValues();
+               }
+
+               /**
+                * @param start Start of the wanted segment. (inclusive)
+                * @param end   End of the wanted segment. (exclusive)
+                * @return The values of the segment of {@link Bit}s indexed.
+                * 
+                * @author Fabian Stemmler
+                */
+               public BitVector getValues(int start, int end)
+               {
+                       return Wire.this.getValues(start, end);
+               }
+
+               /**
+                * The {@link Wire} is interpreted as an unsigned integer with n bits.
+                * 
+                * @return <code>true</code> if all bits are either <code>Bit.ONE</code> or <code>Bit.ZERO</code> (they do not all have to have the
+                *         same value), not <code>Bit.X</code> or <code>Bit.Z</code>. <code>false</code> is returned otherwise.
+                * 
+                * @author Fabian Stemmler
+                */
+               public boolean hasNumericValue()
+               {
+                       return Wire.this.hasNumericValue();
+               }
+
+               /**
+                * The {@link Wire} is interpreted as an unsigned integer with n bits.
+                * 
+                * @return The unsigned value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
+                * 
+                * @author Fabian Stemmler
+                */
+               public long getUnsignedValue()
+               {
+                       return Wire.this.getUnsignedValue();
+               }
+
+               /**
+                * The {@link Wire} is interpreted as a signed integer with n bits.
+                * 
+                * @return The signed value of the {@link Wire}'s bits, where value 0 corresponds with 2^0, value 1 is 2^1 and so on.
+                * 
+                * @author Fabian Stemmler
+                */
+               public long getSignedValue()
+               {
+                       return Wire.this.getSignedValue();
+               }
+
+               @Override
+               public String toString()
+               {
+                       return Wire.this.toString();
+               }
+
+               public void close()
+               {
+                       inputs.remove(this);
+                       detachEnd(this);
+                       recalculate();
+               }
+
+               public int length()
+               {
+                       return length;
+               }
+
+               public boolean addObserver(WireObserver ob)
+               {
+                       return observers.add(ob);
+               }
+
+               public Wire getWire()
+               {
+                       return Wire.this;
+               }
+       }
+
+       public class ReadWriteEnd extends ReadEnd
+       {
+               private boolean open;
+               private BitVector inputValues;
+
+               private ReadWriteEnd()
+               {
+                       super();
+                       open = true;
+                       initValues();
+                       registerInput(this);
+               }
+
+               private void initValues()
+               {
+                       inputValues = U.toVector(length);
+               }
+
+               /**
+                * Sets the wires values. This takes up time, as specified by the {@link Wire}s travel time.
+                * 
+                * @param newValues The new values the wires should take on.
+                * 
+                * @author Fabian Stemmler
+                */
+               public void feedSignals(Bit... newValues)
+               {
+                       feedSignals(BitVector.of(newValues));
+               }
+
+               public void feedSignals(BitVector newValues)
+               {
+                       if (newValues.length() != length)
+                               throw new IllegalArgumentException(
+                                               String.format("Attempted to input %d bits instead of %d bits.", newValues.length(), length));
+                       if (!open)
+                               throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
+                       timeline.addEvent(e -> setValues(newValues), travelTime);
+               }
+
+               /**
+                * Sets values of a subarray of wires. This takes up time, as specified by the {@link Wire}s travel time.
+                * 
+                * @param bitVector   The new values the wires should take on.
+                * @param startingBit The first index of the subarray of wires.
+                * 
+                * @author Fabian Stemmler
+                */
+               public void feedSignals(int startingBit, BitVector bitVector)
+               {
+                       if (!open)
+                               throw new RuntimeException("Attempted to write to closed WireArrayEnd.");
+                       timeline.addEvent(e -> setValues(startingBit, bitVector), travelTime);
+               }
+
+               private void setValues(int startingBit, BitVector newValues)
+               {
+                       // index check covered in equals
+                       if (!inputValues.equalsWithOffset(newValues, startingBit))
+                       {
+                               Bit[] vals = inputValues.getBits();
+                               System.arraycopy(newValues.getBits(), 0, vals, startingBit, newValues.length());
+                               inputValues = BitVector.of(vals);
+                               Wire.this.recalculate();
+                       }
+               }
+
+               private void setValues(BitVector newValues)
+               {
+                       if (inputValues.equals(newValues))
+                               return;
+                       inputValues = newValues;
+                       Wire.this.recalculate();
+               }
+
+               /**
+                * @return The value (of bit 0) the {@link ReadEnd} is currently feeding into the associated {@link Wire}.
+                */
+               public Bit getInputValue()
+               {
+                       return getInputValue(0);
+               }
+
+               /**
+                * @return The value which the {@link ReadEnd} is currently feeding into the associated {@link Wire} at the indexed {@link Bit}.
+                */
+               public Bit getInputValue(int index)
+               {
+                       return inputValues.getBit(index);
+               }
+
+               /**
+                * @return A copy (safe to modify) of the values the {@link ReadEnd} is currently feeding into the associated {@link Wire}.
+                */
+               public BitVector getInputValues()
+               {
+                       return getInputValues(0, length);
+               }
+
+               public BitVector getInputValues(int start, int end)
+               {
+                       return inputValues.subVector(start, end);
+               }
+
+               /**
+                * {@link ReadEnd} now feeds Z into the associated {@link Wire}.
+                */
+               public void clearSignals()
+               {
+                       feedSignals(Z.toVector(length));
+               }
+
+               public BitVector wireValuesExcludingMe()
+               {
+                       BitVectorMutator mutator = BitVectorMutator.empty();
+                       for (ReadWriteEnd wireEnd : inputs)
+                       {
+                               if (wireEnd == this)
+                                       continue;
+                               mutator.join(wireEnd.inputValues);
+                       }
+                       return mutator.get();
+               }
+
+               @Override
+               public String toString()
+               {
+                       return inputValues.toString();
+               }
+       }
+
+       @Override
+       public String toString()
+       {
+               return String.format("wire 0x%08x value: %s inputs: %s", hashCode(), values, inputs);
+               // Arrays.toString(values), inputs.stream().map(i -> Arrays.toString(i.inputValues)).reduce((s1, s2) -> s1 + s2)
+       }
+
+       public static ReadEnd[] extractEnds(Wire[] w)
+       {
+               ReadEnd[] inputs = new ReadEnd[w.length];
+               for (int i = 0; i < w.length; i++)
+                       inputs[i] = w[i].createReadWriteEnd();
+               return inputs;
+       }
+}
\ No newline at end of file
diff --git a/era.mi/src/mograsim/logic/core/wires/WireObserver.java b/era.mi/src/mograsim/logic/core/wires/WireObserver.java
new file mode 100644 (file)
index 0000000..2082bd3
--- /dev/null
@@ -0,0 +1,9 @@
+package mograsim.logic.core.wires;
+
+import mograsim.logic.core.types.BitVector;
+import mograsim.logic.core.wires.Wire.ReadEnd;
+
+public interface WireObserver
+{
+       public void update(ReadEnd initiator, BitVector oldValues);
+}