Package com.cburch.logisim.circuit.appear

Source Code of com.cburch.logisim.circuit.appear.CircuitAppearance$MyListener

/* 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.circuit.appear;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import com.cburch.draw.model.CanvasModelEvent;
import com.cburch.draw.model.CanvasModelListener;
import com.cburch.draw.model.CanvasObject;
import com.cburch.draw.model.Drawing;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Direction;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.instance.Instance;
import com.cburch.logisim.util.EventSourceWeakSupport;

public class CircuitAppearance extends Drawing {
    private class MyListener implements CanvasModelListener {
        @Override
        public void modelChanged(CanvasModelEvent event) {
            if (!suppressRecompute) {
                setDefaultAppearance(false);
                fireCircuitAppearanceChanged(CircuitAppearanceEvent.ALL_TYPES);
            }
        }
    }

    private Circuit circuit;
    private EventSourceWeakSupport<CircuitAppearanceListener> listeners;
    private PortManager portManager;
    private CircuitPins circuitPins;
    private MyListener myListener;
    private boolean isDefault;
    private boolean suppressRecompute;

    public CircuitAppearance(Circuit circuit) {
        this.circuit = circuit;
        listeners = new EventSourceWeakSupport<CircuitAppearanceListener>();
        portManager = new PortManager(this);
        circuitPins = new CircuitPins(portManager);
        myListener = new MyListener();
        suppressRecompute = false;
        addCanvasModelListener(myListener);
        setDefaultAppearance(true);
    }

    public CircuitPins getCircuitPins() {
        return circuitPins;
    }

    public void addCircuitAppearanceListener(CircuitAppearanceListener l) {
        listeners.add(l);
    }

    public void removeCircuitAppearanceListener(CircuitAppearanceListener l) {
        listeners.remove(l);
    }

    void fireCircuitAppearanceChanged(int affected) {
        CircuitAppearanceEvent event;
        event = new CircuitAppearanceEvent(circuit, affected);
        for (CircuitAppearanceListener listener : listeners) {
            listener.circuitAppearanceChanged(event);
        }
    }

    void replaceAutomatically(List<AppearancePort> removes,
            List<AppearancePort> adds) {
        // this should be called only when substituting ports via PortManager
        boolean oldSuppress = suppressRecompute;
        try {
            suppressRecompute = true;
            removeObjects(removes);
            addObjects(getObjectsFromBottom().size() - 1, adds);
            recomputeDefaultAppearance();
        } finally {
            suppressRecompute = oldSuppress;
        }
        fireCircuitAppearanceChanged(CircuitAppearanceEvent.ALL_TYPES);
    }

    public boolean isDefaultAppearance() {
        return isDefault;
    }

    public void setDefaultAppearance(boolean value) {
        if (isDefault != value) {
            isDefault = value;
            if (value) {
                recomputeDefaultAppearance();
            }
        }
    }

    void recomputePorts() {
        if (isDefault) {
            recomputeDefaultAppearance();
        } else {
            fireCircuitAppearanceChanged(CircuitAppearanceEvent.ALL_TYPES);
        }
    }

    private void recomputeDefaultAppearance() {
        if (isDefault) {
            List<CanvasObject> shapes;
            shapes = DefaultAppearance.build(circuitPins.getPins());
            setObjectsForce(shapes);
        }
    }

    public Direction getFacing() {
        AppearanceAnchor anchor = findAnchor();
        if (anchor == null) {
            return Direction.EAST;
        } else {
            return anchor.getFacing();
        }
    }

    public void setObjectsForce(List<? extends CanvasObject> shapesBase) {
        // This shouldn't ever be an issue, but just to make doubly sure, we'll
        // check that the anchor and all ports are in their proper places.
        List<CanvasObject> shapes = new ArrayList<CanvasObject>(shapesBase);
        int n = shapes.size();
        int ports = 0;
        // count ports, move anchor to end
        for (int i = n - 1; i >= 0; i--) {
            CanvasObject o = shapes.get(i);
            if (o instanceof AppearanceAnchor) {
                if (i != n - 1) {
                    shapes.remove(i);
                    shapes.add(o);
                }
            } else if (o instanceof AppearancePort) {
                ports++;
            }
        }
        // move ports to top
        for (int i = (n - ports - 1) - 1; i >= 0; i--) {
            CanvasObject o = shapes.get(i);
            if (o instanceof AppearancePort) {
                shapes.remove(i);
                shapes.add(n - ports - 1, o);
                i--;
            }
        }

        try {
            suppressRecompute = true;
            super.removeObjects(new ArrayList<CanvasObject>(getObjectsFromBottom()));
            super.addObjects(0, shapes);
        } finally {
            suppressRecompute = false;
        }
        fireCircuitAppearanceChanged(CircuitAppearanceEvent.ALL_TYPES);
    }

    public void paintSubcircuit(Graphics g, Direction facing) {
        Direction defaultFacing = getFacing();
        double rotate = 0.0;
        if (facing != defaultFacing && g instanceof Graphics2D) {
            rotate = defaultFacing.toRadians() - facing.toRadians();
            ((Graphics2D) g).rotate(rotate);
        }
        Location offset = findAnchorLocation();
        g.translate(-offset.getX(), -offset.getY());
        for (CanvasObject shape : getObjectsFromBottom()) {
            if (!(shape instanceof AppearanceElement)) {
                Graphics dup = g.create();
                shape.paint(dup, null);
                dup.dispose();
            }
        }
        g.translate(offset.getX(), offset.getY());
        if (rotate != 0.0) {
            ((Graphics2D) g).rotate(-rotate);
        }
    }

    private Location findAnchorLocation() {
        AppearanceAnchor anchor = findAnchor();
        if (anchor == null) {
            return Location.create(100, 100);
        } else {
            return anchor.getLocation();
        }
    }

    private AppearanceAnchor findAnchor() {
        for (CanvasObject shape : getObjectsFromBottom()) {
            if (shape instanceof AppearanceAnchor) {
                return (AppearanceAnchor) shape;
            }
        }
        return null;
    }

    public Bounds getOffsetBounds() {
        return getBounds(true);
    }

    public Bounds getAbsoluteBounds() {
        return getBounds(false);
    }

    private Bounds getBounds(boolean relativeToAnchor) {
        Bounds ret = null;
        Location offset = null;
        for (CanvasObject o : getObjectsFromBottom()) {
            if (o instanceof AppearanceElement) {
                Location loc = ((AppearanceElement) o).getLocation();
                if (o instanceof AppearanceAnchor) {
                    offset = loc;
                }
                if (ret == null) {
                    ret = Bounds.create(loc);
                } else {
                    ret = ret.add(loc);
                }
            } else {
                if (ret == null) {
                    ret = o.getBounds();
                } else {
                    ret = ret.add(o.getBounds());
                }
            }
        }
        if (ret == null) {
            return Bounds.EMPTY_BOUNDS;
        } else if (relativeToAnchor && offset != null) {
            return ret.translate(-offset.getX(), -offset.getY());
        } else {
            return ret;
        }
    }

    public boolean contains(Location loc) {
        Location query;
        AppearanceAnchor anchor = findAnchor();
        if (anchor == null) {
            query = loc;
        } else {
            Location anchorLoc = anchor.getLocation();
            query = loc.translate(anchorLoc.getX(), anchorLoc.getY());
        }
        for (CanvasObject o : getObjectsFromBottom()) {
            if (!(o instanceof AppearanceElement) && o.contains(query, true)) {
                return true;
            }
        }
        return false;
    }

    public SortedMap<Location, Instance> getPortOffsets(Direction facing) {
        Location anchor = null;
        Direction defaultFacing = Direction.EAST;
        List<AppearancePort> ports = new ArrayList<AppearancePort>();
        for (CanvasObject shape : getObjectsFromBottom()) {
            if (shape instanceof AppearancePort) {
                ports.add((AppearancePort) shape);
            } else if (shape instanceof AppearanceAnchor) {
                AppearanceAnchor o = (AppearanceAnchor) shape;
                anchor = o.getLocation();
                defaultFacing = o.getFacing();
            }
        }

        SortedMap<Location, Instance> ret = new TreeMap<Location, Instance>();
        for (AppearancePort port : ports) {
            Location loc = port.getLocation();
            if (anchor != null) {
                loc = loc.translate(-anchor.getX(), -anchor.getY());
            }
            if (facing != defaultFacing) {
                loc = loc.rotate(defaultFacing, facing, 0, 0);
            }
            ret.put(loc, port.getPin());
        }
        return ret;
    }

    @Override
    public void addObjects(int index, Collection<? extends CanvasObject> shapes) {
        super.addObjects(index, shapes);
        checkToFirePortsChanged(shapes);
    }

    @Override
    public void addObjects(Map<? extends CanvasObject, Integer> shapes) {
        super.addObjects(shapes);
        checkToFirePortsChanged(shapes.keySet());
    }

    @Override
    public void removeObjects(Collection<? extends CanvasObject> shapes) {
        super.removeObjects(shapes);
        checkToFirePortsChanged(shapes);
    }

    @Override
    public void translateObjects(Collection<? extends CanvasObject> shapes, int dx, int dy) {
        super.translateObjects(shapes, dx, dy);
        checkToFirePortsChanged(shapes);
    }

    private void checkToFirePortsChanged(Collection<? extends CanvasObject> shapes) {
        if (affectsPorts(shapes)) {
            recomputePorts();
        }
    }

    private boolean affectsPorts(Collection<? extends CanvasObject> shapes) {
        for (CanvasObject o : shapes) {
            if (o instanceof AppearanceElement) {
                return true;
            }
        }
        return false;
    }
}
TOP

Related Classes of com.cburch.logisim.circuit.appear.CircuitAppearance$MyListener

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.