diff --git a/src/main/java/de/neemann/digital/draw/graphics/GraphicRestyle.java b/src/main/java/de/neemann/digital/draw/graphics/GraphicRestyle.java new file mode 100644 index 000000000..ef3d0aff1 --- /dev/null +++ b/src/main/java/de/neemann/digital/draw/graphics/GraphicRestyle.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 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.graphics; + +/** + * A instance that performs a modification of styles on the drawing and then draws it on a given delegate. + */ +public abstract class GraphicRestyle extends Graphic { + + private final Graphic parent; + + /** + * Creates a new instace + * + * @param parent the delegate to be used to berform the drawing + */ + public GraphicRestyle(Graphic parent) { + this.parent = parent; + } + + /** + * The function to modify the style + * + * @param style the old style + * @return the new style + */ + public abstract Style getStyle(Style style); + + @Override + public void drawLine(VectorInterface p1, VectorInterface p2, Style style) { + parent.drawLine(p1, p2, getStyle(style)); + } + + + @Override + public void drawPolygon(Polygon p, Style style) { + parent.drawPolygon(p, getStyle(style)); + } + + @Override + public void drawCircle(VectorInterface p1, VectorInterface p2, Style style) { + parent.drawCircle(p1, p2, getStyle(style)); + } + + @Override + public void drawText(VectorInterface p1, VectorInterface p2, VectorInterface p3, String text, Orientation orientation, Style style) { + parent.drawText(p1, p2, p3, text, orientation, getFontStyle(style)); + } + + /** + * The function to modify the font style. + * By default, it calls getStyle. + * + * @param style the old style + * @return the new style + */ + public Style getFontStyle(Style style) { + return getStyle(style); + } + + @Override + public boolean isFlagSet(Flag flag) { + return parent.isFlagSet(flag); + } +} 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 ab8823d52..816e13c1f 100644 --- a/src/main/java/de/neemann/digital/draw/shapes/CustomCircuitShapeType.java +++ b/src/main/java/de/neemann/digital/draw/shapes/CustomCircuitShapeType.java @@ -29,6 +29,11 @@ public enum CustomCircuitShapeType { */ LAYOUT, + /** + * The shape is a minified version of the circuit + */ + MINIMIZED, + /** * Shape is defined in the circuit itself. */ diff --git a/src/main/java/de/neemann/digital/draw/shapes/MinimizedShape.java b/src/main/java/de/neemann/digital/draw/shapes/MinimizedShape.java new file mode 100644 index 000000000..3fc2e025f --- /dev/null +++ b/src/main/java/de/neemann/digital/draw/shapes/MinimizedShape.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2023 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.element.ElementAttributes; +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.library.ElementNotFoundException; +import de.neemann.digital.draw.library.ElementTypeDescriptionCustom; +import de.neemann.digital.draw.library.GenericCode; +import de.neemann.digital.draw.library.GenericInitCode; +import de.neemann.digital.lang.Lang; +import de.neemann.digital.testing.TestCaseElement; + +import java.util.HashMap; +import java.util.HashSet; + +import static de.neemann.digital.draw.shapes.GenericShape.SIZE; +import static de.neemann.digital.draw.shapes.GenericShape.SIZE2; + +/** + * A shape created from the circuit inside. + */ +public class MinimizedShape implements Shape { + private static final HashSet IGNORE_SET = new HashSet<>(); + + static { + IGNORE_SET.add(In.DESCRIPTION.getName()); + IGNORE_SET.add(Out.DESCRIPTION.getName()); + IGNORE_SET.add(Clock.DESCRIPTION.getName()); + IGNORE_SET.add(GenericCode.DESCRIPTION.getName()); + IGNORE_SET.add(GenericInitCode.DESCRIPTION.getName()); + IGNORE_SET.add(TestCaseElement.DESCRIPTION.getName()); + } + + private final Pins pins; + private final Circuit circuit; + private final Vector min; + private final Polygon outer; + private final String name; + private final Vector textPos; + private final Vector labelPos; + private final String label; + + + /** + * Creates a new instance. + * + * @param custom then included circuit + * @param elementAttributes the circuits attributes + * @throws NodeException NodeException + * @throws ElementNotFoundException ElementNotFoundException + * @throws PinException PinException + */ + public MinimizedShape(ElementTypeDescriptionCustom custom, ElementAttributes elementAttributes) throws NodeException, ElementNotFoundException, PinException { + name = custom.getShortName(); + label = elementAttributes.getLabel(); + + circuit = custom.getResolvedCircuit(elementAttributes); + + HashMap pinMap = new HashMap<>(); + for (VisualElement ve : circuit.getElements()) { + if (ve.equalsDescription(In.DESCRIPTION) || ve.equalsDescription(Clock.DESCRIPTION)) { + addToMap(pinMap, ve); + } + if (ve.equalsDescription(Out.DESCRIPTION)) { + addToMap(pinMap, ve); + } + } + boolean first = true; + int minX = 0; + int minY = 0; + for (Vector p : pinMap.values()) { + if (first) { + minX = p.x; + minY = p.y; + first = false; + } else { + if (p.x < minX) { + minX = p.x; + } + if (p.y < minY) { + minY = p.y; + } + } + } + min = new Vector(minX, minY); + + pins = new Pins(); + for (PinDescription p : custom.getInputDescription(elementAttributes)) { + pins.add(new Pin(toGrid(pinMap.get(p.getName())), p)); + } + for (PinDescription p : custom.getOutputDescriptions(elementAttributes)) { + pins.add(new Pin(toGrid(pinMap.get(p.getName())), p)); + } + + GraphicMinMax minMax = new GraphicMinMax(); + drawCircuitTo(minMax); + for (Pin p : pins) + minMax.check(p.getPos().mul(2).add(min)); + + outer = new Polygon(true) + .add(new Vector(minMax.getMin().x, minMax.getMin().y - SIZE2)) + .add(new Vector(minMax.getMin().x, minMax.getMax().y + SIZE2)) + .add(new Vector(minMax.getMax().x, minMax.getMax().y + SIZE2)) + .add(new Vector(minMax.getMax().x, minMax.getMin().y - SIZE2)); + + Vector size = minMax.getMax().sub(minMax.getMin()).div(2); + + labelPos = new Vector(size.x / 2, -SIZE); + textPos = new Vector(size.x / 2, size.y + SIZE2); + } + + private void addToMap(HashMap pinMap, VisualElement ve) throws PinException { + final String label = ve.getElementAttributes().getLabel(); + if (pinMap.containsKey(label)) + throw new PinException(Lang.get("err_duplicatePinLabel", label, name)); + pinMap.put(label, ve.getPos()); + } + + private Vector toGrid(VectorInterface pos) { + pos = pos.sub(min).div(2); + return new Vector(Math.round(pos.getXFloat() / SIZE) * SIZE, Math.round(pos.getYFloat() / SIZE) * SIZE); + } + + @Override + public void drawTo(Graphic graphic, Style highLight) { + Graphic gr = new GraphicTransform(graphic, + Transform.mul( + new TransformTranslate(min.mul(-1)), + TransformMatrix.scale(0.5f, 0.5f))); + + gr = new GraphicRestyle(gr) { + @Override + public Style getStyle(Style style) { + if (style != Style.DASH) + return Style.THIN; + else + return style; + } + + @Override + public Style getFontStyle(Style style) { + return Style.THIN.deriveFontStyle(style.getFontSize() / 2, false); + } + }; + + drawCircuitTo(gr); + gr.drawPolygon(outer, Style.DASH); + + if (label != null && label.length() > 0) + graphic.drawText(labelPos, label, Orientation.CENTERBOTTOM, Style.NORMAL); + + if (name.length() > 0) + graphic.drawText(textPos, name, Orientation.CENTERTOP, Style.SHAPE_PIN); + } + + private void drawCircuitTo(Graphic gr) { + for (Wire w : circuit.getWires()) + gr.drawLine(w.p1, w.p2, Style.THIN); + for (VisualElement ve : circuit.getElements()) + if (!IGNORE_SET.contains(ve.getElementName())) { + ve.drawTo(gr, null); + } + } + + @Override + public Pins getPins() { + return pins; + } + + @Override + public InteractorInterface applyStateMonitor(IOState ioState) { + return null; + } +} 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 70f998ebd..332191fad 100644 --- a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java +++ b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java @@ -216,6 +216,8 @@ public final class ShapeFactory { customDescr.getAttributes()); case LAYOUT: return new LayoutShape(customDescr, elementAttributes); + case MINIMIZED: + return new MinimizedShape(customDescr, elementAttributes); case CUSTOM: final CustomShapeDescription customShapeDescription = customDescr.getAttributes().get(Keys.CUSTOM_SHAPE); if (!customShapeDescription.isEmpty()) diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 5df5fce66..feeb9d0e5 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -1585,6 +1585,7 @@ Sind evtl. die Namen der Variablen nicht eindeutig? DIL-Gehäuse Layout Benutzerdefiniert + verkleinerte Schaltung Ausrichtung Lage der Koordinate relativ zum Text. diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index ed1da48a4..22cf3e448 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -1574,6 +1574,7 @@ DIL-Chip Layout User defined + Downsized Circuit Orientation Position of the coordinate relative to the text.