Package com.cburch.logisim.std.gates

Source Code of com.cburch.logisim.std.gates.AbstractGate

/* Copyright (c) 2010, Carl Burch. License information is located in the
* com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */

package com.cburch.logisim.std.gates;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Map;

import javax.swing.Icon;

import com.cburch.draw.tools.SVGIcon;
import com.cburch.logisim.LogisimVersion;
import com.cburch.logisim.analyze.model.Expression;
import com.cburch.logisim.analyze.model.Expressions;
import com.cburch.logisim.circuit.ExpressionComputer;
import com.cburch.logisim.comp.TextField;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Direction;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.data.Value;
import com.cburch.logisim.file.Options;
import com.cburch.logisim.instance.Instance;
import com.cburch.logisim.instance.InstanceFactory;
import com.cburch.logisim.instance.InstancePainter;
import com.cburch.logisim.instance.InstanceState;
import com.cburch.logisim.instance.Port;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.prefs.AppPreferences;
import com.cburch.logisim.tools.WireRepair;
import com.cburch.logisim.tools.WireRepairData;
import com.cburch.logisim.tools.key.BitWidthConfigurator;
import com.cburch.logisim.tools.key.IntegerConfigurator;
import com.cburch.logisim.tools.key.JoinedConfigurator;
import com.cburch.logisim.util.GraphicsUtil;
import com.cburch.logisim.util.Icons;

abstract class AbstractGate extends InstanceFactory {
    private String[] iconNames = new String[3];
    private SVGIcon[] icons = new SVGIcon[3];
    private int bonusWidth = 0;
    private boolean negateOutput = false;
    private boolean isXor = false;
    private String rectLabel = "";
    private boolean paintInputLines;

    protected AbstractGate(String name, String desc) {
        this(name, desc, false);
    }

    protected AbstractGate(String name, String desc, boolean isXor) {
        super(name, desc);
        this.isXor = isXor;
        setFacingAttribute(StdAttr.FACING);
        setKeyConfigurator(JoinedConfigurator.create(
            new IntegerConfigurator(GateAttributes.ATTR_INPUTS, 2,
                    GateAttributes.MAX_INPUTS, 0),
            new BitWidthConfigurator(StdAttr.WIDTH)));
    }


    @Override
    public AttributeSet createAttributeSet() {
        return new GateAttributes(isXor);
    }

    @Override
    public Object getDefaultAttributeValue(Attribute<?> attr, LogisimVersion ver) {
        if (attr instanceof NegateAttribute) {
            return Boolean.FALSE;
        } else {
            return super.getDefaultAttributeValue(attr, ver);
        }
    }

    @Override
    public Bounds getOffsetBounds(AttributeSet attrsBase) {
        GateAttributes attrs = (GateAttributes) attrsBase;
        Direction facing = attrs.facing;
        int size = ((Integer) attrs.size.getValue()).intValue();
        int inputs = attrs.inputs;
        if (inputs % 2 == 0) {
            inputs++;
        }
        int negated = attrs.negated;

        int width = size + bonusWidth + (negateOutput ? 10 : 0);
        if (negated != 0) {
            width += 10;
        }
        int height = Math.max(10 * inputs, size);
        if (facing == Direction.SOUTH) {
            return Bounds.create(-height / 2, -width, height, width);
        } else if (facing == Direction.NORTH) {
            return Bounds.create(-height / 2, 0, height, width);
        } else if (facing == Direction.WEST) {
            return Bounds.create(0, -height / 2, width, height);
        } else {
            return Bounds.create(-width, -height / 2, width, height);
        }
    }

    @Override
    public boolean contains(Location loc, AttributeSet attrsBase) {
        GateAttributes attrs = (GateAttributes) attrsBase;
        if (super.contains(loc, attrs)) {
            if (attrs.negated == 0) {
                return true;
            } else {
                Direction facing = attrs.facing;
                Bounds bds = getOffsetBounds(attrsBase);
                int delt;
                if (facing == Direction.NORTH) {
                    delt = loc.getY() - (bds.getY() + bds.getHeight());
                } else if (facing == Direction.SOUTH) {
                    delt = loc.getY() - bds.getY();
                } else if (facing == Direction.WEST) {
                    delt = loc.getX() - (bds.getX() + bds.getHeight());
                } else {
                    delt = loc.getX() - bds.getX();
                }
                if (Math.abs(delt) > 5) {
                    return true;
                } else {
                    int inputs = attrs.inputs;
                    for (int i = 1; i <= inputs; i++) {
                        Location offs = getInputOffset(attrs, i);
                        if (loc.manhattanDistanceTo(offs) <= 5) {
                            return true;
                        }

                    }
                    return false;
                }
            }
        } else {
            return false;
        }
    }

