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