Package com.cburch.draw.tools

Source Code of com.cburch.draw.tools.SelectTool

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

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.swing.Icon;

import com.cburch.draw.actions.ModelMoveHandleAction;
import com.cburch.draw.actions.ModelRemoveAction;
import com.cburch.draw.actions.ModelTranslateAction;
import com.cburch.draw.canvas.Canvas;
import com.cburch.draw.canvas.Selection;
import com.cburch.draw.model.CanvasModel;
import com.cburch.draw.model.CanvasObject;
import com.cburch.draw.model.Handle;
import com.cburch.draw.model.HandleGesture;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.util.GraphicsUtil;
import com.cburch.logisim.util.Icons;

public class SelectTool extends AbstractTool {
  private static final int IDLE = 0;
  private static final int MOVE_ALL = 1;
  private static final int RECT_SELECT = 2;
  private static final int RECT_TOGGLE = 3;
  private static final int MOVE_HANDLE = 4;
 
  private static final int DRAG_TOLERANCE = 2;
  private static final int HANDLE_SIZE = 8;
 
  private static final Color RECT_SELECT_BACKGROUND = new Color(0, 0, 0, 32);
 
  private int curAction;
  private List<CanvasObject> beforePressSelection;
  private Handle beforePressHandle;
  private Location dragStart;
  private Location dragEnd;
  private boolean dragEffective;
  private int lastMouseX;
  private int lastMouseY;
  private HandleGesture curGesture;
 
  public SelectTool() {
    curAction = IDLE;
    dragStart = Location.create(0, 0);
    dragEnd = dragStart;
    dragEffective = false;
  }
 
  @Override
  public Icon getIcon() {
    return Icons.getIcon("select.gif");
  }

  @Override
  public Cursor getCursor(Canvas canvas) {
    return Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
  }
 
  @Override
  public List<Attribute<?>> getAttributes() {
    return Collections.emptyList();
  }
 
  @Override
  public void toolSelected(Canvas canvas) {
    curAction = IDLE;
    canvas.getSelection().clearSelected();
    repaintArea(canvas);
  }
 
  @Override
  public void toolDeselected(Canvas canvas) {
    curAction = IDLE;
    canvas.getSelection().clearSelected();
    repaintArea(canvas);
  }
 
  private int getHandleSize(Canvas canvas) {
    double zoom = canvas.getZoomFactor();
    return (int) Math.ceil(HANDLE_SIZE / Math.sqrt(zoom));
  }
 