    //
    // painting methods
    //
    @Override
    public void paintGhost(InstancePainter painter) {
        paintBase(painter);
    }

    @Override
    public void paintInstance(InstancePainter painter) {
        paintBase(painter);
        if (!painter.isPrintView() || painter.getGateShape() == AppPreferences.SHAPE_RECTANGULAR) {
            painter.drawPorts();
        }
    }

    private void paintBase(InstancePainter painter) {
        GateAttributes attrs = (GateAttributes) painter.getAttributeSet();
        Direction facing = attrs.facing;
        int inputs = attrs.inputs;
        int negated = attrs.negated;

        Object shape = painter.getGateShape();
        Location loc = painter.getLocation();
        Bounds bds = painter.getOffsetBounds();
        int width = bds.getWidth();
        int height = bds.getHeight();
        if (facing == Direction.NORTH || facing == Direction.SOUTH) {
            int t = width; width = height; height = t;
        }
        if (negated != 0) {
            width -= 10;
        }

        Graphics g = painter.getGraphics();
        Color baseColor = g.getColor();
        if (shape == AppPreferences.SHAPE_SHAPED && paintInputLines) {
            PainterShaped.paintInputLines(painter, this);
        } else if (negated != 0) {
            for (int i = 0; i < inputs; i++) {
                int negatedBit = (negated >> i) & 1;
                if (negatedBit == 1) {
                    Location in = getInputOffset(attrs, i);
                    Location cen = in.translate(facing, 5);
                    painter.drawDongle(loc.getX() + cen.getX(),
                            loc.getY() + cen.getY());
                }
            }
        }

        g.setColor(baseColor);
        g.translate(loc.getX(), loc.getY());
        double rotate = 0.0;
        if (facing != Direction.EAST && g instanceof Graphics2D) {
            rotate = -facing.toRadians();
            Graphics2D g2 = (Graphics2D) g;
            g2.rotate(rotate);
        }

        if (shape == AppPreferences.SHAPE_RECTANGULAR) {
            paintRectangular(painter, width, height);
        } else if (shape == AppPreferences.SHAPE_DIN40700) {
            paintDinShape(painter, width, height, inputs);
        // SHAPE_SHAPED
        } else {
            if (negateOutput) {
                g.translate(-10, 0);
                paintShape(painter, width - 10, height);
                painter.drawDongle(5, 0);
                g.translate(10, 0);
            } else {
                paintShape(painter, width, height);
            }
        }

        if (rotate != 0.0) {
            ((Graphics2D) g).rotate(-rotate);
        }
        g.translate(-loc.getX(), -loc.getY());

        painter.drawLabel();
    }

    protected void setIconNames(String all) {
        setIconNames(all, all, all);
    }

