diff --git a/src/main/java/de/neemann/digital/draw/shapes/CustomCircuitShapeType.java b/src/main/java/de/neemann/digital/draw/shapes/CustomCircuitShapeType.java
index 11a5e996c..ab8823d52 100644
--- a/src/main/java/de/neemann/digital/draw/shapes/CustomCircuitShapeType.java
+++ b/src/main/java/de/neemann/digital/draw/shapes/CustomCircuitShapeType.java
@@ -10,10 +10,15 @@ package de.neemann.digital.draw.shapes;
*/
public enum CustomCircuitShapeType {
/**
- * The default shape. inputs at the left, outputs at the right
+ * Uses the shape specified in the circuit itself
*/
DEFAULT,
+ /**
+ * The default shape. inputs at the left, outputs at the right
+ */
+ SIMPLE,
+
/**
* A DIL shape
*/
diff --git a/src/main/java/de/neemann/digital/draw/shapes/LayoutShape.java b/src/main/java/de/neemann/digital/draw/shapes/LayoutShape.java
new file mode 100644
index 000000000..f226ab9ab
--- /dev/null
+++ b/src/main/java/de/neemann/digital/draw/shapes/LayoutShape.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018 Helmut Neemann.
+ * Use of this source code is governed by the GPL v3 license
+ * that can be found in the LICENSE file.
+ */
+package de.neemann.digital.draw.shapes;
+
+import de.neemann.digital.core.NodeException;
+import de.neemann.digital.core.Observer;
+import de.neemann.digital.core.element.ElementAttributes;
+import de.neemann.digital.core.element.Keys;
+import de.neemann.digital.core.element.PinDescription;
+import de.neemann.digital.core.io.In;
+import de.neemann.digital.core.io.Out;
+import de.neemann.digital.core.wiring.Clock;
+import de.neemann.digital.draw.elements.*;
+import de.neemann.digital.draw.graphics.*;
+import de.neemann.digital.draw.graphics.Polygon;
+import de.neemann.digital.draw.library.ElementLibrary;
+import de.neemann.digital.lang.Lang;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
+
+/**
+ * The layout shape.
+ * The pins are ordered in the same way they are placed inside the circuit.
+ * Thus the shape feels like a minimized version of the contained circuit in respect to pin ordering.
+ */
+public class LayoutShape implements Shape {
+
+ private final int width;
+ private final int height;
+ private final Pins pins;
+ private final Color color;
+ private final String name;
+ private final String label;
+ private final PinList left;
+ private final PinList right;
+ private final PinList top;
+ private final PinList bottom;
+
+ /**
+ * Creates a new instance
+ *
+ * @param custom the type description
+ * @param elementAttributes the local attributes
+ * @throws NodeException NodeException
+ * @throws PinException PinException
+ */
+ public LayoutShape(ElementLibrary.ElementTypeDescriptionCustom custom, ElementAttributes elementAttributes) throws NodeException, PinException {
+ left = new PinList(false);
+ right = new PinList(false);
+ top = new PinList(true);
+ bottom = new PinList(true);
+
+ for (VisualElement ve : custom.getCircuit().getElements()) {
+ if (ve.equalsDescription(In.DESCRIPTION) || ve.equalsDescription(Clock.DESCRIPTION)) {
+ switch (ve.getRotate()) {
+ case 0:
+ left.add(ve);
+ break;
+ case 1:
+ bottom.add(ve);
+ break;
+ case 2:
+ right.add(ve);
+ break;
+ default:
+ top.add(ve);
+ break;
+ }
+ }
+ if (ve.equalsDescription(Out.DESCRIPTION)) {
+ switch (ve.getRotate()) {
+ case 0:
+ right.add(ve);
+ break;
+ case 1:
+ top.add(ve);
+ break;
+ case 2:
+ left.add(ve);
+ break;
+ default:
+ bottom.add(ve);
+ break;
+ }
+ }
+ }
+
+ height = Math.max(right.size(), left.size()) + 1;
+ final int w = Math.max(top.size(), bottom.size()) + 1;
+ width = Math.max(w, custom.getAttributes().get(Keys.WIDTH));
+
+
+ HashMap map = new HashMap<>();
+ top.createPosition(map, new Vector(((width - top.size()) / 2 + 1) * SIZE, 0));
+ bottom.createPosition(map, new Vector(((width - bottom.size()) / 2 + 1) * SIZE, SIZE * height));
+ left.createPosition(map, new Vector(0, SIZE));
+ right.createPosition(map, new Vector(SIZE * width, SIZE));
+
+ pins = new Pins();
+ for (PinDescription p : custom.getInputDescription(elementAttributes))
+ pins.add(createPin(map, p));
+ for (PinDescription p : custom.getOutputDescriptions(elementAttributes))
+ pins.add(createPin(map, p));
+
+ color = custom.getCircuit().getAttributes().get(Keys.BACKGROUND_COLOR);
+ label = elementAttributes.getCleanLabel();
+ name = custom.getShortName();
+ }
+
+ private Pin createPin(HashMap map, PinDescription p) throws PinException {
+ PinPos pinPos = map.get(p.getName());
+ if (pinPos == null)
+ throw new PinException(Lang.get("err_pin_N_notFound", p.getName()));
+ return new Pin(pinPos.pos, p);
+ }
+
+
+ @Override
+ public Pins getPins() {
+ return pins;
+ }
+
+ @Override
+ public InteractorInterface applyStateMonitor(IOState ioState, Observer guiObserver) {
+ return null;
+ }
+
+ @Override
+ public void drawTo(Graphic graphic, Style highLight) {
+ final Polygon poly = new Polygon(true)
+ .add(0, 0)
+ .add(width * SIZE, 0)
+ .add(width * SIZE, height * SIZE)
+ .add(0, height * SIZE);
+ graphic.drawPolygon(poly, Style.NORMAL.deriveFillStyle(color));
+ graphic.drawPolygon(poly, Style.NORMAL);
+
+ Vector center = new Vector(width * SIZE / 2, height * SIZE / 2);
+ Graphic.drawText(graphic, center.add(0, -2), name, Orientation.CENTERBOTTOM, Style.SHAPE_PIN);
+ Graphic.drawText(graphic, center.add(0, 2), label, Orientation.CENTERTOP, Style.SHAPE_PIN);
+
+ for (PinPos p : left)
+ Graphic.drawText(graphic, p.pos.add(4, 0), p.label, Orientation.LEFTCENTER, Style.SHAPE_PIN);
+ for (PinPos p : right)
+ Graphic.drawText(graphic, p.pos.add(-4, 0), p.label, Orientation.RIGHTCENTER, Style.SHAPE_PIN);
+ for (PinPos p : top)
+ graphic.drawText(p.pos.add(0, 4), p.pos.add(0, 3), p.label, Orientation.RIGHTCENTER, Style.SHAPE_PIN);
+ for (PinPos p : bottom)
+ graphic.drawText(p.pos.add(0, -4), p.pos.add(0, -3), p.label, Orientation.RIGHTCENTER, Style.SHAPE_PIN);
+ }
+
+ private final static class PinPos implements Comparable {
+ private final int orderPos;
+ private final String label;
+ private Vector pos;
+
+ private PinPos(VisualElement ve, boolean horizontal) {
+ if (horizontal)
+ orderPos = ve.getPos().x;
+ else
+ orderPos = ve.getPos().y;
+ label = ve.getElementAttributes().getLabel();
+ }
+
+ @Override
+ public int compareTo(PinPos pinPos) {
+ return orderPos - pinPos.orderPos;
+ }
+
+ }
+
+ private final static class PinList implements Iterable {
+ private final boolean horizontal;
+ private ArrayList pins;
+
+ private PinList(boolean horizontal) {
+ this.horizontal = horizontal;
+ pins = new ArrayList<>();
+ }
+
+ private void add(VisualElement ve) {
+ pins.add(new PinPos(ve, horizontal));
+ }
+
+ private int size() {
+ return pins.size();
+ }
+
+ private void createPosition(HashMap map, Vector pos) {
+ Collections.sort(pins);
+ for (PinPos pp : pins) {
+ map.put(pp.label, pp);
+ pp.pos = pos;
+ if (horizontal)
+ pos = pos.add(SIZE, 0);
+ else
+ pos = pos.add(0, SIZE);
+ }
+ }
+
+ @Override
+ public Iterator iterator() {
+ return pins.iterator();
+ }
+ }
+}
diff --git a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java
index 861faad62..337e560a7 100644
--- a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java
+++ b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java
@@ -183,6 +183,8 @@ public final class ShapeFactory {
pt.getOutputDescriptions(elementAttributes),
elementAttributes.getLabel(),
customDescr.getAttributes());
+ case LAYOUT:
+ return new LayoutShape(customDescr, elementAttributes);
case CUSTOM:
final CustomShapeDescription customShapeDescription = customDescr.getAttributes().get(Keys.CUSTOM_SHAPE);
if (customShapeDescription != CustomShapeDescription.EMPTY)
diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml
index 25c3c8b44..40dac5b78 100644
--- a/src/main/resources/lang/lang_de.xml
+++ b/src/main/resources/lang/lang_de.xml
@@ -1189,9 +1189,10 @@ Sind evtl. die Namen der Variablen nicht eindeutig?
Form
Die Form, welche für die Repräsentation der Schaltung in einer einbettenden
- Schaltung verwendet werden soll. Bei "Layout" bestimmt die Lage der Ein- und Ausgänge in der Schaltung die
- Position der Pins.
- Standard
+ Schaltung verwendet werden soll. Bei "Layout" bestimmt die Lage und Orientierung der Ein- und Ausgänge in
+ der Schaltung die Position der Pins.
+ Vorgabe
+ Einfach
DIL-Gehäuse
Layout
Benutzerdefiniert
diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml
index adcf3884e..23d515813 100644
--- a/src/main/resources/lang/lang_en.xml
+++ b/src/main/resources/lang/lang_en.xml
@@ -1180,8 +1180,10 @@
Shape
The shape to be used for the representation of the circuit in an embedding circuit.
- With "Layout", the position of the inputs and outputs in the circuit determines the position of the pins.
+ With "Layout", the position of the inputs and outputs and and their orientation in the circuit determines
+ the position of the pins.
Default
+ Simple
DIL-Chip
Layout
User defined