mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-16 16:34:47 -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.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of pins
|
* A list of pins
|
||||||
*/
|
*/
|
||||||
@ -90,4 +92,16 @@ public class Pins implements Iterable<Pin> {
|
|||||||
public Pin get(int index) {
|
public Pin get(int index) {
|
||||||
return allPins.get(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.graphics.*;
|
||||||
import de.neemann.digital.draw.shapes.*;
|
import de.neemann.digital.draw.shapes.*;
|
||||||
import de.neemann.digital.draw.shapes.Shape;
|
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.digital.gui.components.CircuitComponent;
|
||||||
import de.neemann.gui.Screen;
|
import de.neemann.gui.Screen;
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
|||||||
private transient Element element;
|
private transient Element element;
|
||||||
// shape is set to null and recreated if needed if attributes are changed
|
// shape is set to null and recreated if needed if attributes are changed
|
||||||
private transient Shape shape;
|
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!
|
// shapes are recreated if attributes are changed, therefore a factory is necessary and not only a simple shape!
|
||||||
private transient ShapeFactory shapeFactory;
|
private transient ShapeFactory shapeFactory;
|
||||||
private transient Transform transform;
|
private transient Transform transform;
|
||||||
@ -102,7 +104,12 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attributeChanged() {
|
public void attributeChanged() {
|
||||||
|
resetShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetShape() {
|
||||||
shape = null;
|
shape = null;
|
||||||
|
autoWire = null;
|
||||||
resetGeometry();
|
resetGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +189,19 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
|||||||
return shape;
|
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
|
@Override
|
||||||
public void drawTo(Graphic graphic, Style highLight) {
|
public void drawTo(Graphic graphic, Style highLight) {
|
||||||
drawShape(graphic, highLight);
|
drawShape(graphic, highLight);
|
||||||
@ -196,7 +216,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void drawShape(Graphic graphic, Style highLight) {
|
private void drawShape(Graphic graphic, Style highLight) {
|
||||||
Graphic gr = new GraphicTransform(graphic, createTransform());
|
Graphic gr = new GraphicTransform(graphic, getTransform());
|
||||||
Shape shape = getShape();
|
Shape shape = getShape();
|
||||||
shape.drawTo(gr, highLight);
|
shape.drawTo(gr, highLight);
|
||||||
for (Pin p : shape.getPins())
|
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);
|
p.getDirection() == Pin.Direction.input ? Style.WIRE : Style.WIRE_OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Transform createTransform() {
|
private Transform getTransform() {
|
||||||
if (transform == null) {
|
if (transform == null) {
|
||||||
int rotate = getRotate();
|
int rotate = getRotate();
|
||||||
if (rotate == 0)
|
if (rotate == 0)
|
||||||
@ -293,12 +313,12 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
|||||||
*/
|
*/
|
||||||
public Pins getPins() {
|
public Pins getPins() {
|
||||||
Shape shape = getShape();
|
Shape shape = getShape();
|
||||||
Transform tr = createTransform();
|
Transform tr = getTransform();
|
||||||
Pins pins = shape.getPins();
|
Pins pins = shape.getPins();
|
||||||
Pins transformed = new Pins();
|
Pins transformedPins = new Pins();
|
||||||
for (Pin p : pins)
|
for (Pin p : pins)
|
||||||
transformed.add(new Pin(tr.transform(p.getPos()), p).setVisualElement(this));
|
transformedPins.add(new Pin(tr.transform(p.getPos()), p).setVisualElement(this));
|
||||||
return transformed;
|
return transformedPins;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -311,7 +331,7 @@ public class VisualElement implements Drawable, Movable, AttributeListener {
|
|||||||
this.ioState = ioState;
|
this.ioState = ioState;
|
||||||
if (ioState == null) {
|
if (ioState == null) {
|
||||||
interactor = null;
|
interactor = null;
|
||||||
shape = null;
|
resetShape();
|
||||||
} else
|
} else
|
||||||
interactor = getShape().applyStateMonitor(ioState, guiObserver);
|
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) {
|
public boolean elementDragged(CircuitComponent cc, Point pos, Vector posInComponent, SyncAccess modelSync) {
|
||||||
if (interactor != null)
|
if (interactor != null)
|
||||||
return interactor.dragged(cc, posInComponent, transform, ioState, element, modelSync);
|
return interactor.dragged(cc, posInComponent, getTransform(), ioState, element, modelSync);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ public interface Shape extends Drawable, ObservableValueReader {
|
|||||||
* Puts the pins name and the pins x-y-position together!
|
* 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.
|
* 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
|
* 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
|
* @return the pins
|
||||||
*/
|
*/
|
||||||
|
@ -250,7 +250,7 @@ public final class ShapeFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates a new shape
|
* Creates a new shape
|
||||||
*/
|
*/
|
||||||
public interface Creator {
|
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.io.Out;
|
||||||
import de.neemann.digital.core.switching.Switch;
|
import de.neemann.digital.core.switching.Switch;
|
||||||
import de.neemann.digital.draw.elements.*;
|
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.Vector;
|
||||||
|
import de.neemann.digital.draw.graphics.*;
|
||||||
import de.neemann.digital.draw.library.ElementLibrary;
|
import de.neemann.digital.draw.library.ElementLibrary;
|
||||||
import de.neemann.digital.draw.library.ElementNotFoundException;
|
import de.neemann.digital.draw.library.ElementNotFoundException;
|
||||||
import de.neemann.digital.draw.library.LibraryListener;
|
import de.neemann.digital.draw.library.LibraryListener;
|
||||||
@ -42,8 +42,8 @@ import java.awt.geom.Rectangle2D;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
|
import static de.neemann.digital.draw.shapes.GenericShape.SIZE;
|
||||||
import static de.neemann.digital.draw.shapes.GenericShape.SIZE2;
|
import static de.neemann.digital.draw.shapes.GenericShape.SIZE2;
|
||||||
@ -1457,8 +1457,10 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
void clicked(MouseEvent e) {
|
void clicked(MouseEvent e) {
|
||||||
if (mouse.isPrimaryClick(e) && !isLocked())
|
if (mouse.isPrimaryClick(e) && !isLocked()) {
|
||||||
modify(new ModifyInsertElement(element));
|
modify(new ModifyInsertElement(element));
|
||||||
|
insertWires(element);
|
||||||
|
}
|
||||||
mouseNormal.activate();
|
mouseNormal.activate();
|
||||||
focusWasLost = false;
|
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 final class MouseControllerMoveElement extends MouseController {
|
||||||
private VisualElement visualElement;
|
private VisualElement visualElement;
|
||||||
private Vector delta;
|
private Vector delta;
|
||||||
@ -1505,8 +1538,10 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
|
|||||||
if (!isLocked()) {
|
if (!isLocked()) {
|
||||||
visualElement.setPos(raster(visualElement.getPos()));
|
visualElement.setPos(raster(visualElement.getPos()));
|
||||||
if (!visualElement.getPos().equals(initialPos)
|
if (!visualElement.getPos().equals(initialPos)
|
||||||
|| visualElement.getRotate() != initialRot)
|
|| visualElement.getRotate() != initialRot) {
|
||||||
addModificationAlreadyMade(new ModifyMoveAndRotElement(visualElement, initialPos));
|
addModificationAlreadyMade(new ModifyMoveAndRotElement(visualElement, initialPos));
|
||||||
|
insertWires(visualElement);
|
||||||
|
}
|
||||||
normalEnd = true;
|
normalEnd = true;
|
||||||
}
|
}
|
||||||
mouseNormal.activate();
|
mouseNormal.activate();
|
||||||
|
@ -338,6 +338,18 @@ public class TestInGUI extends TestCase {
|
|||||||
.execute();
|
.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() {
|
public void testDraw() {
|
||||||
new GuiTester()
|
new GuiTester()
|
||||||
.add(new DrawCircuit("../../main/dig/sequential/JK-MS.dig"))
|
.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