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 {
    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;
    for (int i = n - 1; i >= 0; i--) { // count ports, move anchor to end
      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++;
      }
    }
    for (int i = (n - ports - 1) - 1; i >= 0; i--) { // move ports to top
      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 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.