diff --git a/pom.xml b/pom.xml
index f91143d0c..58503ddf5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,7 +79,7 @@
-
org.apache.maven.plugins
@@ -128,7 +128,7 @@
true
- de.neemann.assembler.gui.Main
+ de.neemann.digital.gui.Main
${buildNumber}
@@ -182,7 +182,7 @@
-
+
diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java
new file mode 100644
index 000000000..e73d0c24a
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/Main.java
@@ -0,0 +1,39 @@
+package de.neemann.digital.gui;
+
+import de.neemann.digital.gui.components.CircuitComponent;
+import de.neemann.digital.gui.draw.graphics.Vector;
+import de.neemann.digital.gui.draw.parts.Circuit;
+import de.neemann.digital.gui.draw.parts.Part;
+import de.neemann.digital.gui.draw.shapes.GenericShape;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author hneemann
+ */
+public class Main extends JFrame {
+ private final CircuitComponent cr;
+
+ public Main() {
+ super("Digital");
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+
+ cr = new CircuitComponent(createDemoCircuit());
+ getContentPane().add(cr);
+
+ setPreferredSize(new Dimension(800, 600));
+ pack();
+ setLocationRelativeTo(null);
+ }
+
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(() -> new Main().setVisible(true));
+ }
+
+ private Circuit createDemoCircuit() {
+ Circuit cr = new Circuit();
+ cr.add(new Part(new GenericShape("&", 2, 1)).setPos(new Vector(10, 10)));
+ return cr;
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java
new file mode 100644
index 000000000..110595ec1
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java
@@ -0,0 +1,27 @@
+package de.neemann.digital.gui.components;
+
+import de.neemann.digital.gui.draw.graphics.GraphicSwing;
+import de.neemann.digital.gui.draw.parts.Circuit;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author hneemann
+ */
+public class CircuitComponent extends JComponent {
+
+ private final Circuit circuit;
+
+ public CircuitComponent(Circuit circuit) {
+ this.circuit = circuit;
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+
+ GraphicSwing gr = new GraphicSwing((Graphics2D) g);
+ circuit.drawTo(gr);
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/graphics/Graphic.java b/src/main/java/de/neemann/digital/gui/draw/graphics/Graphic.java
new file mode 100644
index 000000000..d65f5603b
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/graphics/Graphic.java
@@ -0,0 +1,15 @@
+package de.neemann.digital.gui.draw.graphics;
+
+/**
+ * @author hneemann
+ */
+public interface Graphic {
+
+ void drawLine(Vector p1, Vector p2, Style style);
+
+ void drawPolygon(Polygon p, Style style);
+
+ void drawCircle(Vector p1, Vector p2, Style style);
+
+ void drawText(Vector p1, Vector p2, String text);
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/graphics/GraphicSwing.java b/src/main/java/de/neemann/digital/gui/draw/graphics/GraphicSwing.java
new file mode 100644
index 000000000..3766ae28f
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/graphics/GraphicSwing.java
@@ -0,0 +1,40 @@
+package de.neemann.digital.gui.draw.graphics;
+
+import java.awt.*;
+
+/**
+ * @author hneemann
+ */
+public class GraphicSwing implements Graphic {
+
+ private final Graphics2D gr;
+
+ public GraphicSwing(Graphics2D gr) {
+ this.gr = gr;
+ }
+
+ @Override
+ public void drawLine(Vector p1, Vector p2, Style style) {
+ gr.drawLine(p1.x, p1.y, p2.x, p2.y);
+ }
+
+ @Override
+ public void drawPolygon(Polygon p, Style style) {
+ java.awt.Polygon poly = new java.awt.Polygon();
+ for (Vector v : p.getPoints())
+ poly.addPoint(v.x, v.y);
+ gr.draw(poly);
+ }
+
+ @Override
+ public void drawCircle(Vector p1, Vector p2, Style style) {
+ Vector p = Vector.min(p1, p2);
+ Vector w = Vector.width(p1, p2);
+ gr.drawOval(p.x, p.y, w.x, w.y);
+ }
+
+ @Override
+ public void drawText(Vector p1, Vector p2, String text) {
+ gr.drawString(text, p1.x, p1.y);
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/graphics/GraphicTransform.java b/src/main/java/de/neemann/digital/gui/draw/graphics/GraphicTransform.java
new file mode 100644
index 000000000..020994691
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/graphics/GraphicTransform.java
@@ -0,0 +1,44 @@
+package de.neemann.digital.gui.draw.graphics;
+
+/**
+ * @author hneemann
+ */
+public class GraphicTransform implements Graphic {
+
+ private final Graphic parent;
+ private final Vector pos;
+ private final int rotate;
+
+ public GraphicTransform(Graphic parent, Vector pos, int rotate) {
+ this.parent = parent;
+ this.pos = pos;
+ this.rotate = rotate;
+ }
+
+ @Override
+ public void drawLine(Vector p1, Vector p2, Style style) {
+ parent.drawLine(transform(p1), transform(p2), style);
+ }
+
+ @Override
+ public void drawPolygon(Polygon p, Style style) {
+ Polygon pp = new Polygon(p.isClosed());
+ for (Vector v : p.getPoints())
+ pp.add(transform(v));
+ parent.drawPolygon(pp, style);
+ }
+
+ @Override
+ public void drawCircle(Vector p1, Vector p2, Style style) {
+ parent.drawCircle(transform(p1), transform(p2), style);
+ }
+
+ @Override
+ public void drawText(Vector p1, Vector p2, String text) {
+ parent.drawText(transform(p1), transform(p2), text);
+ }
+
+ public Vector transform(Vector v) {
+ return v.add(pos);
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/graphics/Polygon.java b/src/main/java/de/neemann/digital/gui/draw/graphics/Polygon.java
new file mode 100644
index 000000000..ce6903225
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/graphics/Polygon.java
@@ -0,0 +1,46 @@
+package de.neemann.digital.gui.draw.graphics;
+
+import java.util.ArrayList;
+
+/**
+ * @author hneemann
+ */
+public class Polygon {
+
+ private ArrayList points;
+ private boolean closed;
+
+ public Polygon() {
+ this(new ArrayList<>(), true);
+ }
+
+ public Polygon(boolean closed) {
+ this(new ArrayList<>(), closed);
+ }
+
+ public Polygon(ArrayList points, boolean closed) {
+ this.points = points;
+ this.closed = closed;
+ }
+
+ public boolean isClosed() {
+ return closed;
+ }
+
+ public void setClosed(boolean closed) {
+ this.closed = closed;
+ }
+
+ public Polygon add(int x, int y) {
+ return add(new Vector(x, y));
+ }
+
+ public Polygon add(Vector p) {
+ points.add(p);
+ return this;
+ }
+
+ public ArrayList getPoints() {
+ return points;
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/graphics/Style.java b/src/main/java/de/neemann/digital/gui/draw/graphics/Style.java
new file mode 100644
index 000000000..c8b595005
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/graphics/Style.java
@@ -0,0 +1,19 @@
+package de.neemann.digital.gui.draw.graphics;
+
+/**
+ * @author hneemann
+ */
+public class Style {
+ public static final Style NORMAL = new Style(1);
+ public static final Style WIRE = new Style(2);
+
+ private final int thickness;
+
+ private Style(int thickness) {
+ this.thickness = thickness;
+ }
+
+ public int getThickness() {
+ return thickness;
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/graphics/Vector.java b/src/main/java/de/neemann/digital/gui/draw/graphics/Vector.java
new file mode 100644
index 000000000..c6a10c79f
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/graphics/Vector.java
@@ -0,0 +1,51 @@
+package de.neemann.digital.gui.draw.graphics;
+
+/**
+ * @author hneemann
+ */
+public class Vector {
+
+ public final int x;
+ public final int y;
+
+ public Vector(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public static Vector min(Vector... p) {
+ int x = p[0].x;
+ int y = p[0].y;
+ for (int i = 1; i < p.length; i++) {
+ if (p[i].x < x) x = p[i].x;
+ if (p[i].y < y) y = p[i].y;
+ }
+ return new Vector(x, y);
+ }
+
+ public static Vector width(Vector... p) {
+ int x1 = p[0].x;
+ int y1 = p[0].y;
+ int x2 = x1;
+ int y2 = y1;
+ for (int i = 1; i < p.length; i++) {
+ if (p[i].x < x1) x1 = p[i].x;
+ if (p[i].y < y1) y1 = p[i].y;
+ if (p[i].x > x2) x2 = p[i].x;
+ if (p[i].y > y2) y2 = p[i].y;
+ }
+ return new Vector(x2 - x1, y2 - y1);
+ }
+
+ public Vector add(Vector a) {
+ return new Vector(x + a.x, y + a.y);
+ }
+
+ public Vector add(int x, int y) {
+ return new Vector(this.x + x, this.y + y);
+ }
+
+ public Vector sub(Vector a) {
+ return new Vector(x - a.x, y - a.y);
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/parts/Circuit.java b/src/main/java/de/neemann/digital/gui/draw/parts/Circuit.java
new file mode 100644
index 000000000..10f0d102c
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/parts/Circuit.java
@@ -0,0 +1,32 @@
+package de.neemann.digital.gui.draw.parts;
+
+import de.neemann.digital.gui.draw.graphics.Graphic;
+import de.neemann.digital.gui.draw.shapes.Drawable;
+
+import java.util.ArrayList;
+
+/**
+ * @author hneemann
+ */
+public class Circuit implements Drawable {
+
+ private final ArrayList parts;
+ private final ArrayList wires;
+
+ public Circuit() {
+ parts = new ArrayList<>();
+ wires = new ArrayList<>();
+ }
+
+ @Override
+ public void drawTo(Graphic graphic) {
+ for (Wire w : wires)
+ w.drawTo(graphic);
+ for (Part p : parts)
+ p.drawTo(graphic);
+ }
+
+ public void add(Part part) {
+ parts.add(part);
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/parts/Moveable.java b/src/main/java/de/neemann/digital/gui/draw/parts/Moveable.java
new file mode 100644
index 000000000..58ad67c88
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/parts/Moveable.java
@@ -0,0 +1,10 @@
+package de.neemann.digital.gui.draw.parts;
+
+import de.neemann.digital.gui.draw.graphics.Vector;
+
+/**
+ * @author hneemann
+ */
+public interface Moveable {
+ void move(Vector delta);
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/parts/Part.java b/src/main/java/de/neemann/digital/gui/draw/parts/Part.java
new file mode 100644
index 000000000..0ea342cc7
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/parts/Part.java
@@ -0,0 +1,51 @@
+package de.neemann.digital.gui.draw.parts;
+
+import de.neemann.digital.gui.draw.graphics.Graphic;
+import de.neemann.digital.gui.draw.graphics.GraphicTransform;
+import de.neemann.digital.gui.draw.graphics.Style;
+import de.neemann.digital.gui.draw.graphics.Vector;
+import de.neemann.digital.gui.draw.shapes.Drawable;
+import de.neemann.digital.gui.draw.shapes.Shape;
+
+/**
+ * @author hneemann
+ */
+public class Part implements Drawable, Moveable {
+ private Shape shape;
+ private Vector pos;
+ private int rotate;
+
+ public Part(Shape shape) {
+ this.shape = shape;
+ }
+
+ public Vector getPos() {
+ return pos;
+ }
+
+ public Part setPos(Vector pos) {
+ this.pos = pos;
+ return this;
+ }
+
+ public int getRotate() {
+ return rotate;
+ }
+
+ public void setRotate(int rotate) {
+ this.rotate = rotate;
+ }
+
+ @Override
+ public void drawTo(Graphic graphic) {
+ Graphic gr = new GraphicTransform(graphic, pos, rotate);
+ shape.drawTo(gr);
+ for (Pin p : shape.getPins())
+ gr.drawCircle(p.getPos().add(-1, -1), p.getPos().add(1, 1), Style.NORMAL);
+ }
+
+ @Override
+ public void move(Vector delta) {
+ pos = pos.add(delta);
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/parts/Pin.java b/src/main/java/de/neemann/digital/gui/draw/parts/Pin.java
new file mode 100644
index 000000000..2f4fd7a70
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/parts/Pin.java
@@ -0,0 +1,20 @@
+package de.neemann.digital.gui.draw.parts;
+
+import de.neemann.digital.gui.draw.graphics.Vector;
+
+/**
+ * @author hneemann
+ */
+public class Pin {
+ private Vector pos;
+ private String name;
+
+ public Pin(Vector pos, String name) {
+ this.pos = pos;
+ this.name = name;
+ }
+
+ public Vector getPos() {
+ return pos;
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/parts/Wire.java b/src/main/java/de/neemann/digital/gui/draw/parts/Wire.java
new file mode 100644
index 000000000..c99fc0326
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/parts/Wire.java
@@ -0,0 +1,26 @@
+package de.neemann.digital.gui.draw.parts;
+
+import de.neemann.digital.gui.draw.graphics.Graphic;
+import de.neemann.digital.gui.draw.graphics.Style;
+import de.neemann.digital.gui.draw.graphics.Vector;
+import de.neemann.digital.gui.draw.shapes.Drawable;
+
+/**
+ * @author hneemann
+ */
+public class Wire implements Drawable, Moveable {
+
+ private Vector p1;
+ private Vector p2;
+
+ @Override
+ public void drawTo(Graphic graphic) {
+ graphic.drawLine(p1, p2, Style.WIRE);
+ }
+
+ @Override
+ public void move(Vector delta) {
+ p1 = p1.add(delta);
+ p2 = p2.add(delta);
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/shapes/Drawable.java b/src/main/java/de/neemann/digital/gui/draw/shapes/Drawable.java
new file mode 100644
index 000000000..41272000b
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/shapes/Drawable.java
@@ -0,0 +1,10 @@
+package de.neemann.digital.gui.draw.shapes;
+
+import de.neemann.digital.gui.draw.graphics.Graphic;
+
+/**
+ * @author hneemann
+ */
+public interface Drawable {
+ void drawTo(Graphic graphic);
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/shapes/GenericShape.java b/src/main/java/de/neemann/digital/gui/draw/shapes/GenericShape.java
new file mode 100644
index 000000000..47155d5b6
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/shapes/GenericShape.java
@@ -0,0 +1,65 @@
+package de.neemann.digital.gui.draw.shapes;
+
+import de.neemann.digital.gui.draw.graphics.Graphic;
+import de.neemann.digital.gui.draw.graphics.Polygon;
+import de.neemann.digital.gui.draw.graphics.Style;
+import de.neemann.digital.gui.draw.graphics.Vector;
+import de.neemann.digital.gui.draw.parts.Pin;
+
+import java.util.ArrayList;
+
+/**
+ * @author hneemann
+ */
+public class GenericShape implements Shape {
+
+ private final String name;
+ private int inputs;
+ private int outputs;
+ private ArrayList pins;
+
+ public GenericShape(String name, int inputs, int outputs) {
+ this.name = name;
+ this.inputs = inputs;
+ this.outputs = outputs;
+ }
+
+ @Override
+ public Iterable getPins() {
+ if (pins == null) {
+ pins = new ArrayList<>(inputs + outputs);
+ for (int i = 0; i < inputs; i++)
+ pins.add(new Pin(new Vector(0, i * 5), "i" + i));
+ for (int i = 0; i < outputs; i++)
+ pins.add(new Pin(new Vector(15, i * 5), "o" + i));
+
+ }
+ return pins;
+ }
+
+ @Override
+ public void drawTo(Graphic graphic) {
+ int max = Math.max(inputs, outputs);
+ int height = (max - 1) * 5 + 2;
+ graphic.drawPolygon(new Polygon(true).add(1, -2).add(14, -2).add(14, height).add(1, height), Style.NORMAL);
+ graphic.drawText(new Vector(3, 5), new Vector(4, 5), name);
+ }
+
+ public int getInputs() {
+ return inputs;
+ }
+
+ public void setInputs(int inputs) {
+ pins = null;
+ this.inputs = inputs;
+ }
+
+ public int getOutputs() {
+ return outputs;
+ }
+
+ public void setOutputs(int outputs) {
+ pins = null;
+ this.outputs = outputs;
+ }
+}
diff --git a/src/main/java/de/neemann/digital/gui/draw/shapes/Shape.java b/src/main/java/de/neemann/digital/gui/draw/shapes/Shape.java
new file mode 100644
index 000000000..76b217cc0
--- /dev/null
+++ b/src/main/java/de/neemann/digital/gui/draw/shapes/Shape.java
@@ -0,0 +1,12 @@
+package de.neemann.digital.gui.draw.shapes;
+
+import de.neemann.digital.gui.draw.parts.Pin;
+
+/**
+ * @author hneemann
+ */
+public interface Shape extends Drawable {
+
+ Iterable getPins();
+
+}