Package com.cburch.logisim.tools

Source Code of com.cburch.logisim.tools.EditTool$Listener

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

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Set;

import com.cburch.logisim.LogisimVersion;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.CircuitEvent;
import com.cburch.logisim.circuit.CircuitListener;
import com.cburch.logisim.circuit.Wire;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.ComponentDrawContext;
import com.cburch.logisim.comp.ComponentFactory;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Direction;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.data.Value;
import com.cburch.logisim.gui.main.Canvas;
import com.cburch.logisim.gui.main.Selection;
import com.cburch.logisim.gui.main.SelectionActions;
import com.cburch.logisim.gui.main.Selection.Event;
import com.cburch.logisim.proj.Action;
import com.cburch.logisim.util.GraphicsUtil;

public class EditTool extends Tool {
  private static final int CACHE_MAX_SIZE = 32;
  private static final Location NULL_LOCATION
    = Location.create(Integer.MIN_VALUE, Integer.MIN_VALUE);
 
  private class Listener implements CircuitListener, Selection.Listener {
    public void circuitChanged(CircuitEvent event) {
      if (event.getAction() != CircuitEvent.ACTION_INVALIDATE) {
        lastX = -1;
        cache.clear();
        updateLocation(lastCanvas, lastRawX, lastRawY, lastMods);
      }
    }

    public void selectionChanged(Event event) {
      lastX = -1;
      cache.clear();
      updateLocation(lastCanvas, lastRawX, lastRawY, lastMods);
    }
  }
 
  private Listener listener;
  private SelectTool select;
  private WiringTool wiring;
  private Tool current;
  private LinkedHashMap<Location,Boolean> cache;
  private Canvas lastCanvas;
  private int lastRawX;
  private int lastRawY;
  private int lastX; // last coordinates where wiring was computed
  private int lastY;
  private int lastMods; // last modifiers for mouse event
  private Location wireLoc; // coordinates where to draw wiring indicator, if
  private int pressX; // last coordinate where mouse was pressed
  private int pressY; // (used to determine when a short wire has been clicked)
 
  public EditTool(SelectTool select, WiringTool wiring) {
    this.listener = new Listener();
    this.select = select;
    this.wiring = wiring;
    this.current = select;
    this.cache = new LinkedHashMap<Location,Boolean>();
    this.lastX = -1;
    this.wireLoc = NULL_LOCATION;
    this.pressX = -1;
  }
 
  @Override
  public boolean equals(Object other) {
    return other instanceof EditTool;
  }
 
  @Override
  public int hashCode() {
    return EditTool.class.hashCode();
  }

  @Override
  public String getName() {
    return "Edit Tool";
  }
 
  @Override
  public String getDisplayName() {
    return Strings.get("editTool");
  }
 
  @Override
  public String getDescription() {
    return Strings.get("editToolDesc");
  }

  @Override
  public AttributeSet getAttributeSet() {
    return select.getAttributeSet();
  }
 
  @Override
  public void setAttributeSet(AttributeSet attrs) {
    select.setAttributeSet(attrs);
  }
 
  @Override
  public AttributeSet getAttributeSet(Canvas canvas) {
    return canvas.getSelection().getAttributeSet();
  }

  @Override
  public boolean isAllDefaultValues(AttributeSet attrs, LogisimVersion ver) {
    return true;
  }
 
  @Override
  public void paintIcon(ComponentDrawContext c, int x, int y) {
    select.paintIcon(c, x, y);
  }
 
  @Override
  public Set<Component> getHiddenComponents(Canvas canvas) {
    return current.getHiddenComponents(canvas);
  }
   
  @Override
  public void draw(Canvas canvas, ComponentDrawContext context) {
    Location loc = wireLoc;
    if (loc != NULL_LOCATION && current != wiring) {
      int x = loc.getX();
      int y = loc.getY();
      Graphics g = context.getGraphics();
      g.setColor(Value.TRUE_COLOR);
      GraphicsUtil.switchToWidth(g, 2);
      g.drawOval(x - 5, y - 5, 10, 10);
      g.setColor(Color.BLACK);
      GraphicsUtil.switchToWidth(g, 1);
    }
    current.draw(canvas, context);
  }
 
  @Override
  public void select(Canvas canvas) {
    current = select;
    lastCanvas = canvas;
    cache.clear();
    canvas.getCircuit().addCircuitListener(listener);
    canvas.getSelection().addListener(listener);
    select.select(canvas);
  }
 
