mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-14 15:26:52 -04:00
Adds a simple auto wire function; closes #274
This commit is contained in:
parent
4b60be0808
commit
f3f6c7d001
@ -13,6 +13,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
|
||||
|
||||
/**
|
||||
* A list of pins
|
||||
*/
|
||||
@ -90,4 +92,16 @@ public class Pins implements Iterable<Pin> {
|
||||
public Pin get(int index) {
|
||||
return allPins.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false if there are two pins next to each other in horizontal direction
|
||||
*/
|
||||
boolean autoWireCompatible() {
|
||||
for (Pin p1 : allPins)
|
||||
for (Pin p2 : allPins) {
|
||||
if (p1.getPos().add(SIZE, 0).equals(p2.getPos()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import de.neemann.digital.core.element.*;
|
||||
import de.neemann.digital.draw.graphics.*;
|
||||
import de.neemann.digital.draw.shapes.*;
|
||||
import de.neemann.digital.draw.shapes.Shape;
|
||||
import de.neemann.digital.draw.shapes.custom.CustomShape;
|
||||
import de.neemann.digital.gui.components.CircuitComponent;
|
||||
import de.neemann.gui.Screen;
|
||||
|
||||
@ -34,6 +35,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
||||
private transient Element element;
|
||||
// shape is set to null and recreated if needed if attributes are changed
|
||||
private transient Shape shape;
|
||||
private transient Boolean autoWire;
|
||||
// shapes are recreated if attributes are changed, therefore a factory is necessary and not only a simple shape!
|
||||
private transient ShapeFactory shapeFactory;
|
||||
private transient Transform transform;
|
||||
@ -102,7 +104,12 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
||||
|
||||
@Override
|
||||
public void attributeChanged() {
|
||||
resetShape();
|
||||
}
|
||||
|
||||
private void resetShape() {
|
||||
shape = null;
|
||||
autoWire = null;
|
||||
resetGeometry();
|
||||
}
|
||||
|
||||
@ -182,6 +189,19 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
||||
return shape;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this shape supports auto wire
|
||||
*/
|
||||
public boolean isAutoWireCompatible() {
|
||||
if (autoWire == null) {
|
||||
Shape shape = getShape();
|
||||
autoWire = !(shape instanceof DILShape || shape instanceof CustomShape || shape instanceof LayoutShape);
|
||||
if (autoWire)
|
||||
autoWire = shape.getPins().autoWireCompatible();
|
||||
}
|
||||
return autoWire;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTo(Graphic graphic, Style highLight) {
|
||||
drawShape(graphic, highLight);
|
||||
@ -196,7 +216,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
||||
}
|
||||
|
||||
private void drawShape(Graphic graphic, Style highLight) {
|
||||
Graphic gr = new GraphicTransform(graphic, createTransform());
|
||||
Graphic gr = new GraphicTransform(graphic, getTransform());
|
||||
Shape shape = getShape();
|
||||
shape.drawTo(gr, highLight);
|
||||
for (Pin p : shape.getPins())
|
||||
@ -204,7 +224,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
||||
p.getDirection() == Pin.Direction.input ? Style.WIRE : Style.WIRE_OUT);
|
||||
}
|
||||
|
||||
private Transform createTransform() {
|
||||
private Transform getTransform() {
|
||||
if (transform == null) {
|
||||
int rotate = getRotate();
|
||||
if (rotate == 0)
|
||||
@ -293,12 +313,12 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
||||
*/
|
||||
public Pins getPins() {
|
||||
Shape shape = getShape();
|
||||
Transform tr = createTransform();
|
||||
Transform tr = getTransform();
|
||||
Pins pins = shape.getPins();
|
||||
Pins transformed = new Pins();
|
||||
Pins transformedPins = new Pins();
|
||||
for (Pin p : pins)
|
||||
transformed.add(new Pin(tr.transform(p.getPos()), p).setVisualElement(this));
|
||||
return transformed;
|
||||
transformedPins.add(new Pin(tr.transform(p.getPos()), p).setVisualElement(this));
|
||||
return transformedPins;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -311,7 +331,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
||||
this.ioState = ioState;
|
||||
if (ioState == null) {
|
||||
interactor = null;
|
||||
shape = null;
|
||||
resetShape();
|
||||
} else
|
||||
interactor = getShape().applyStateMonitor(ioState, guiObserver);
|
||||
}
|
||||
@ -379,7 +399,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
||||
*/
|
||||
public boolean elementDragged(CircuitComponent cc, Point pos, Vector posInComponent, SyncAccess modelSync) {
|
||||
if (interactor != null)
|
||||
return interactor.dragged(cc, posInComponent, transform, ioState, element, modelSync);
|
||||
return interactor.dragged(cc, posInComponent, getTransform(), ioState, element, modelSync);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ public interface Shape extends Drawable, ObservableValueReader {
|
||||
* Puts the pins name and the pins x-y-position together!
|
||||
* This information is used to calculate the models connections from the wiring in the circuit.
|
||||
* Don't create your own {@link de.neemann.digital.core.element.PinInfo} instance! Try to use
|
||||
* the instances passed to the constructor of the shape via the {@link ShapeFactory}s {@link ShapeFactory#Creator} interface.
|
||||
* the instances passed to the constructor of the shape via the {@link ShapeFactory}s {@link ShapeFactory.Creator} interface.
|
||||
*
|
||||
* @return the pins
|
||||
*/
|
||||
|
@ -250,7 +250,7 @@ public final class ShapeFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new shape
|
||||
* Creates a new shape
|
||||
*/
|
||||
public interface Creator {
|
||||
/**
|
||||
|
@ -15,8 +15,8 @@ import de.neemann.digital.core.io.InValue;
|
||||
import de.neemann.digital.core.io.Out;
|
||||
import de.neemann.digital.core.switching.Switch;
|
||||
import de.neemann.digital.draw.elements.*;
|
||||
import de.neemann.digital.draw.graphics.*;
|
||||
import de.neemann.digital.draw.graphics.Vector;
|
||||
import de.neemann.digital.draw.graphics.*;
|
||||
import de.neemann.digital.draw.library.ElementLibrary;
|
||||
import de.neemann.digital.draw.library.ElementNotFoundException;
|
||||
import de.neemann.digital.draw.library.LibraryListener;
|
||||
@ -42,8 +42,8 @@ import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
|
||||
import static de.neemann.digital.draw.shapes.GenericShape.SIZE2;
|
||||
@ -1457,8 +1457,10 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
|
||||
|
||||
@Override
|
||||
void clicked(MouseEvent e) {
|
||||
if (mouse.isPrimaryClick(e) && !isLocked())
|
||||
if (mouse.isPrimaryClick(e) && !isLocked()) {
|
||||
modify(new ModifyInsertElement(element));
|
||||
insertWires(element);
|
||||
}
|
||||
mouseNormal.activate();
|
||||
focusWasLost = false;
|
||||
}
|
||||
@ -1476,6 +1478,37 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
|
||||
|
||||
}
|
||||
|
||||
private void insertWires(VisualElement element) {
|
||||
if (element.isAutoWireCompatible()) {
|
||||
Modifications.Builder wires = new Modifications.Builder(Lang.get("lib_wires"));
|
||||
for (Pin p : element.getPins())
|
||||
insertWirePin(p, element.getRotate(), wires);
|
||||
modify(wires.build());
|
||||
}
|
||||
}
|
||||
|
||||
private void insertWirePin(Pin p, int rotate, Modifications.Builder wires) {
|
||||
TransformRotate tr = new TransformRotate(new Vector(0, 0), rotate);
|
||||
Vector pos = new Vector(-SIZE, 0);
|
||||
if (p.getDirection() != PinDescription.Direction.input)
|
||||
pos = new Vector(SIZE, 0);
|
||||
|
||||
pos = tr.transform(pos);
|
||||
pos = pos.add(p.getPos());
|
||||
boolean found = false;
|
||||
List<VisualElement> el = circuit.getElementListAt(pos, false);
|
||||
for (VisualElement ve : el) {
|
||||
final Pin pinAt = circuit.getPinAt(pos, ve);
|
||||
if (pinAt != null && pinAt.getPos().equals(pos)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
wires.add(new ModifyInsertWire(new Wire(pos, p.getPos())));
|
||||
}
|
||||
|
||||
|
||||
private final class MouseControllerMoveElement extends MouseController {
|
||||
private VisualElement visualElement;
|
||||
private Vector delta;
|
||||
@ -1505,8 +1538,10 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
|
||||
if (!isLocked()) {
|
||||
visualElement.setPos(raster(visualElement.getPos()));
|
||||
if (!visualElement.getPos().equals(initialPos)
|
||||
|| visualElement.getRotate() != initialRot)
|
||||
|| visualElement.getRotate() != initialRot) {
|
||||
addModificationAlreadyMade(new ModifyMoveAndRotElement(visualElement, initialPos));
|
||||
insertWires(visualElement);
|
||||
}
|
||||
normalEnd = true;
|
||||
}
|
||||
mouseNormal.activate();
|
||||
|
@ -338,6 +338,18 @@ public class TestInGUI extends TestCase {
|
||||
.execute();
|
||||
}
|
||||
|
||||
public void testAutoWire() {
|
||||
new GuiTester()
|
||||
.add(new DrawCircuit("dig/autoWire.dig"))
|
||||
.press("F8")
|
||||
.delay(500)
|
||||
.add(new GuiTester.CheckTextInWindow<>(ValueTableDialog.class, Lang.get("msg_test_N_Passed", "")))
|
||||
.add(new GuiTester.CheckTableRows<>(ValueTableDialog.class, 4))
|
||||
.add(new GuiTester.CloseTopMost())
|
||||
.add(new GuiTester.CloseTopMost())
|
||||
.execute();
|
||||
}
|
||||
|
||||
public void testDraw() {
|
||||
new GuiTester()
|
||||
.add(new DrawCircuit("../../main/dig/sequential/JK-MS.dig"))
|
||||
|
75
src/test/resources/dig/autoWire.dig
Normal file
75
src/test/resources/dig/autoWire.dig
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<circuit>
|
||||
<version>1</version>
|
||||
<attributes/>
|
||||
<visualElements>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>A</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="380" y="140"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>In</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>B</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="380" y="180"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Not</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="400" y="140"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Not</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="400" y="180"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>And</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="460" y="140"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Not</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="540" y="160"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Out</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Label</string>
|
||||
<string>Y</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="600" y="160"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Testcase</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>Testdata</string>
|
||||
<testData>
|
||||
<dataString>A B Y
|
||||
0 0 0
|
||||
0 1 1
|
||||
1 0 1
|
||||
1 1 1</dataString>
|
||||
</testData>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="440" y="220"/>
|
||||
</visualElement>
|
||||
</visualElements>
|
||||
<wires/>
|
||||
<measurementOrdering/>
|
||||
</circuit>
|
Loading…
x
Reference in New Issue
Block a user