private SVGIcon getIcon(int type) { SVGIcon ret = icons[type]; if (ret != null) { return ret; } else { String iconName = iconNames[type]; if (iconName == null) { return null; } else { ret = Icons.getIcon(iconName); if (ret == null) { iconNames[type] = null; } else { icons[type] = ret; } return ret; } } }
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 Icon getIcon() { return Icons.getIcon("drawrrct.gif"); }
public class SelectTool extends Tool { private static final Cursor selectCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); private static final Cursor rectSelectCursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); private static final Cursor moveCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR); private static final int IDLE = 0; private static final int MOVING = 1; private static final int RECT_SELECT = 2; private static final Icon toolIcon = Icons.getIcon("select.gif"); private static final Color COLOR_UNMATCHED = new Color(192, 0, 0); private static final Color COLOR_COMPUTING = new Color(96, 192, 96); private static final Color COLOR_RECT_SELECT = new Color(0, 64, 128, 255); private static final Color BACKGROUND_RECT_SELECT = new Color(192, 192, 255, 192); private static class MoveRequestHandler implements MoveRequestListener { private Canvas canvas; MoveRequestHandler(Canvas canvas) { this.canvas = canvas; } public void requestSatisfied(MoveGesture gesture, int dx, int dy) { clearCanvasMessage(canvas, dx, dy); } } private class Listener implements Selection.Listener { public void selectionChanged(Event event) { keyHandlers = null; } } private Location start; private int state; private int curDx; private int curDy; private boolean drawConnections; private MoveGesture moveGesture; private HashMap<Component, KeyConfigurator> keyHandlers; private HashSet<Selection> selectionsAdded; private Listener selListener; public SelectTool() { start = null; state = IDLE; selectionsAdded = new HashSet<Selection>(); selListener = new Listener(); keyHandlers = null; } @Override public boolean equals(Object other) { return other instanceof SelectTool; } @Override public int hashCode() { return SelectTool.class.hashCode(); } @Override public String getName() { return "Select Tool"; } @Override public String getDisplayName() { return Strings.get("selectTool"); } @Override public String getDescription() { return Strings.get("selectToolDesc"); } @Override public AttributeSet getAttributeSet(Canvas canvas) { return canvas.getSelection().getAttributeSet(); } @Override public boolean isAllDefaultValues(AttributeSet attrs, LogisimVersion ver) { return true; } @Override public void draw(Canvas canvas, ComponentDrawContext context) { Project proj = canvas.getProject(); int dx = curDx; int dy = curDy; if (state == MOVING) { proj.getSelection().drawGhostsShifted(context, dx, dy); MoveGesture gesture = moveGesture; if (gesture != null && drawConnections && (dx != 0 || dy != 0)) { MoveResult result = gesture.findResult(dx, dy); if (result != null) { Collection<Wire> wiresToAdd = result.getWiresToAdd(); Graphics g = context.getGraphics(); GraphicsUtil.switchToWidth(g, 3); g.setColor(Color.GRAY); for (Wire w : wiresToAdd) { Location loc0 = w.getEnd0(); Location loc1 = w.getEnd1(); g.drawLine(loc0.getX(), loc0.getY(), loc1.getX(), loc1.getY()); } GraphicsUtil.switchToWidth(g, 1); g.setColor(COLOR_UNMATCHED); for (Location conn : result.getUnconnectedLocations()) { int connX = conn.getX(); int connY = conn.getY(); g.fillOval(connX - 3, connY - 3, 6, 6); g.fillOval(connX + dx - 3, connY + dy - 3, 6, 6); } } } } else if (state == RECT_SELECT) { int left = start.getX(); int right = left + dx; if (left > right) { int i = left; left = right; right = i; } int top = start.getY(); int bot = top + dy; if (top > bot) { int i = top; top = bot; bot = i; } Graphics gBase = context.getGraphics(); int w = right - left - 1; int h = bot - top - 1; if (w > 2 && h > 2) { gBase.setColor(BACKGROUND_RECT_SELECT); gBase.fillRect(left + 1, top + 1, w - 1, h - 1); } Circuit circ = canvas.getCircuit(); Bounds bds = Bounds.create(left, top, right - left, bot - top); for (Component c : circ.getAllWithin(bds)) { Location cloc = c.getLocation(); Graphics gDup = gBase.create(); context.setGraphics(gDup); c.getFactory() .drawGhost(context, COLOR_RECT_SELECT, cloc.getX(), cloc.getY(), c.getAttributeSet()); gDup.dispose(); } gBase.setColor(COLOR_RECT_SELECT); GraphicsUtil.switchToWidth(gBase, 2); if (w < 0) w = 0; if (h < 0) h = 0; gBase.drawRect(left, top, w, h); } } @Override public void select(Canvas canvas) { Selection sel = canvas.getSelection(); if (!selectionsAdded.contains(sel)) { sel.addListener(selListener); } } @Override public void deselect(Canvas canvas) { moveGesture = null; } @Override public void mouseEntered(Canvas canvas, Graphics g, MouseEvent e) { canvas.requestFocusInWindow(); } @Override public void mousePressed(Canvas canvas, Graphics g, MouseEvent e) { Project proj = canvas.getProject(); Selection sel = proj.getSelection(); Circuit circuit = canvas.getCircuit(); start = Location.create(e.getX(), e.getY()); curDx = 0; curDy = 0; moveGesture = null; // if the user clicks into the selection, // selection is being modified Collection<Component> in_sel = sel.getComponentsContaining(start, g); if (!in_sel.isEmpty()) { if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) { setState(proj, MOVING); proj.repaintCanvas(); return; } else { Action act = SelectionActions.drop(sel, in_sel); if (act != null) { proj.doAction(act); } } } // if the user clicks into a component outside selection, user // wants to add/reset selection Collection<Component> clicked = circuit.getAllContaining(start, g); if (!clicked.isEmpty()) { if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) { if (sel.getComponentsContaining(start).isEmpty()) { Action act = SelectionActions.dropAll(sel); if (act != null) { proj.doAction(act); } } } for (Component comp : clicked) { if (!in_sel.contains(comp)) { sel.add(comp); } } setState(proj, MOVING); proj.repaintCanvas(); return; } // The user clicked on the background. This is a rectangular // selection (maybe with the shift key down). if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) { Action act = SelectionActions.dropAll(sel); if (act != null) { proj.doAction(act); } } setState(proj, RECT_SELECT); proj.repaintCanvas(); } @Override public void mouseDragged(Canvas canvas, Graphics g, MouseEvent e) { if (state == MOVING) { Project proj = canvas.getProject(); computeDxDy(proj, e, g); handleMoveDrag(canvas, curDx, curDy, e.getModifiersEx()); } else if (state == RECT_SELECT) { Project proj = canvas.getProject(); curDx = e.getX() - start.getX(); curDy = e.getY() - start.getY(); proj.repaintCanvas(); } } private void handleMoveDrag(Canvas canvas, int dx, int dy, int modsEx) { boolean connect = shouldConnect(canvas, modsEx); drawConnections = connect; if (connect) { MoveGesture gesture = moveGesture; if (gesture == null) { gesture = new MoveGesture( new MoveRequestHandler(canvas), canvas.getCircuit(), canvas.getSelection().getAnchoredComponents()); moveGesture = gesture; } if (dx != 0 || dy != 0) { boolean queued = gesture.enqueueRequest(dx, dy); if (queued) { canvas.setErrorMessage(new ComputingMessage(dx, dy), COLOR_COMPUTING); // maybe CPU scheduled led the request to be satisfied // just before the "if(queued)" statement. In any case, it // doesn't hurt to check to ensure the message belongs. if (gesture.findResult(dx, dy) != null) { clearCanvasMessage(canvas, dx, dy); } } } } canvas.repaint(); } private boolean shouldConnect(Canvas canvas, int modsEx) { boolean shiftReleased = (modsEx & MouseEvent.SHIFT_DOWN_MASK) == 0; boolean dflt = AppPreferences.MOVE_KEEP_CONNECT.getBoolean(); if (shiftReleased) { return dflt; } else { return !dflt; } } @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(); } } @Override public void keyPressed(Canvas canvas, KeyEvent e) { if (state == MOVING && e.getKeyCode() == KeyEvent.VK_SHIFT) { handleMoveDrag(canvas, curDx, curDy, e.getModifiersEx()); } else { switch (e.getKeyCode()) { case KeyEvent.VK_BACK_SPACE: case KeyEvent.VK_DELETE: if (!canvas.getSelection().isEmpty()) { Action act = SelectionActions.clear(canvas.getSelection()); canvas.getProject().doAction(act); e.consume(); } break; default: processKeyEvent(canvas, e, KeyConfigurationEvent.KEY_PRESSED); } } } @Override public void keyReleased(Canvas canvas, KeyEvent e) { if (state == MOVING && e.getKeyCode() == KeyEvent.VK_SHIFT) { handleMoveDrag(canvas, curDx, curDy, e.getModifiersEx()); } else { processKeyEvent(canvas, e, KeyConfigurationEvent.KEY_RELEASED); } } @Override public void keyTyped(Canvas canvas, KeyEvent e) { processKeyEvent(canvas, e, KeyConfigurationEvent.KEY_TYPED); } 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); } } } } private void computeDxDy(Project proj, MouseEvent e, Graphics g) { Bounds bds = proj.getSelection().getBounds(g); int dx; int dy; if (bds == Bounds.EMPTY_BOUNDS) { dx = e.getX() - start.getX(); dy = e.getY() - start.getY(); } else { dx = Math.max(e.getX() - start.getX(), -bds.getX()); dy = Math.max(e.getY() - start.getY(), -bds.getY()); } Selection sel = proj.getSelection(); if (sel.shouldSnap()) { dx = Canvas.snapXToGrid(dx); dy = Canvas.snapYToGrid(dy); } curDx = dx; curDy = dy; } @Override public void paintIcon(ComponentDrawContext c, int x, int y) { Graphics g = c.getGraphics(); if (toolIcon != null) { toolIcon.paintIcon(c.getDestination(), g, x + 2, y + 2); } else { int[] xp = {x + 5, x + 5, x + 9, x + 12, x + 14, x + 11, x + 16}; int[] yp = {y, y + 17, y + 12, y + 18, y + 18, y + 12, y + 12}; g.setColor(java.awt.Color.black); g.fillPolygon(xp, yp, xp.length); } } @Override public Cursor getCursor() { return state == IDLE ? selectCursor : (state == RECT_SELECT ? rectSelectCursor : moveCursor); } @Override public Set<Component> getHiddenComponents(Canvas canvas) { if (state == MOVING) { int dx = curDx; int dy = curDy; if (dx == 0 && dy == 0) { return null; } Set<Component> sel = canvas.getSelection().getComponents(); MoveGesture gesture = moveGesture; if (gesture != null && drawConnections) { MoveResult result = gesture.findResult(dx, dy); if (result != null) { HashSet<Component> ret = new HashSet<Component>(sel); ret.addAll(result.getReplacementMap().getRemovals()); return ret; } } return sel; } else { return null; } } private void setState(Project proj, int new_state) { if (state == new_state) return; // do nothing if state not new state = new_state; proj.getFrame().getCanvas().setCursor(getCursor()); } private static void clearCanvasMessage(Canvas canvas, int dx, int dy) { Object getter = canvas.getErrorMessage(); if (getter instanceof ComputingMessage) { ComputingMessage msg = (ComputingMessage) getter; if (msg.dx == dx && msg.dy == dy) { canvas.setErrorMessage(null); canvas.repaint(); } } } private static class ComputingMessage implements StringGetter { private int dx; private int dy; public ComputingMessage(int dx, int dy) { this.dx = dx; this.dy = dy; } public String get() { return Strings.get("moveWorkingMsg"); } } }
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(); } }