  @Override
  public void mousePressed(Canvas canvas, MouseEvent e) {
    beforePressSelection = new ArrayList<CanvasObject>(canvas.getSelection().getSelected());
    beforePressHandle = canvas.getSelection().getSelectedHandle();
    int mx = e.getX();
    int my = e.getY();
    boolean shift = (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0;
    dragStart = Location.create(mx, my);
    dragEffective = false;
    dragEnd = dragStart;
    lastMouseX = mx;
    lastMouseY = my;
    Selection selection = canvas.getSelection();
    selection.setHandleSelected(null);
   
    // see whether user is pressing within an existing handle
    int halfSize = getHandleSize(canvas) / 2;
    CanvasObject clicked = null;
    for (CanvasObject shape : selection.getSelected()) {
      List<Handle> handles = shape.getHandles(null);
      for (Handle han : handles) {
        int dx = han.getX() - mx;
        int dy = han.getY() - my;
        if (dx >= -halfSize && dx <= halfSize
            && dy >= -halfSize && dy <= halfSize) {
          if (shape.canMoveHandle(han)) {
            curAction = MOVE_HANDLE;
            curGesture = new HandleGesture(han, 0, 0,
                e.getModifiersEx());
            repaintArea(canvas);
            return;
          } else if (clicked == null) {
            clicked = shape;
          }
        }
      }
    }

    // see whether the user is clicking within a shape
    if (clicked == null) {
      clicked = getObjectAt(canvas.getModel(), e.getX(), e.getY(), false);
    }
    if (clicked != null) {
      if (shift && selection.isSelected(clicked)) {
        selection.setSelected(clicked, false);
        curAction = IDLE;
      } else {
        if (!shift && !selection.isSelected(clicked)) {
          selection.clearSelected();
        }
        selection.setSelected(clicked, true);
        selection.setMovingShapes(selection.getSelected(), 0, 0);
        curAction = MOVE_ALL;
      }
      repaintArea(canvas);
      return;
    }
   
    clicked = getObjectAt(canvas.getModel(), e.getX(), e.getY(), true);
    if (clicked != null && selection.isSelected(clicked)) {
      if (shift) {
        selection.setSelected(clicked, false);
        curAction = IDLE;
      } else {
        selection.setMovingShapes(selection.getSelected(), 0, 0);
        curAction = MOVE_ALL;
      }
      repaintArea(canvas);
      return;
    }

    if (shift) {
      curAction = RECT_TOGGLE;
    } else {
      selection.clearSelected();
      curAction = RECT_SELECT;
    }
    repaintArea(canvas);
  }
 
  @Override
  public void cancelMousePress(Canvas canvas) {
    List<CanvasObject> before = beforePressSelection;
    Handle handle = beforePressHandle;
    beforePressSelection = null;
    beforePressHandle = null;
    if (before != null) {
      curAction = IDLE;
      Selection sel = canvas.getSelection();
      sel.clearDrawsSuppressed();
      sel.setMovingShapes(Collections.<CanvasObject>emptySet(), 0, 0);
      sel.clearSelected();
      sel.setSelected(before, true);
      sel.setHandleSelected(handle);
      repaintArea(canvas);
    }
  }
 
  @Override
  public void mouseDragged(Canvas canvas, MouseEvent e) {
    setMouse(canvas, e.getX(), e.getY(), e.getModifiersEx());
  }
 
  @Override
  public void mouseReleased(Canvas canvas, MouseEvent e) {
    beforePressSelection = null;
    beforePressHandle = null;
    setMouse(canvas, e.getX(), e.getY(), e.getModifiersEx());
   
    CanvasModel model = canvas.getModel();
    Selection selection = canvas.getSelection();
    Set<CanvasObject> selected = selection.getSelected();
    int action = curAction;
    curAction = IDLE;
   
    if (!dragEffective) {
      Location loc = dragEnd;
      CanvasObject o = getObjectAt(model, loc.getX(), loc.getY(), false);
      if (o != null) {
        Handle han = o.canDeleteHandle(loc);
        if (han != null) {
          selection.setHandleSelected(han);
        } else {
          han = o.canInsertHandle(loc);
          if (han != null) {
            selection.setHandleSelected(han);
          }
        }
      }
    }
   
    Location start = dragStart;
    int x1 = e.getX();
    int y1 = e.getY();
    switch (action) {
    case MOVE_ALL:
      Location moveDelta = selection.getMovingDelta();
      if (dragEffective && !moveDelta.equals(Location.create(0, 0))) {
        canvas.doAction(new ModelTranslateAction(model, selected,
            moveDelta.getX(), moveDelta.getY()));
      }
      break;
    case MOVE_HANDLE:
      HandleGesture gesture = curGesture;
      curGesture = null;
      if (dragEffective && gesture != null) {
        ModelMoveHandleAction act;
        act = new ModelMoveHandleAction(model, gesture);
        canvas.doAction(act);
        Handle result = act.getNewHandle();
        if (result != null) {
          Handle h = result.getObject().canDeleteHandle(result.getLocation());
          selection.setHandleSelected(h);
        }
      }
      break;
    case RECT_SELECT:
      if (dragEffective) {
        Bounds bds = Bounds.create(start).add(x1, y1);
        selection.setSelected(canvas.getModel().getObjectsIn(bds), true);
      } else {
        CanvasObject clicked;
        clicked = getObjectAt(model, start.getX(), start.getY(), true);
        if (clicked != null) {
          selection.clearSelected();
          selection.setSelected(clicked, true);
        }
      }
      break;
    case RECT_TOGGLE:
      if (dragEffective) {
        Bounds bds = Bounds.create(start).add(x1, y1);
        selection.toggleSelected(canvas.getModel().getObjectsIn(bds));
      } else {
        CanvasObject clicked;
        clicked = getObjectAt(model, start.getX(), start.getY(), true);
        selection.setSelected(clicked, !selected.contains(clicked));
      }
      break;
    }
    selection.clearDrawsSuppressed();
    repaintArea(canvas);
  }
 
  @Override
  public void keyPressed(Canvas canvas, KeyEvent e) {
    int code = e.getKeyCode();
    if ((code == KeyEvent.VK_SHIFT || code == KeyEvent.VK_CONTROL
        || code == KeyEvent.VK_ALT) && curAction != IDLE) {
      setMouse(canvas, lastMouseX, lastMouseY, e.getModifiersEx());
    }
  }
 
  @Override
  public void keyReleased(Canvas canvas, KeyEvent e) {
    keyPressed(canvas, e);
  }
 
  @Override
  public void keyTyped(Canvas canvas, KeyEvent e) {
    char ch = e.getKeyChar();
    Selection selected = canvas.getSelection();
    if ((ch == '\u0008' || ch == '\u007F') && !selected.isEmpty()) {
      ArrayList<CanvasObject> toRemove = new ArrayList<CanvasObject>();
      for (CanvasObject shape : selected.getSelected()) {
        if (shape.canRemove()) {
          toRemove.add(shape);
        }
      }
      if (!toRemove.isEmpty()) {
        e.consume();
        CanvasModel model = canvas.getModel();
        canvas.doAction(new ModelRemoveAction(model, toRemove));
        selected.clearSelected();
        repaintArea(canvas);
      }
    } else if (ch == '\u001b' && !selected.isEmpty()) {
      selected.clearSelected();
      repaintArea(canvas);
    }
  }
 
 
  private void setMouse(Canvas canvas, int mx, int my, int mods) {
    lastMouseX = mx;
    lastMouseY = my;
    boolean shift = (mods & MouseEvent.SHIFT_DOWN_MASK) != 0;
    boolean ctrl = (mods & InputEvent.CTRL_DOWN_MASK) != 0;
    Location newEnd = Location.create(mx, my);
    dragEnd = newEnd;

    Location start = dragStart;
    int dx = newEnd.getX() - start.getX();
    int dy = newEnd.getY() - start.getY();
    if (!dragEffective) {
      if (Math.abs(dx) + Math.abs(dy) > DRAG_TOLERANCE) {
        dragEffective = true;
      } else {
        return;
      }
    }

    switch (curAction) {
    case MOVE_HANDLE:
      HandleGesture gesture = curGesture;
      if (ctrl) {
        Handle h = gesture.getHandle();
        dx = canvas.snapX(h.getX() + dx) - h.getX();
        dy = canvas.snapY(h.getY() + dy) - h.getY();
      }
      curGesture = new HandleGesture(gesture.getHandle(), dx, dy, mods);
      canvas.getSelection().setHandleGesture(curGesture);
      break;
    case MOVE_ALL:
      if (ctrl) {
        int minX = Integer.MAX_VALUE;
        int minY = Integer.MAX_VALUE;
        for (CanvasObject o : canvas.getSelection().getSelected()) {
          for (Handle handle : o.getHandles(null)) {
            int x = handle.getX();
            int y = handle.getY();
            if (x < minX) minX = x;
            if (y < minY) minY = y;
          }
        }
        dx = canvas.snapX(minX + dx) - minX;
        dy = canvas.snapY(minY + dy) - minY;
      }
      if (shift) {
        if (Math.abs(dx) > Math.abs(dy)) {
          dy = 0;
        } else {
          dx = 0;
        }
      }
      canvas.getSelection().setMovingDelta(dx, dy);
      break;
    }
    repaintArea(canvas);
  }

  private void repaintArea(Canvas canvas) {
    canvas.repaint();
  }
 
  @Override
  public void draw(Canvas canvas, Graphics g) {
    Selection selection = canvas.getSelection();
    int action = curAction;

    Location start = dragStart;
    Location end = dragEnd;
    HandleGesture gesture = null;
    boolean drawHandles;
    switch (action) {
    case MOVE_ALL:
      drawHandles = !dragEffective;
      break;
    case MOVE_HANDLE:
      drawHandles = !dragEffective;
      if (dragEffective) gesture = curGesture;
      break;
    default:
      drawHandles = true;
    }

    CanvasObject moveHandleObj = null;
    if (gesture != null) moveHandleObj = gesture.getHandle().getObject();
    if (drawHandles) {
      // unscale the coordinate system so that the stroke width isn't scaled
      double zoom = 1.0;
      Graphics gCopy = g.create();
      if (gCopy instanceof Graphics2D) {
        zoom = canvas.getZoomFactor();
        if (zoom != 1.0) {
          ((Graphics2D) gCopy).scale(1.0 / zoom, 1.0 / zoom);
        }
      }
      GraphicsUtil.switchToWidth(gCopy, 1);

      int size = (int) Math.ceil(HANDLE_SIZE * Math.sqrt(zoom));
      int offs = size / 2;
      for (CanvasObject obj : selection.getSelected()) {
        List<Handle> handles;
        if (action == MOVE_HANDLE && obj == moveHandleObj) {
          handles = obj.getHandles(gesture);
        } else {
          handles = obj.getHandles(null);
        }
        for (Handle han : handles) {
          int x = han.getX();
          int y = han.getY();
          if (action == MOVE_ALL && dragEffective) {
            Location delta = selection.getMovingDelta();
            x += delta.getX();
            y += delta.getY();
          }
          x = (int) Math.round(zoom * x);
          y = (int) Math.round(zoom * y);
          gCopy.clearRect(x - offs, y - offs, size, size);
          gCopy.drawRect(x - offs, y - offs, size, size);
        }
      }
      Handle selHandle = selection.getSelectedHandle();
      if (selHandle != null) {
        int x = selHandle.getX();
        int y = selHandle.getY();
        if (action == MOVE_ALL && dragEffective) {
          Location delta = selection.getMovingDelta();
          x += delta.getX();
          y += delta.getY();
        }
        x = (int) Math.round(zoom * x);
        y = (int) Math.round(zoom * y);
        int[] xs = { x - offs, x, x + offs, x };
        int[] ys = { y, y - offs, y, y + offs };
        gCopy.setColor(Color.WHITE);
        gCopy.fillPolygon(xs, ys, 4);
        gCopy.setColor(Color.BLACK);
        gCopy.drawPolygon(xs, ys, 4);
      }
    }
   
    switch (action) {
    case RECT_SELECT:
    case RECT_TOGGLE:
      if (dragEffective) {
        // find rectangle currently to show
        int x0 = start.getX();
        int y0 = start.getY();
        int x1 = end.getX();
        int y1 = end.getY();
        if (x1 < x0) { int t = x0; x0 = x1; x1 = t; }
        if (y1 < y0) { int t = y0; y0 = y1; y1 = t; }

        // make the region that's not being selected darker
        int w = canvas.getWidth();
        int h = canvas.getHeight();
        g.setColor(RECT_SELECT_BACKGROUND);
        g.fillRect(0, 0, w, y0);
        g.fillRect(0, y0, x0, y1 - y0);
        g.fillRect(x1, y0, w - x1, y1 - y0);
        g.fillRect(0, y1, w, h - y1);

        // now draw the rectangle
        g.setColor(Color.GRAY);
        g.drawRect(x0, y0, x1 - x0, y1 - y0);
      }
      break;
    }
  }

  private static CanvasObject getObjectAt(CanvasModel model, int x, int y,
      boolean assumeFilled) {
    Location loc = Location.create(x, y);
    for (CanvasObject o : model.getObjectsFromTop()) {
      if (o.contains(loc, assumeFilled)) return o;
    }
    return null;
  }
}
TOP

Related Classes of com.cburch.draw.tools.SelectTool

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.