    protected void setIconNames(String shaped, String rect, String din) {
        iconNames[0] = shaped;
        iconNames[1] = rect;
        iconNames[2] = din;
    }

    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;
            }
        }
    }

    private Icon getIconShaped() {
        return getIcon(0);
    }

    private Icon getIconRectangular() {
        return getIcon(1);
    }

    private Icon getIconDin40700() {
        return getIcon(2);
    }

    protected void setPaintInputLines(boolean value) {
        paintInputLines = value;
    }

    protected abstract void paintIconShaped(InstancePainter painter);

    protected void paintIconRectangular(InstancePainter painter) {
        Graphics g = painter.getGraphics();
        g.drawRect(1, 2, 16, 16);
        if (negateOutput) {
            g.drawOval(16, 8, 4, 4);
        }

        String label = getRectangularLabel(painter.getAttributeSet());
        GraphicsUtil.drawCenteredText(g, label, 9, 8);
    }

    @Override
    public final void paintIcon(InstancePainter painter) {
        Graphics g = painter.getGraphics();
        g.setColor(Color.black);
        if (painter.getGateShape() == AppPreferences.SHAPE_RECTANGULAR) {
            Icon iconRect = getIconRectangular();
            if (iconRect != null) {
                iconRect.paintIcon(painter.getDestination(), g, 2, 2);
            } else {
                paintIconRectangular(painter);
            }
        } else if (painter.getGateShape() == AppPreferences.SHAPE_DIN40700) {
            Icon iconDin = getIconDin40700();
            if (iconDin != null) {
                iconDin.paintIcon(painter.getDestination(), g, 2, 2);
            } else {
                paintIconRectangular(painter);
            }
        } else {
            Icon iconShaped = getIconShaped();
            if (iconShaped != null) {
                iconShaped.paintIcon(painter.getDestination(), g, 2, 2);
            } else {
                paintIconShaped(painter);
            }
        }
    }

    protected void setAdditionalWidth(int value) {
        bonusWidth = value;
    }

    protected void setNegateOutput(boolean value) {
        negateOutput = value;
    }

    protected void setRectangularLabel(String value) {
        rectLabel = value;
    }

    protected String getRectangularLabel(AttributeSet attrs) {
        return rectLabel;
    }

    //
    // protected methods intended to be overridden
    //
    protected abstract Value getIdentity();

    protected abstract void paintShape(InstancePainter painter,
            int width, int height);

    protected void paintRectangular(InstancePainter painter,
            int width, int height) {
        int don = negateOutput ? 10 : 0;
        AttributeSet attrs = painter.getAttributeSet();
        painter.drawRectangle(-width, -height / 2, width - don, height,
                getRectangularLabel(attrs));
        if (negateOutput) {
            painter.drawDongle(-5, 0);
        }
    }

    protected abstract void paintDinShape(InstancePainter painter,
            int width, int height, int inputs);

    protected abstract Value computeOutput(Value[] inputs, int numInputs,
            InstanceState state);

    protected abstract Expression computeExpression(Expression[] inputs,
            int numInputs);

    protected boolean shouldRepairWire(Instance instance, WireRepairData data) {
        return false;
    }

    //
    // methods for instances
    //
    @Override
    protected void configureNewInstance(Instance instance) {
        instance.addAttributeListener();
        computePorts(instance);
        computeLabel(instance);
    }

    @Override
    protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) {
        if (attr == GateAttributes.ATTR_SIZE || attr == StdAttr.FACING) {
            instance.recomputeBounds();
            computePorts(instance);
            computeLabel(instance);
        } else if (attr == GateAttributes.ATTR_INPUTS
                || attr instanceof NegateAttribute) {
            instance.recomputeBounds();
            computePorts(instance);
        } else if (attr == GateAttributes.ATTR_XOR) {
            instance.fireInvalidated();
        }
    }

    private void computeLabel(Instance instance) {
        GateAttributes attrs = (GateAttributes) instance.getAttributeSet();
        Direction facing = attrs.facing;
        int baseWidth = ((Integer) attrs.size.getValue()).intValue();

        int axis = baseWidth / 2 + (negateOutput ? 10 : 0);
        int perp = 0;
        if (AppPreferences.GATE_SHAPE.get().equals(AppPreferences.SHAPE_RECTANGULAR)) {
            perp += 6;
        }
        Location loc = instance.getLocation();
        int cx;
        int cy;
        if (facing == Direction.NORTH) {
            cx = loc.getX() + perp;
            cy = loc.getY() + axis;
        } else if (facing == Direction.SOUTH) {
            cx = loc.getX() - perp;
            cy = loc.getY() - axis;
        } else if (facing == Direction.WEST) {
            cx = loc.getX() + axis;
            cy = loc.getY() - perp;
        } else {
            cx = loc.getX() - axis;
            cy = loc.getY() + perp;
        }
        instance.setTextField(StdAttr.LABEL, StdAttr.LABEL_FONT, cx, cy,
                TextField.H_CENTER, TextField.V_CENTER);
    }

    void computePorts(Instance instance) {
        GateAttributes attrs = (GateAttributes) instance.getAttributeSet();
        int inputs = attrs.inputs;

        Port[] ports = new Port[inputs + 1];
        ports[0] = new Port(0, 0, Port.OUTPUT, StdAttr.WIDTH);
        for (int i = 0; i < inputs; i++) {
            Location offs = getInputOffset(attrs, i);
            ports[i + 1] = new Port(offs.getX(), offs.getY(), Port.INPUT, StdAttr.WIDTH);
        }
        instance.setPorts(ports);
    }

    @Override
    public void propagate(InstanceState state) {
        GateAttributes attrs = (GateAttributes) state.getAttributeSet();
        int inputCount = attrs.inputs;
        int negated = attrs.negated;
        AttributeSet opts = state.getProject().getOptions().getAttributeSet();
        boolean errorIfUndefined = opts.getValue(Options.ATTR_GATE_UNDEFINED)
                                    .equals(Options.GATE_UNDEFINED_ERROR);

        Value[] inputs = new Value[inputCount];
        int numInputs = 0;
        boolean error = false;
        for (int i = 1; i <= inputCount; i++) {
            if (state.isPortConnected(i)) {
                int negatedBit = (negated >> (i - 1)) & 1;
                if (negatedBit == 1) {
                    inputs[numInputs] = state.getPort(i).not();
                } else {
                    inputs[numInputs] = state.getPort(i);
                }
                numInputs++;
            } else {
                if (errorIfUndefined) {
                    error = true;
                }
            }
        }
        Value out = null;
        if (numInputs == 0 || error) {
            out = Value.createError(attrs.width);
        } else {
            out = computeOutput(inputs, numInputs, state);
            out = pullOutput(out, attrs.out);
        }
        state.setPort(0, out, GateAttributes.DELAY);
    }

    static Value pullOutput(Value value, Object outType) {
        if (outType == GateAttributes.OUTPUT_01) {
            return value;
        } else {
            Value[] v = value.getAll();
            if (outType == GateAttributes.OUTPUT_0Z) {
                for (int i = 0; i < v.length; i++) {
                    if (v[i] == Value.TRUE) {
                        v[i] = Value.UNKNOWN;
                    }

                }
            } else if (outType == GateAttributes.OUTPUT_Z1) {
                for (int i = 0; i < v.length; i++) {
                    if (v[i] == Value.FALSE) {
                        v[i] = Value.UNKNOWN;
                    }

                }
            }
            return Value.create(v);
        }
    }

    @Override
    protected Object getInstanceFeature(final Instance instance, Object key) {
        if (key == WireRepair.class) {
            return new WireRepair() {
                @Override
                public boolean shouldRepairWire(WireRepairData data) {
                    return AbstractGate.this.shouldRepairWire(instance, data);
                }
            };
        }
        if (key == ExpressionComputer.class) {
            return new ExpressionComputer() {
                @Override
                public void computeExpression(Map<Location,Expression> expressionMap) {
                    GateAttributes attrs = (GateAttributes) instance.getAttributeSet();
                    int inputCount = attrs.inputs;
                    int negated = attrs.negated;

                    Expression[] inputs = new Expression[inputCount];
                    int numInputs = 0;
                    for (int i = 1; i <= inputCount; i++) {
                        Expression e = expressionMap.get(instance.getPortLocation(i));
                        if (e != null) {
                            int negatedBit = (negated >> (i - 1)) & 1;
                            if (negatedBit == 1) {
                                e = Expressions.not(e);
                            }
                            inputs[numInputs] = e;
                            ++numInputs;
                        }
                    }
                    if (numInputs > 0) {
                        Expression out = AbstractGate.this.computeExpression(inputs, numInputs);
                        expressionMap.put(instance.getPortLocation(0), out);
                    }
                }
            };
        }
        return super.getInstanceFeature(instance, key);
    }

    Location getInputOffset(GateAttributes attrs, int index) {
        int inputs = attrs.inputs;
        Direction facing = attrs.facing;
        int size = ((Integer) attrs.size.getValue()).intValue();
        int axisLength = size + bonusWidth + (negateOutput ? 10 : 0);
        int negated = attrs.negated;

        int skipStart;
        int skipDist;
        int skipLowerEven = 10;
        if (inputs <= 3) {
            if (size < 40) {
                skipStart = -5;
                skipDist = 10;
                skipLowerEven = 10;
            } else if (size < 60 || inputs <= 2) {
                skipStart = -10;
                skipDist = 20;
                skipLowerEven = 20;
            } else {
                skipStart = -15;
                skipDist = 30;
                skipLowerEven = 30;
            }
        } else if (inputs == 4 && size >= 60) {
            skipStart = -5;
            skipDist = 20;
            skipLowerEven = 0;
        } else {
            skipStart = -5;
            skipDist = 10;
            skipLowerEven = 10;
        }

        int dy;
        if ((inputs & 1) == 1) {
            dy = skipStart * (inputs - 1) + skipDist * index;
        } else {
            dy = skipStart * inputs + skipDist * index;
            if (index >= inputs / 2) {
                dy += skipLowerEven;
            }

        }

        int dx = axisLength;
        int negatedBit = (negated >> index) & 1;
        if (negatedBit == 1) {
            dx += 10;
        }

        if (facing == Direction.NORTH) {
            return Location.create(dy, dx);
        } else if (facing == Direction.SOUTH) {
            return Location.create(dy, -dx);
        } else if (facing == Direction.WEST) {
            return Location.create(dx, dy);
        } else {
            return Location.create(-dx, dy);
        }
    }
}
TOP

Related Classes of com.cburch.logisim.std.gates.AbstractGate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.