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); }
@Override public void mouseReleased(Canvas canvas, Graphics g, MouseEvent e) { Project proj = canvas.getProject(); if (state == MOVING) { setState(proj, IDLE); computeDxDy(proj, e, g); int dx = curDx; int dy = curDy; if (dx != 0 || dy != 0) { if (!proj.getLogisimFile().contains(canvas.getCircuit())) { canvas.setErrorMessage(Strings.getter("cannotModifyError")); } else if (proj.getSelection().hasConflictWhenMoved(dx, dy)) { canvas.setErrorMessage(Strings.getter("exclusiveError")); } else { boolean connect = shouldConnect(canvas, e.getModifiersEx()); drawConnections = false; ReplacementMap repl; if (connect) { MoveGesture gesture = moveGesture; if (gesture == null) { gesture = new MoveGesture( new MoveRequestHandler(canvas), canvas.getCircuit(), canvas.getSelection().getAnchoredComponents()); } canvas.setErrorMessage(new ComputingMessage(dx, dy), COLOR_COMPUTING); MoveResult result = gesture.forceRequest(dx, dy); clearCanvasMessage(canvas, dx, dy); repl = result.getReplacementMap(); } else { repl = null; } Selection sel = proj.getSelection(); proj.doAction(SelectionActions.translate(sel, dx, dy, repl)); } } moveGesture = null; proj.repaintCanvas(); } else if (state == RECT_SELECT) { Bounds bds = Bounds.create(start).add(start.getX() + curDx, start.getY() + curDy); Circuit circuit = canvas.getCircuit(); Selection sel = proj.getSelection(); Collection<Component> in_sel = sel.getComponentsWithin(bds, g); for (Component comp : circuit.getAllWithin(bds, g)) { if (!in_sel.contains(comp)) sel.add(comp); } Action act = SelectionActions.drop(sel, in_sel); if (act != null) { proj.doAction(act); } setState(proj, IDLE); proj.repaintCanvas(); } }
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); }
public class Memory extends Library { protected static final int DELAY = 5; private static FactoryDescription[] DESCRIPTIONS = { new FactoryDescription( "D Flip-Flop", Strings.getter("dFlipFlopComponent"), "dFlipFlop.gif", "DFlipFlop"), new FactoryDescription( "T Flip-Flop", Strings.getter("tFlipFlopComponent"), "tFlipFlop.gif", "TFlipFlop"), new FactoryDescription( "J-K Flip-Flop", Strings.getter("jkFlipFlopComponent"), "jkFlipFlop.gif", "JKFlipFlop"), new FactoryDescription( "S-R Flip-Flop", Strings.getter("srFlipFlopComponent"), "srFlipFlop.gif", "SRFlipFlop"), new FactoryDescription( "Register", Strings.getter("registerComponent"), "register.gif", "Register"), new FactoryDescription("Counter", Strings.getter("counterComponent"), "counter.gif", "Counter"), new FactoryDescription( "Shift Register", Strings.getter("shiftRegisterComponent"), "shiftreg.gif", "ShiftRegister"), new FactoryDescription("Random", Strings.getter("randomComponent"), "random.gif", "Random"), new FactoryDescription("RAM", Strings.getter("ramComponent"), "ram.gif", "Ram"), new FactoryDescription("ROM", Strings.getter("romComponent"), "rom.gif", "Rom"), }; private List<Tool> tools = null; public Memory() {} @Override public String getName() { return "Memory"; } @Override public String getDisplayName() { return Strings.get("memoryLibrary"); } @Override public List<Tool> getTools() { if (tools == null) { tools = FactoryDescription.getTools(Memory.class, DESCRIPTIONS); } return tools; } }
public Ground() { super("Ground", Strings.getter("groundComponent")); setIconName("ground.gif"); setAttributes( new Attribute[] {StdAttr.FACING, StdAttr.WIDTH}, new Object[] {Direction.SOUTH, BitWidth.ONE}); setFacingAttribute(StdAttr.FACING); setKeyConfigurator(new BitWidthConfigurator(StdAttr.WIDTH)); setPorts(new Port[] {new Port(0, 0, Port.OUTPUT, StdAttr.WIDTH)}); }
public void editingStopped(CaretEvent e) { if (e.getCaret() != caret) { e.getCaret().removeCaretListener(this); return; } caret.removeCaretListener(this); caretCircuit.removeCircuitListener(this); String val = caret.getText(); boolean isEmpty = (val == null || val.equals("")); Action a; Project proj = caretCanvas.getProject(); if (caretCreatingText) { if (!isEmpty) { CircuitMutation xn = new CircuitMutation(caretCircuit); xn.add(caretComponent); a = xn.toAction(Strings.getter("addComponentAction", Text.FACTORY.getDisplayGetter())); } else { a = null; // don't add the blank text field } } else { if (isEmpty && caretComponent.getFactory() instanceof Text) { CircuitMutation xn = new CircuitMutation(caretCircuit); xn.add(caretComponent); a = xn.toAction(Strings.getter("removeComponentAction", Text.FACTORY.getDisplayGetter())); } else { Object obj = caretComponent.getFeature(TextEditable.class); if (obj == null) { // should never happen a = null; } else { TextEditable editable = (TextEditable) obj; a = editable.getCommitAction(caretCircuit, e.getOldText(), e.getText()); } } } caretCircuit = null; caretComponent = null; caretCreatingText = false; caret = null; if (a != null) proj.doAction(a); }
private void processKeyEvent(Canvas canvas, KeyEvent e, int type) { HashMap<Component, KeyConfigurator> handlers = keyHandlers; if (handlers == null) { handlers = new HashMap<Component, KeyConfigurator>(); Selection sel = canvas.getSelection(); for (Component comp : sel.getComponents()) { ComponentFactory factory = comp.getFactory(); AttributeSet attrs = comp.getAttributeSet(); Object handler = factory.getFeature(KeyConfigurator.class, attrs); if (handler != null) { KeyConfigurator base = (KeyConfigurator) handler; handlers.put(comp, base.clone()); } } keyHandlers = handlers; } if (!handlers.isEmpty()) { boolean consume = false; ArrayList<KeyConfigurationResult> results; results = new ArrayList<KeyConfigurationResult>(); for (Map.Entry<Component, KeyConfigurator> entry : handlers.entrySet()) { Component comp = entry.getKey(); KeyConfigurator handler = entry.getValue(); KeyConfigurationEvent event = new KeyConfigurationEvent(type, comp.getAttributeSet(), e, comp); KeyConfigurationResult result = handler.keyEventReceived(event); consume |= event.isConsumed(); if (result != null) { results.add(result); } } if (consume) { e.consume(); } if (!results.isEmpty()) { SetAttributeAction act = new SetAttributeAction( canvas.getCircuit(), Strings.getter("changeComponentAttributesAction")); for (KeyConfigurationResult result : results) { Component comp = (Component) result.getEvent().getData(); Map<Attribute<?>, Object> newValues = result.getAttributeValues(); for (Map.Entry<Attribute<?>, Object> entry : newValues.entrySet()) { act.set(comp, entry.getKey(), entry.getValue()); } } if (!act.isEmpty()) { canvas.getProject().doAction(act); } } } }
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)); }
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)); }
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); } }
@Override public void mousePressed(Canvas canvas, Graphics g, MouseEvent e) { Project proj = canvas.getProject(); Circuit circ = canvas.getCircuit(); if (!proj.getLogisimFile().contains(circ)) { if (caret != null) caret.cancelEditing(); canvas.setErrorMessage(Strings.getter("cannotModifyError")); return; } // Maybe user is clicking within the current caret. if (caret != null) { if (caret.getBounds(g).contains(e.getX(), e.getY())) { // Yes caret.mousePressed(e); proj.repaintCanvas(); return; } else { // No. End the current caret. caret.stopEditing(); } } // caret will be null at this point // Otherwise search for a new caret. int x = e.getX(); int y = e.getY(); Location loc = Location.create(x, y); ComponentUserEvent event = new ComponentUserEvent(canvas, x, y); // First search in selection. for (Component comp : proj.getSelection().getComponentsContaining(loc, g)) { TextEditable editable = (TextEditable) comp.getFeature(TextEditable.class); if (editable != null) { caret = editable.getTextCaret(event); if (caret != null) { proj.getFrame().viewComponentAttributes(circ, comp); caretComponent = comp; caretCreatingText = false; break; } } } // Then search in circuit if (caret == null) { for (Component comp : circ.getAllContaining(loc, g)) { TextEditable editable = (TextEditable) comp.getFeature(TextEditable.class); if (editable != null) { caret = editable.getTextCaret(event); if (caret != null) { proj.getFrame().viewComponentAttributes(circ, comp); caretComponent = comp; caretCreatingText = false; break; } } } } // if nothing found, create a new label if (caret == null) { if (loc.getX() < 0 || loc.getY() < 0) return; AttributeSet copy = (AttributeSet) attrs.clone(); caretComponent = Text.FACTORY.createComponent(loc, copy); caretCreatingText = true; TextEditable editable = (TextEditable) caretComponent.getFeature(TextEditable.class); if (editable != null) { caret = editable.getTextCaret(event); proj.getFrame().viewComponentAttributes(circ, caretComponent); } } if (caret != null) { caretCanvas = canvas; caretCircuit = canvas.getCircuit(); caret.addCaretListener(listener); caretCircuit.addCircuitListener(listener); } proj.repaintCanvas(); }
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 + "]"; } }