  @Override
  public void deselect(Canvas canvas) {
    current = select;
    canvas.getSelection().setSuppressHandles(null);
    cache.clear();
    canvas.getCircuit().removeCircuitListener(listener);
    canvas.getSelection().removeListener(listener);
  }

  @Override
  public void mousePressed(Canvas canvas, Graphics g, MouseEvent e) {
    boolean wire = updateLocation(canvas, e);
    Location oldWireLoc = wireLoc;
    wireLoc = NULL_LOCATION;
    lastX = Integer.MIN_VALUE;
    if (wire) {
      current = wiring;
      Selection sel = canvas.getSelection();
      Circuit circ = canvas.getCircuit();
      Collection<Component> selected = sel.getAnchoredComponents();
      ArrayList<Component> suppress = null;
      for (Wire w : circ.getWires()) {
        if (selected.contains(w)) {
          if (w.contains(oldWireLoc)) {
            if (suppress == null) suppress = new ArrayList<Component>();
            suppress.add(w);
          }
        }
      }
      sel.setSuppressHandles(suppress);
    } else {
      current = select;
    }
    pressX = e.getX();
    pressY = e.getY();
    current.mousePressed(canvas, g, e);
  }
 
  @Override
  public void mouseDragged(Canvas canvas, Graphics g, MouseEvent e) {
    isClick(e);
    current.mouseDragged(canvas, g, e);
  }
 
  @Override
  public void mouseReleased(Canvas canvas, Graphics g, MouseEvent e) {
    boolean click = isClick(e) && current == wiring;
    canvas.getSelection().setSuppressHandles(null);
    current.mouseReleased(canvas, g, e);
    if (click) {
      wiring.resetClick();
      select.mousePressed(canvas, g, e);
      select.mouseReleased(canvas, g, e);
    }
    current = select;
    cache.clear();
    updateLocation(canvas, e);
  }
 
  @Override
  public void mouseEntered(Canvas canvas, Graphics g, MouseEvent e) {
    pressX = -1;
    current.mouseEntered(canvas, g, e);
    canvas.requestFocusInWindow();
  }
 
  @Override
  public void mouseExited(Canvas canvas, Graphics g, MouseEvent e) {
    pressX = -1;
    current.mouseExited(canvas, g, e);
  }
 
  @Override
  public void mouseMoved(Canvas canvas, Graphics g, MouseEvent e) {
    updateLocation(canvas, e);
    select.mouseMoved(canvas, g, e);
  }
 
  private boolean isClick(MouseEvent e) {
    int px = pressX;
    if (px < 0) {
      return false;
    } else {
      int dx = e.getX() - px;
      int dy = e.getY() - pressY;
      if (dx * dx + dy * dy <= 4) {
        return true;
      } else {
        pressX = -1;
        return false;
      }
    }
  }
 
  private boolean updateLocation(Canvas canvas, MouseEvent e) {
    return updateLocation(canvas, e.getX(), e.getY(), e.getModifiersEx());
  }
 
  private boolean updateLocation(Canvas canvas, KeyEvent e) {
    int x = lastRawX;
    if (x >= 0) return updateLocation(canvas, x, lastRawY, e.getModifiersEx());
    else return false;
  }
 
  private boolean updateLocation(Canvas canvas, int mx, int my, int mods) {
    int snapx = Canvas.snapXToGrid(mx);
    int snapy = Canvas.snapYToGrid(my);
    int dx = mx - snapx;
    int dy = my - snapy;
    boolean isEligible = dx * dx + dy * dy < 36;
    if ((mods & MouseEvent.ALT_DOWN_MASK) != 0) isEligible = true;
    if (!isEligible) {
      snapx = -1;
      snapy = -1;
    }
    boolean modsSame = lastMods == mods;
    lastCanvas = canvas;
    lastRawX = mx;
    lastRawY = my;
    lastMods = mods;
    if (lastX == snapx && lastY == snapy && modsSame) { // already computed
      return wireLoc != NULL_LOCATION;
    } else {
      Location snap = Location.create(snapx, snapy);
      if (modsSame) {
        Object o = cache.get(snap);
        if (o != null) {
          lastX = snapx;
          lastY = snapy;
          canvas.repaint();
          boolean ret = ((Boolean) o).booleanValue();
          wireLoc = ret ? snap : NULL_LOCATION;
          return ret;
        }
      } else {
        cache.clear();
      }

      boolean ret = isEligible && isWiringPoint(canvas, snap, mods);
      wireLoc = ret ? snap : NULL_LOCATION;
      cache.put(snap, Boolean.valueOf(ret));
      int toRemove = cache.size() - CACHE_MAX_SIZE;
      Iterator<Location> it = cache.keySet().iterator();
      while (it.hasNext() && toRemove > 0) {
        it.next();
        it.remove();
        toRemove--;
      }

      lastX = snapx;
      lastY = snapy;
      canvas.repaint();
      return ret;
    }
  }
 
