Package com.cburch.logisim.circuit.appear

Source Code of com.cburch.logisim.circuit.appear.PortManager

/* 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.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.cburch.draw.model.CanvasObject;
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.instance.StdAttr;

class PortManager {
  private CircuitAppearance appearance;
  private boolean doingUpdate;
 
  PortManager(CircuitAppearance appearance) {
    this.appearance = appearance;
    this.doingUpdate = false;
  }
 
  void updatePorts() {
    appearance.recomputePorts();
  }
 
  void updatePorts(Set<Instance> adds, Set<Instance> removes,
      Map<Instance, Instance> replaces, Collection<Instance> allPins) {
    if (appearance.isDefaultAppearance()) {
      appearance.recomputePorts();
    } else if (!doingUpdate) {
      // "doingUpdate" ensures infinite recursion doesn't happen
      try {
        doingUpdate = true;
        performUpdate(adds, removes, replaces, allPins);
        appearance.recomputePorts();
      } finally {
        doingUpdate = false;
      }
    }
  }
 
  private void performUpdate(Set<Instance> adds, Set<Instance> removes,
      Map<Instance, Instance> replaces, Collection<Instance> allPins) {
    // Find the current objects corresponding to pins
    Map<Instance, AppearancePort> oldObjects;
    oldObjects = new HashMap<Instance, AppearancePort>();
    AppearanceAnchor anchor = null;
    for (CanvasObject o : appearance.getObjectsFromBottom()) {
      if (o instanceof AppearancePort) {
        AppearancePort port = (AppearancePort) o;
        oldObjects.put(port.getPin(), port);
      } else if (o instanceof AppearanceAnchor) {
        anchor = (AppearanceAnchor) o;
      }
    }
   
    // ensure we have the anchor in the circuit
    if (anchor == null) {
      for (CanvasObject o : DefaultAppearance.build(allPins)) {
        if (o instanceof AppearanceAnchor) {
          anchor = (AppearanceAnchor) o;
        }
      }
      if (anchor == null) {
        anchor = new AppearanceAnchor(Location.create(100, 100));
      }
      int dest = appearance.getObjectsFromBottom().size();
      appearance.addObjects(dest, Collections.singleton(anchor));
    }

    // Compute how the ports should change
    ArrayList<AppearancePort> portRemoves;
    portRemoves = new ArrayList<AppearancePort>(removes.size());
    ArrayList<AppearancePort> portAdds;
    portAdds = new ArrayList<AppearancePort>(adds.size());
   
    // handle removals
    for (Instance pin : removes) {
      AppearancePort port = oldObjects.remove(pin);
      if (port != null) {
        portRemoves.add(port);
      }
    }
    // handle replacements
    ArrayList<Instance> addsCopy = new ArrayList<Instance>(adds);
    for (Map.Entry<Instance, Instance> entry : replaces.entrySet()) {
      AppearancePort port = oldObjects.remove(entry.getKey());
      if (port != null) {
        port.setPin(entry.getValue());
        oldObjects.put(entry.getValue(), port);
      } else { // this really shouldn't happen, but just to make sure...
        addsCopy.add(entry.getValue());
      }
    }
    // handle additions
    DefaultAppearance.sortPinList(addsCopy, Direction.EAST);
      // They're probably not really all facing east.
      // I'm just sorting them so it works predictably.
    for (Instance pin : addsCopy) {
      if (!oldObjects.containsKey(pin)) {
        Location loc = computeDefaultLocation(appearance, pin, oldObjects);
        AppearancePort o = new AppearancePort(loc, pin);
        portAdds.add(o);
        oldObjects.put(pin, o);
      }
    }

    // Now update the appearance
    appearance.replaceAutomatically(portRemoves, portAdds);
  }
 
  private static Location computeDefaultLocation(CircuitAppearance appear,
      Instance pin, Map<Instance, AppearancePort> others) {
    // Determine which locations are being used in canvas, and look for
    // which instances facing the same way in layout
    Set<Location> usedLocs = new HashSet<Location>();
    List<Instance> sameWay = new ArrayList<Instance>();
    Direction facing = pin.getAttributeValue(StdAttr.FACING);
    for (Map.Entry<Instance, AppearancePort> entry : others.entrySet()) {
      Instance pin2 = entry.getKey();
      Location loc = entry.getValue().getLocation();
      usedLocs.add(loc);
      if (pin2.getAttributeValue(StdAttr.FACING) == facing) {
        sameWay.add(pin2);
      }
    }
   
    // if at least one faces the same way, place pin relative to that
    if (sameWay.size() > 0) {
      sameWay.add(pin);
      DefaultAppearance.sortPinList(sameWay, facing);
      boolean isFirst = false;
      Instance neighbor = null; // (preferably previous in map)
      for (Instance p : sameWay) {
        if (p == pin) {
          break;
        } else {
          neighbor = p;
        }
      }
      if (neighbor == null) { // pin must have been first in list
        neighbor = sameWay.get(1);
      }
      int dx;
      int dy;
      if (facing == Direction.EAST || facing == Direction.WEST) {
        dx = 0;
        dy = isFirst? -10 : 10;
      } else {
        dx = isFirst ? -10 : 10;
        dy = 0;
      }
      Location loc = others.get(neighbor).getLocation();
      do {
        loc = loc.translate(dx, dy);
      } while (usedLocs.contains(loc));
      if (loc.getX() >= 0 && loc.getY() >= 0) {
        return loc;
      }
      do {
        loc = loc.translate(-dx, -dy);
      } while (usedLocs.contains(loc));
      return loc;
    }
   
    // otherwise place it on the boundary of the bounding rectangle
    Bounds bds = appear.getAbsoluteBounds();
    int x;
    int y;
    int dx = 0;
    int dy = 0;
    if (facing == Direction.EAST) { // on west side by default
      x = bds.getX() - 7;
      y = bds.getY() + 5;
      dy = 10;
    } else if (facing == Direction.WEST) { // on east side by default
      x = bds.getX() + bds.getWidth() - 3;
      y = bds.getY() + 5;
      dy = 10;
    } else if (facing == Direction.SOUTH) { // on north side by default
      x = bds.getX() + 5;
      y = bds.getY() - 7;
      dx = 10;
    } else { // on south side by default
      x = bds.getX() + 5;
      y = bds.getY() + bds.getHeight() - 3;
      dx = 10;
    }
    x = (x + 9) / 10 * 10; // round coordinates up to ensure they're on grid
    y = (y + 9) / 10 * 10;
    Location loc = Location.create(x, y);
    while (usedLocs.contains(loc)) {
      loc = loc.translate(dx, dy);
    }
    return loc;
  }
}
TOP

Related Classes of com.cburch.logisim.circuit.appear.PortManager

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.