public interface StdAttr { Attribute<Direction> FACING = Attributes.forDirection("facing", Strings.getter("stdFacingAttr")); Attribute<BitWidth> WIDTH = Attributes.forBitWidth("width", Strings.getter("stdDataWidthAttr")); AttributeOption TRIG_RISING = new AttributeOption("rising", Strings.getter("stdTriggerRising")); AttributeOption TRIG_FALLING = new AttributeOption("falling", Strings.getter("stdTriggerFalling")); AttributeOption TRIG_HIGH = new AttributeOption("high", Strings.getter("stdTriggerHigh")); AttributeOption TRIG_LOW = new AttributeOption("low", Strings.getter("stdTriggerLow")); Attribute<AttributeOption> TRIGGER = Attributes.forOption( "trigger", Strings.getter("stdTriggerAttr"), new AttributeOption[] {TRIG_RISING, TRIG_FALLING, TRIG_HIGH, TRIG_LOW}); Attribute<AttributeOption> EDGE_TRIGGER = Attributes.forOption( "trigger", Strings.getter("stdTriggerAttr"), new AttributeOption[] {TRIG_RISING, TRIG_FALLING}); Attribute<String> LABEL = Attributes.forString("label", Strings.getter("stdLabelAttr")); Attribute<Font> LABEL_FONT = Attributes.forFont("labelfont", Strings.getter("stdLabelFontAttr")); Font DEFAULT_LABEL_FONT = new Font("SansSerif", Font.PLAIN, 12); }
class NotGate extends InstanceFactory { public static final AttributeOption SIZE_NARROW = new AttributeOption(Integer.valueOf(20), Strings.getter("gateSizeNarrowOpt")); public static final AttributeOption SIZE_WIDE = new AttributeOption(Integer.valueOf(30), Strings.getter("gateSizeWideOpt")); public static final Attribute<AttributeOption> ATTR_SIZE = Attributes.forOption( "size", Strings.getter("gateSizeAttr"), new AttributeOption[] {SIZE_NARROW, SIZE_WIDE}); private static final String RECT_LABEL = "1"; private static final Icon toolIcon = Icons.getIcon("notGate.gif"); private static final Icon toolIconRect = Icons.getIcon("notGateRect.gif"); private static final Icon toolIconDin = Icons.getIcon("dinNotGate.gif"); public static InstanceFactory FACTORY = new NotGate(); private NotGate() { super("NOT Gate", Strings.getter("notGateComponent")); setAttributes( new Attribute[] { StdAttr.FACING, StdAttr.WIDTH, ATTR_SIZE, GateAttributes.ATTR_OUTPUT, StdAttr.LABEL, StdAttr.LABEL_FONT, }, new Object[] { Direction.EAST, BitWidth.ONE, SIZE_WIDE, GateAttributes.OUTPUT_01, "", StdAttr.DEFAULT_LABEL_FONT, }); setFacingAttribute(StdAttr.FACING); setKeyConfigurator(new BitWidthConfigurator(StdAttr.WIDTH)); } @Override public Bounds getOffsetBounds(AttributeSet attrs) { Object value = attrs.getValue(ATTR_SIZE); if (value == SIZE_NARROW) { Direction facing = attrs.getValue(StdAttr.FACING); if (facing == Direction.SOUTH) return Bounds.create(-9, -20, 18, 20); if (facing == Direction.NORTH) return Bounds.create(-9, 0, 18, 20); if (facing == Direction.WEST) return Bounds.create(0, -9, 20, 18); return Bounds.create(-20, -9, 20, 18); } else { Direction facing = attrs.getValue(StdAttr.FACING); if (facing == Direction.SOUTH) return Bounds.create(-9, -30, 18, 30); if (facing == Direction.NORTH) return Bounds.create(-9, 0, 18, 30); if (facing == Direction.WEST) return Bounds.create(0, -9, 30, 18); return Bounds.create(-30, -9, 30, 18); } } @Override public void propagate(InstanceState state) { Value in = state.getPort(1); Value out = in.not(); out = Buffer.repair(state, out); state.setPort(0, out, GateAttributes.DELAY); } // // methods for instances // @Override protected void configureNewInstance(Instance instance) { configurePorts(instance); instance.addAttributeListener(); String gateShape = AppPreferences.GATE_SHAPE.get(); configureLabel(instance, gateShape.equals(AppPreferences.SHAPE_RECTANGULAR), null); } @Override protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) { if (attr == ATTR_SIZE || attr == StdAttr.FACING) { instance.recomputeBounds(); configurePorts(instance); String gateShape = AppPreferences.GATE_SHAPE.get(); configureLabel(instance, gateShape.equals(AppPreferences.SHAPE_RECTANGULAR), null); } } private void configurePorts(Instance instance) { Object size = instance.getAttributeValue(ATTR_SIZE); Direction facing = instance.getAttributeValue(StdAttr.FACING); int dx = size == SIZE_NARROW ? -20 : -30; Port[] ports = new Port[2]; ports[0] = new Port(0, 0, Port.OUTPUT, StdAttr.WIDTH); Location out = Location.create(0, 0).translate(facing, dx); ports[1] = new Port(out.getX(), out.getY(), Port.INPUT, StdAttr.WIDTH); instance.setPorts(ports); } @Override protected Object getInstanceFeature(final Instance instance, Object key) { if (key == ExpressionComputer.class) { return new ExpressionComputer() { public void computeExpression(Map<Location, Expression> expressionMap) { Expression e = expressionMap.get(instance.getPortLocation(1)); if (e != null) { expressionMap.put(instance.getPortLocation(0), Expressions.not(e)); } } }; } return super.getInstanceFeature(instance, key); } // // painting methods // @Override public void paintIcon(InstancePainter painter) { Graphics g = painter.getGraphics(); g.setColor(Color.black); if (painter.getGateShape() == AppPreferences.SHAPE_RECTANGULAR) { if (toolIconRect != null) { toolIconRect.paintIcon(painter.getDestination(), g, 2, 2); } else { g.drawRect(0, 2, 16, 16); GraphicsUtil.drawCenteredText(g, RECT_LABEL, 8, 8); g.drawOval(16, 8, 4, 4); } } else if (painter.getGateShape() == AppPreferences.SHAPE_DIN40700) { if (toolIconDin != null) { toolIconDin.paintIcon(painter.getDestination(), g, 2, 2); } else { g.drawRect(0, 2, 16, 16); GraphicsUtil.drawCenteredText(g, RECT_LABEL, 8, 8); g.drawOval(16, 8, 4, 4); } } else { if (toolIcon != null) { toolIcon.paintIcon(painter.getDestination(), g, 2, 2); } else { int[] xp = new int[4]; int[] yp = new int[4]; xp[0] = 15; yp[0] = 10; xp[1] = 1; yp[1] = 3; xp[2] = 1; yp[2] = 17; xp[3] = 15; yp[3] = 10; g.drawPolyline(xp, yp, 4); g.drawOval(15, 8, 4, 4); } } } @Override public void paintGhost(InstancePainter painter) { paintBase(painter); } @Override public void paintInstance(InstancePainter painter) { painter.getGraphics().setColor(Color.BLACK); paintBase(painter); painter.drawPorts(); painter.drawLabel(); } private void paintBase(InstancePainter painter) { Graphics g = painter.getGraphics(); Direction facing = painter.getAttributeValue(StdAttr.FACING); Location loc = painter.getLocation(); int x = loc.getX(); int y = loc.getY(); g.translate(x, y); double rotate = 0.0; if (facing != null && facing != Direction.EAST && g instanceof Graphics2D) { rotate = -facing.toRadians(); ((Graphics2D) g).rotate(rotate); } Object shape = painter.getGateShape(); if (shape == AppPreferences.SHAPE_RECTANGULAR) { paintRectangularBase(g, painter); } else if (shape == AppPreferences.SHAPE_DIN40700) { int width = painter.getAttributeValue(ATTR_SIZE) == SIZE_NARROW ? 20 : 30; PainterDin.paintAnd(painter, width, 18, true); } else { PainterShaped.paintNot(painter); } if (rotate != 0.0) { ((Graphics2D) g).rotate(-rotate); } g.translate(-x, -y); } private void paintRectangularBase(Graphics g, InstancePainter painter) { GraphicsUtil.switchToWidth(g, 2); if (painter.getAttributeValue(ATTR_SIZE) == SIZE_NARROW) { g.drawRect(-20, -9, 14, 18); GraphicsUtil.drawCenteredText(g, RECT_LABEL, -13, 0); g.drawOval(-6, -3, 6, 6); } else { g.drawRect(-30, -9, 20, 18); GraphicsUtil.drawCenteredText(g, RECT_LABEL, -20, 0); g.drawOval(-10, -5, 9, 9); } GraphicsUtil.switchToWidth(g, 1); } static void configureLabel(Instance instance, boolean isRectangular, Location control) { Object facing = instance.getAttributeValue(StdAttr.FACING); Bounds bds = instance.getBounds(); int x; int y; int halign; if (facing == Direction.NORTH || facing == Direction.SOUTH) { x = bds.getX() + bds.getWidth() / 2 + 2; y = bds.getY() - 2; halign = TextField.H_LEFT; } else { // west or east y = isRectangular ? bds.getY() - 2 : bds.getY(); if (control != null && control.getY() == bds.getY()) { // the control line will get in the way x = control.getX() + 2; halign = TextField.H_LEFT; } else { x = bds.getX() + bds.getWidth() / 2; halign = TextField.H_CENTER; } } instance.setTextField(StdAttr.LABEL, StdAttr.LABEL_FONT, x, y, halign, TextField.V_BASELINE); } }
class GateAttributes extends AbstractAttributeSet { static final int MAX_INPUTS = 32; static final int DELAY = 1; static final AttributeOption SIZE_NARROW = new AttributeOption(Integer.valueOf(30), __("gateSizeNarrowOpt")); static final AttributeOption SIZE_MEDIUM = new AttributeOption(Integer.valueOf(50), __("gateSizeNormalOpt")); static final AttributeOption SIZE_WIDE = new AttributeOption(Integer.valueOf(70), __("gateSizeWideOpt")); public static final Attribute<AttributeOption> ATTR_SIZE = Attributes.forOption( "size", __("gateSizeAttr"), new AttributeOption[] {SIZE_NARROW, SIZE_MEDIUM, SIZE_WIDE}); public static final Attribute<Integer> ATTR_INPUTS = Attributes.forIntegerRange("inputs", __("gateInputsAttr"), 2, MAX_INPUTS); static final AttributeOption XOR_ONE = new AttributeOption("1", __("xorBehaviorOne")); static final AttributeOption XOR_ODD = new AttributeOption("odd", __("xorBehaviorOdd")); public static final Attribute<AttributeOption> ATTR_XOR = Attributes.forOption("xor", __("xorBehaviorAttr"), new AttributeOption[] {XOR_ONE, XOR_ODD}); static final AttributeOption OUTPUT_01 = new AttributeOption("01", __("gateOutput01")); static final AttributeOption OUTPUT_0Z = new AttributeOption("0Z", __("gateOutput0Z")); static final AttributeOption OUTPUT_Z1 = new AttributeOption("Z1", __("gateOutputZ1")); public static final Attribute<AttributeOption> ATTR_OUTPUT = Attributes.forOption( "out", __("gateOutputAttr"), new AttributeOption[] {OUTPUT_01, OUTPUT_0Z, OUTPUT_Z1}); Direction facing = Direction.EAST; BitWidth width = BitWidth.ONE; AttributeOption size = SIZE_NARROW; int inputs = 2; int negated = 0; AttributeOption out = OUTPUT_01; AttributeOption xorBehave; String label = ""; Font labelFont = StdAttr.DEFAULT_LABEL_FONT; GateAttributes(boolean isXor) { xorBehave = isXor ? XOR_ONE : null; } @Override protected void copyInto(AbstractAttributeSet dest) { // nothing to do ; } @Override public List<Attribute<?>> getAttributes() { return new GateAttributeList(this); } @Override @SuppressWarnings("unchecked") public <V> V getValue(Attribute<V> attr) { if (attr == StdAttr.FACING) return (V) facing; if (attr == StdAttr.WIDTH) return (V) width; if (attr == StdAttr.LABEL) return (V) label; if (attr == StdAttr.LABEL_FONT) return (V) labelFont; if (attr == ATTR_SIZE) return (V) size; if (attr == ATTR_INPUTS) return (V) Integer.valueOf(inputs); if (attr == ATTR_OUTPUT) return (V) out; if (attr == ATTR_XOR) return (V) xorBehave; if (attr instanceof NegateAttribute) { int index = ((NegateAttribute) attr).index; int bit = (negated >> index) & 1; return (V) Boolean.valueOf(bit == 1); } return null; } @Override public <V> void setValue(Attribute<V> attr, V value) { if (attr == StdAttr.WIDTH) { width = (BitWidth) value; int bits = width.getWidth(); int mask = bits >= 32 ? -1 : ((1 << inputs) - 1); negated &= mask; } else if (attr == StdAttr.FACING) { facing = (Direction) value; } else if (attr == StdAttr.LABEL) { label = (String) value; } else if (attr == StdAttr.LABEL_FONT) { labelFont = (Font) value; } else if (attr == ATTR_SIZE) { size = (AttributeOption) value; } else if (attr == ATTR_INPUTS) { inputs = ((Integer) value).intValue(); fireAttributeListChanged(); } else if (attr == ATTR_XOR) { xorBehave = (AttributeOption) value; } else if (attr == ATTR_OUTPUT) { out = (AttributeOption) value; } else if (attr instanceof NegateAttribute) { int index = ((NegateAttribute) attr).index; if (((Boolean) value).booleanValue()) { negated |= 1 << index; } else { negated &= ~(1 << index); } } else { throw new IllegalArgumentException("unrecognized argument"); } fireAttributeValueChanged(attr, value); } }
public class PullResistor extends InstanceFactory { public static final Attribute<AttributeOption> ATTR_PULL_TYPE = Attributes.forOption( "pull", Strings.getter("pullTypeAttr"), new AttributeOption[] { new AttributeOption(Value.FALSE, "0", Strings.getter("pullZeroType")), new AttributeOption(Value.TRUE, "1", Strings.getter("pullOneType")), new AttributeOption(Value.ERROR, "X", Strings.getter("pullErrorType")) }); public static final PullResistor FACTORY = new PullResistor(); private static final Icon ICON_SHAPED = Icons.getIcon("pullshap.gif"); private static final Icon ICON_RECTANGULAR = Icons.getIcon("pullrect.gif"); public PullResistor() { super("Pull Resistor", Strings.getter("pullComponent")); setAttributes( new Attribute[] {StdAttr.FACING, ATTR_PULL_TYPE}, new Object[] {Direction.SOUTH, ATTR_PULL_TYPE.parse("0")}); setFacingAttribute(StdAttr.FACING); } @Override public Bounds getOffsetBounds(AttributeSet attrs) { Direction facing = attrs.getValue(StdAttr.FACING); if (facing == Direction.EAST) { return Bounds.create(-42, -6, 42, 12); } else if (facing == Direction.WEST) { return Bounds.create(0, -6, 42, 12); } else if (facing == Direction.NORTH) { return Bounds.create(-6, 0, 12, 42); } else { return Bounds.create(-6, -42, 12, 42); } } // // graphics methods // @Override public void paintIcon(InstancePainter painter) { Icon icon; if (painter.getGateShape() == AppPreferences.SHAPE_SHAPED) { icon = ICON_SHAPED; } else { icon = ICON_RECTANGULAR; } icon.paintIcon(painter.getDestination(), painter.getGraphics(), 2, 2); } @Override public void paintGhost(InstancePainter painter) { Value pull = getPullValue(painter.getAttributeSet()); paintBase(painter, pull, null, null); } @Override public void paintInstance(InstancePainter painter) { Location loc = painter.getLocation(); int x = loc.getX(); int y = loc.getY(); Graphics g = painter.getGraphics(); g.translate(x, y); Value pull = getPullValue(painter.getAttributeSet()); Value actual = painter.getPort(0); paintBase(painter, pull, pull.getColor(), actual.getColor()); g.translate(-x, -y); painter.drawPorts(); } private void paintBase(InstancePainter painter, Value pullValue, Color inColor, Color outColor) { boolean color = painter.shouldDrawColor(); Direction facing = painter.getAttributeValue(StdAttr.FACING); Graphics g = painter.getGraphics(); Color baseColor = g.getColor(); GraphicsUtil.switchToWidth(g, 3); if (color && inColor != null) g.setColor(inColor); if (facing == Direction.EAST) { GraphicsUtil.drawText( g, pullValue.toDisplayString(), -32, 0, GraphicsUtil.H_RIGHT, GraphicsUtil.V_CENTER); } else if (facing == Direction.WEST) { GraphicsUtil.drawText( g, pullValue.toDisplayString(), 32, 0, GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER); } else if (facing == Direction.NORTH) { GraphicsUtil.drawText( g, pullValue.toDisplayString(), 0, 32, GraphicsUtil.H_CENTER, GraphicsUtil.V_TOP); } else { GraphicsUtil.drawText( g, pullValue.toDisplayString(), 0, -32, GraphicsUtil.H_CENTER, GraphicsUtil.V_BASELINE); } double rotate = 0.0; if (g instanceof Graphics2D) { rotate = Direction.SOUTH.toRadians() - facing.toRadians(); if (rotate != 0.0) ((Graphics2D) g).rotate(rotate); } g.drawLine(0, -30, 0, -26); g.drawLine(-6, -30, 6, -30); if (color && outColor != null) g.setColor(outColor); g.drawLine(0, -4, 0, 0); g.setColor(baseColor); GraphicsUtil.switchToWidth(g, 2); if (painter.getGateShape() == AppPreferences.SHAPE_SHAPED) { int[] xp = {0, -5, 5, -5, 5, -5, 0}; int[] yp = {-25, -23, -19, -15, -11, -7, -5}; g.drawPolyline(xp, yp, xp.length); } else { g.drawRect(-5, -25, 10, 20); } if (rotate != 0.0) { ((Graphics2D) g).rotate(-rotate); } } // // methods for instances // @Override protected void configureNewInstance(Instance instance) { instance.addAttributeListener(); instance.setPorts(new Port[] {new Port(0, 0, Port.INOUT, BitWidth.UNKNOWN)}); } @Override protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) { if (attr == StdAttr.FACING) { instance.recomputeBounds(); } else if (attr == ATTR_PULL_TYPE) { instance.fireInvalidated(); } } @Override public void propagate(InstanceState state) { ; // nothing to do - handled by CircuitWires } public static Value getPullValue(Instance instance) { return getPullValue(instance.getAttributeSet()); } private static Value getPullValue(AttributeSet attrs) { AttributeOption opt = attrs.getValue(ATTR_PULL_TYPE); return (Value) opt.getValue(); } }
public class BitExtender extends InstanceFactory { private static final Attribute<BitWidth> ATTR_IN_WIDTH = Attributes.forBitWidth("in_width", Strings.getter("extenderInAttr")); private static final Attribute<BitWidth> ATTR_OUT_WIDTH = Attributes.forBitWidth("out_width", Strings.getter("extenderOutAttr")); static final Attribute<AttributeOption> ATTR_TYPE = Attributes.forOption( "type", Strings.getter("extenderTypeAttr"), new AttributeOption[] { new AttributeOption("zero", "zero", Strings.getter("extenderZeroType")), new AttributeOption("one", "one", Strings.getter("extenderOneType")), new AttributeOption("sign", "sign", Strings.getter("extenderSignType")), new AttributeOption("input", "input", Strings.getter("extenderInputType")), }); public static final BitExtender FACTORY = new BitExtender(); public BitExtender() { super("Bit Extender", Strings.getter("extenderComponent")); setIconName("extender.gif"); setAttributes( new Attribute[] {ATTR_IN_WIDTH, ATTR_OUT_WIDTH, ATTR_TYPE}, new Object[] {BitWidth.create(8), BitWidth.create(16), ATTR_TYPE.parse("sign")}); setFacingAttribute(StdAttr.FACING); setKeyConfigurator( JoinedConfigurator.create( new BitWidthConfigurator(ATTR_OUT_WIDTH), new BitWidthConfigurator(ATTR_IN_WIDTH, 1, Value.MAX_WIDTH, 0))); setOffsetBounds(Bounds.create(-40, -20, 40, 40)); } // // methods for instances // @Override protected void configureNewInstance(Instance instance) { configurePorts(instance); instance.addAttributeListener(); } private void configurePorts(Instance instance) { Port p0 = new Port(0, 0, Port.OUTPUT, ATTR_OUT_WIDTH); Port p1 = new Port(-40, 0, Port.INPUT, ATTR_IN_WIDTH); String type = getType(instance.getAttributeSet()); if (type.equals("input")) { instance.setPorts(new Port[] {p0, p1, new Port(-20, -20, Port.INPUT, 1)}); } else { instance.setPorts(new Port[] {p0, p1}); } } private String getType(AttributeSet attrs) { AttributeOption topt = attrs.getValue(ATTR_TYPE); return (String) topt.getValue(); } @Override public boolean HDLSupportedComponent(String HDLIdentifier, AttributeSet attrs, char Vendor) { if (MyHDLGenerator == null) MyHDLGenerator = new BitExtenderHDLGeneratorFactory(); return MyHDLGenerator.HDLTargetSupported(HDLIdentifier, attrs, Vendor); } @Override protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) { if (attr == ATTR_TYPE) { configurePorts(instance); instance.fireInvalidated(); } else { instance.fireInvalidated(); } } // // graphics methods // @Override public void paintInstance(InstancePainter painter) { Graphics g = painter.getGraphics(); FontMetrics fm = g.getFontMetrics(); int asc = fm.getAscent(); painter.drawBounds(); String s0; String type = getType(painter.getAttributeSet()); if (type.equals("zero")) s0 = Strings.get("extenderZeroLabel"); else if (type.equals("one")) s0 = Strings.get("extenderOneLabel"); else if (type.equals("sign")) s0 = Strings.get("extenderSignLabel"); else if (type.equals("input")) s0 = Strings.get("extenderInputLabel"); else s0 = "???"; // should never happen String s1 = Strings.get("extenderMainLabel"); Bounds bds = painter.getBounds(); int x = bds.getX() + bds.getWidth() / 2; int y0 = bds.getY() + (bds.getHeight() / 2 + asc) / 2; int y1 = bds.getY() + (3 * bds.getHeight() / 2 + asc) / 2; GraphicsUtil.drawText(g, s0, x, y0, GraphicsUtil.H_CENTER, GraphicsUtil.V_BASELINE); GraphicsUtil.drawText(g, s1, x, y1, GraphicsUtil.H_CENTER, GraphicsUtil.V_BASELINE); BitWidth w0 = painter.getAttributeValue(ATTR_OUT_WIDTH); BitWidth w1 = painter.getAttributeValue(ATTR_IN_WIDTH); painter.drawPort(0, "" + w0.getWidth(), Direction.WEST); painter.drawPort(1, "" + w1.getWidth(), Direction.EAST); if (type.equals("input")) painter.drawPort(2); } @Override public void propagate(InstanceState state) { Value in = state.getPortValue(1); BitWidth wout = state.getAttributeValue(ATTR_OUT_WIDTH); String type = getType(state.getAttributeSet()); Value extend; if (type.equals("one")) { extend = Value.TRUE; } else if (type.equals("sign")) { int win = in.getWidth(); extend = win > 0 ? in.get(win - 1) : Value.ERROR; } else if (type.equals("input")) { extend = state.getPortValue(2); if (extend.getWidth() != 1) extend = Value.ERROR; } else { extend = Value.FALSE; } Value out = in.extendWidth(wout.getWidth(), extend); state.setPort(0, out, 1); } }
public final class Wire implements Component, AttributeSet, CustomHandles, Iterable<Location> { private class EndList extends AbstractList<EndData> { @Override public EndData get(int i) { return getEnd(i); } @Override public int size() { return 2; } } public static Wire create(Location e0, Location e1) { return (Wire) cache.get(new Wire(e0, e1)); } /** Stroke width when drawing wires. */ public static final int WIDTH = 3; public static final int WIDTH_BUS = 4; public static final int HIGHLIGHTED_WIDTH = 4; public static final int HIGHLIGHTED_WIDTH_BUS = 5; public static final double DOT_MULTIPLY_FACTOR = 1.35; /* multiply factor for the intersection points */ public static final AttributeOption VALUE_HORZ = new AttributeOption("horz", Strings.getter("wireDirectionHorzOption")); public static final AttributeOption VALUE_VERT = new AttributeOption("vert", Strings.getter("wireDirectionVertOption")); public static final Attribute<AttributeOption> dir_attr = Attributes.forOption( "direction", Strings.getter("wireDirectionAttr"), new AttributeOption[] {VALUE_HORZ, VALUE_VERT}); public static final Attribute<Integer> len_attr = Attributes.forInteger("length", Strings.getter("wireLengthAttr")); private static final List<Attribute<?>> ATTRIBUTES = Arrays.asList(new Attribute<?>[] {dir_attr, len_attr}); private static final Cache cache = new Cache(); final Location e0; final Location e1; final boolean is_x_equal; private boolean ShowAsMarked = false; private Color MarkColor = Netlist.DRC_WIRE_MARK_COLOR; private Wire(Location e0, Location e1) { this.is_x_equal = e0.getX() == e1.getX(); if (is_x_equal) { if (e0.getY() > e1.getY()) { this.e0 = e1; this.e1 = e0; } else { this.e0 = e0; this.e1 = e1; } } else { if (e0.getX() > e1.getX()) { this.e0 = e1; this.e1 = e0; } else { this.e0 = e0; this.e1 = e1; } } } public void SetMarked(boolean Mark) { ShowAsMarked = Mark; } public boolean IsSetAsMarked() { return ShowAsMarked; } public void SetMarkColor(Color col) { MarkColor = col; } public Color GetMarkColor() { return MarkColor; } public void addAttributeListener(AttributeListener l) {} // // Component methods // // (Wire never issues ComponentEvents, so we don't need to track listeners) public void addComponentListener(ComponentListener e) {} // // AttributeSet methods // // It makes some sense for a wire to be its own attribute, since // after all it is immutable. // @Override public Object clone() { return this; } public boolean contains(Location q) { int qx = q.getX(); int qy = q.getY(); if (is_x_equal) { int wx = e0.getX(); return qx >= wx - 2 && qx <= wx + 2 && e0.getY() <= qy && qy <= e1.getY(); } else { int wy = e0.getY(); return qy >= wy - 2 && qy <= wy + 2 && e0.getX() <= qx && qx <= e1.getX(); } } public boolean contains(Location pt, Graphics g) { return contains(pt); } public boolean containsAttribute(Attribute<?> attr) { return ATTRIBUTES.contains(attr); } public void draw(ComponentDrawContext context) { CircuitState state = context.getCircuitState(); Graphics g = context.getGraphics(); GraphicsUtil.switchToWidth(g, WIDTH); g.setColor(state.getValue(e0).getColor()); g.drawLine(e0.getX(), e0.getY(), e1.getX(), e1.getY()); } public void drawHandles(ComponentDrawContext context) { context.drawHandle(e0); context.drawHandle(e1); } public boolean endsAt(Location pt) { return e0.equals(pt) || e1.equals(pt); } @Override public boolean equals(Object other) { if (!(other instanceof Wire)) return false; Wire w = (Wire) other; return w.e0.equals(this.e0) && w.e1.equals(this.e1); } // // user interface methods // public void expose(ComponentDrawContext context) { java.awt.Component dest = context.getDestination(); int x0 = e0.getX(); int y0 = e0.getY(); dest.repaint(x0 - 5, y0 - 5, e1.getX() - x0 + 10, e1.getY() - y0 + 10); } public Attribute<?> getAttribute(String name) { for (Attribute<?> attr : ATTRIBUTES) { if (name.equals(attr.getName())) return attr; } return null; } public List<Attribute<?>> getAttributes() { return ATTRIBUTES; } public AttributeSet getAttributeSet() { return this; } public Bounds getBounds() { int x0 = e0.getX(); int y0 = e0.getY(); return Bounds.create(x0 - 2, y0 - 2, e1.getX() - x0 + 5, e1.getY() - y0 + 5); } public Bounds getBounds(Graphics g) { return getBounds(); } public EndData getEnd(int index) { Location loc = getEndLocation(index); return new EndData(loc, BitWidth.UNKNOWN, EndData.INPUT_OUTPUT); } public Location getEnd0() { return e0; } public Location getEnd1() { return e1; } public Location getEndLocation(int index) { return index == 0 ? e0 : e1; } // // propagation methods // public List<EndData> getEnds() { return new EndList(); } public ComponentFactory getFactory() { return WireFactory.instance; } public Object getFeature(Object key) { if (key == CustomHandles.class) return this; return null; } public int getLength() { return (e1.getY() - e0.getY()) + (e1.getX() - e0.getX()); } // location/extent methods public Location getLocation() { return e0; } public Location getOtherEnd(Location loc) { return (loc.equals(e0) ? e1 : e0); } @SuppressWarnings("unchecked") public <V> V getValue(Attribute<V> attr) { if (attr == dir_attr) { return (V) (is_x_equal ? VALUE_VERT : VALUE_HORZ); } else if (attr == len_attr) { return (V) Integer.valueOf(getLength()); } else { return null; } } @Override public int hashCode() { return e0.hashCode() * 31 + e1.hashCode(); } public boolean isParallel(Wire other) { return this.is_x_equal == other.is_x_equal; } public boolean isReadOnly(Attribute<?> attr) { return true; } public boolean isToSave(Attribute<?> attr) { return false; } // // other methods // public boolean isVertical() { return is_x_equal; } public Iterator<Location> iterator() { return new WireIterator(e0, e1); } private boolean overlaps(Location q0, Location q1, boolean includeEnds) { if (is_x_equal) { int x0 = q0.getX(); if (x0 != q1.getX() || x0 != e0.getX()) return false; if (includeEnds) { return e1.getY() >= q0.getY() && e0.getY() <= q1.getY(); } else { return e1.getY() > q0.getY() && e0.getY() < q1.getY(); } } else { int y0 = q0.getY(); if (y0 != q1.getY() || y0 != e0.getY()) return false; if (includeEnds) { return e1.getX() >= q0.getX() && e0.getX() <= q1.getX(); } else { return e1.getX() > q0.getX() && e0.getX() < q1.getX(); } } } public boolean overlaps(Wire other, boolean includeEnds) { return overlaps(other.e0, other.e1, includeEnds); } public void propagate(CircuitState state) { // Normally this is handled by CircuitWires, and so it won't get // called. The exception is when a wire is added or removed state.markPointAsDirty(e0); state.markPointAsDirty(e1); } public void removeAttributeListener(AttributeListener l) {} public void removeComponentListener(ComponentListener e) {} public void setReadOnly(Attribute<?> attr, boolean value) { throw new UnsupportedOperationException(); } public <V> void setValue(Attribute<V> attr, V value) { throw new IllegalArgumentException("read only attribute"); } public boolean sharesEnd(Wire other) { return this.e0.equals(other.e0) || this.e1.equals(other.e0) || this.e0.equals(other.e1) || this.e1.equals(other.e1); } @Override public String toString() { return "Wire[" + e0 + "-" + e1 + "]"; } }