  private boolean isWiringPoint(Canvas canvas, Location loc, int modsEx) {
    boolean wiring = (modsEx & MouseEvent.ALT_DOWN_MASK) == 0;
    boolean select = !wiring;
   
    if (canvas != null && canvas.getSelection() != null) {
      Collection<Component> sel = canvas.getSelection().getComponents();
      if (sel != null) {
        for (Component c : sel) {
          if (c instanceof Wire) {
            Wire w = (Wire) c;
            if (w.contains(loc) && !w.endsAt(loc)) return select;
          }
        }
      }
    }
   
    Circuit circ = canvas.getCircuit();
    Collection<? extends Component> at = circ.getComponents(loc);
    if (at != null && at.size() > 0) return wiring;
   
    for (Wire w : circ.getWires()) {
      if (w.contains(loc)) { return wiring; }
    }
    return select;
  }

  @Override
  public void keyTyped(Canvas canvas, KeyEvent e) {
    select.keyTyped(canvas, e);
  }
 
  @Override
  public void keyPressed(Canvas canvas, KeyEvent e) {
    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();
      } else {
        wiring.keyPressed(canvas, e);
      }
      break;
    case KeyEvent.VK_INSERT:
      Action act = SelectionActions.duplicate(canvas.getSelection());
      canvas.getProject().doAction(act);
      e.consume();
      break;
    case KeyEvent.VK_UP:
      if (e.getModifiersEx() == 0) attemptReface(canvas, Direction.NORTH, e);
      else                         select.keyPressed(canvas, e);
      break;
    case KeyEvent.VK_DOWN:
      if (e.getModifiersEx() == 0) attemptReface(canvas, Direction.SOUTH, e);
      else                         select.keyPressed(canvas, e);
      break;
    case KeyEvent.VK_LEFT:
      if (e.getModifiersEx() == 0) attemptReface(canvas, Direction.WEST, e);
      else                         select.keyPressed(canvas, e);
      break;
    case KeyEvent.VK_RIGHT:
      if (e.getModifiersEx() == 0) attemptReface(canvas, Direction.EAST, e);
      else                         select.keyPressed(canvas, e);
      break;
    case KeyEvent.VK_ALT:   updateLocation(canvas, e); e.consume(); break;
    default:
      select.keyPressed(canvas, e);
    }
  }
 
  @Override
  public void keyReleased(Canvas canvas, KeyEvent e) {
    switch (e.getKeyCode()) {
    case KeyEvent.VK_ALT:   updateLocation(canvas, e); e.consume(); break;
    default:
      select.keyReleased(canvas, e);
    }
  }
 
  private void attemptReface(Canvas canvas, final Direction facing, KeyEvent e) {
    if (e.getModifiersEx() == 0) {
      final Circuit circuit = canvas.getCircuit();
      final Selection sel = canvas.getSelection();
      SetAttributeAction act = new SetAttributeAction(circuit,
          Strings.getter("selectionRefaceAction"));
      for (Component comp : sel.getComponents()) {
        if (!(comp instanceof Wire)) {
          Attribute<Direction> attr = getFacingAttribute(comp);
          if (attr != null) {
            act.set(comp, attr, facing);
          }
        }
      }
      if (!act.isEmpty()) {
        canvas.getProject().doAction(act);
        e.consume();
      }
    }
  }
 
  private Attribute<Direction> getFacingAttribute(Component comp) {
    AttributeSet attrs = comp.getAttributeSet();
    Object key = ComponentFactory.FACING_ATTRIBUTE_KEY;
    Attribute<?> a = (Attribute<?>) comp.getFactory().getFeature(key, attrs);
    @SuppressWarnings("unchecked")
    Attribute<Direction> ret = (Attribute<Direction>) a;
    return ret;
  }
 
  @Override
  public Cursor getCursor() {
    return select.getCursor();
  }
}
TOP

Related Classes of com.cburch.logisim.tools.EditTool$Listener

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.