Package ca.nengo.ui.lib.world.handlers

Source Code of ca.nengo.ui.lib.world.handlers.SelectionHandler

/*
* Copyright (c) 2002-@year@, University of Maryland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of the University of Maryland nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Piccolo was written at the Human-Computer Interaction Laboratory www.cs.umd.edu/hcil by Jesse Grosjean
* under the supervision of Ben Bederson. The Piccolo website is www.cs.umd.edu/hcil/piccolo.
*/
package ca.nengo.ui.lib.world.handlers;

import java.awt.BasicStroke;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.event.InputEvent;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

import ca.nengo.ui.lib.actions.DragAction;
import ca.nengo.ui.lib.objects.models.ModelObject;
import ca.nengo.ui.lib.world.World;
import ca.nengo.ui.lib.world.WorldObject;
import ca.nengo.ui.lib.world.elastic.ElasticGround;
import ca.nengo.ui.lib.world.piccolo.WorldGroundImpl;
import ca.nengo.ui.lib.world.piccolo.WorldImpl;
import ca.nengo.ui.lib.world.piccolo.WorldObjectImpl;
import ca.nengo.ui.lib.world.piccolo.WorldSkyImpl;
import ca.nengo.ui.lib.world.piccolo.objects.SelectionBorder;
import ca.nengo.ui.lib.world.piccolo.objects.Window;
import ca.nengo.ui.lib.world.piccolo.primitives.PiccoloNodeInWorld;
import ca.nengo.ui.models.nodes.UINetwork;
import ca.nengo.ui.models.nodes.UINodeViewable;
import ca.nengo.ui.models.viewers.NodeViewer;
import edu.umd.cs.piccolo.PCamera;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PDragSequenceEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.event.PInputEventFilter;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.util.PBounds;
import edu.umd.cs.piccolo.util.PDimension;
import edu.umd.cs.piccolo.util.PNodeFilter;
import edu.umd.cs.piccolox.event.PNotificationCenter;

/**
* <code>PSelectionEventHandler</code> provides standard interaction for
* selection. Clicking selects the object under the cursor. Shift-clicking
* allows multiple objects to be selected. Dragging offers marquee selection.
* Pressing the delete key deletes the selection by default.
*
* @version 1.0
* @author Ben Bederson, modified by Shu Wu
*/
public class SelectionHandler extends PDragSequenceEventHandler {

  ///////////////////////////////////////////////////////////////////////////
  /// Constants
  public static final String SELECTION_CHANGED_NOTIFICATION = "SELECTION_CHANGED_NOTIFICATION";
  public static final String SELECTION_HANDLER_FRAME_ATTR = "SelHandlerFrame";

  final static int DASH_WIDTH = 5;
  final static int NUM_STROKES = 10;

  ///////////////////////////////////////////////////////////////////////////
  /// Static members
   
  /// this code allows other classes to be notified when the selection changes
  private static HashSet<SelectionListener> selectionListeners
    = new HashSet<SelectionListener>();
 
  public static void addSelectionListener(SelectionListener listener) {
    selectionListeners.add(listener);
  }

  public static void removeSelectionListener(SelectionListener listener) {
    selectionListeners.remove(listener);
  }

  public static void selectionChanged(Collection<WorldObject> objs) {
    for (SelectionListener listener : selectionListeners) {
      listener.selectionChanged(objs);
    }
  }
 
  public static interface SelectionListener {
    public void selectionChanged(Collection<WorldObject> obj);
  }
 
  // this code keeps track of which selection handler (of all selection handlers)
  // is active (i.e., has changed most recently)
  private static HashSet<SelectionHandler> selectionHandlers
    = new HashSet<SelectionHandler>();
  private static void addSelectionHandler(SelectionHandler s) {
    selectionHandlers.add(s);
  }
  private static void removeSelectionHandler(SelectionHandler s) {
    selectionHandlers.remove(s);
  }
 
  private static SelectionHandler activeSelectionHandler = null;
  public static SelectionHandler getActiveSelectionHandler() {
    return activeSelectionHandler;
  }
  private static void setActiveSelectionHandler(SelectionHandler activeS) {
    activeSelectionHandler = activeS;
    for (SelectionHandler s : selectionHandlers) {
      if (s != activeS)
        s.unselectAll();
    }
  }
 
  /**
   * @return the selected objects in the active selection handler
   */
  public static ArrayList<WorldObject> getActiveSelection() {
    if( getActiveSelectionHandler() == null )
      return new ArrayList<WorldObject>();
    else
      return getActiveSelectionHandler().getSelection();
  }
 
    /**
     * @return the last element in the list of active selected objects (or
     * null if no object selected)
     */
    public static WorldObject getActiveObject() {
      ArrayList<WorldObject> s = getActiveSelection();
      if (!s.isEmpty())
        return s.get(s.size() - 1); // return last item
      else
        return null;
    }
   
    public static Object getActiveModel() {
      WorldObject obj = getActiveObject();
      while (obj != null)
        if (obj instanceof ModelObject)
          return ((ModelObject) obj).getModel();
        else
          obj = obj.getParent();
     
      return null;
    }
   
    public static NodeViewer getActiveViewer() {
      WorldObject wo = getActiveObject();
      NodeViewer viewer = null;
      if (wo instanceof UINodeViewable) {
        UINodeViewable node = (UINodeViewable)wo;
        if (node.isViewerWindowVisible())
          viewer = node.getViewer();
      }
      if (viewer == null)
        viewer = getParentViewer(wo);
     
      return viewer;
    }
   
    public static UINetwork getActiveNetwork(boolean toplevel) {
      WorldObject wo = getActiveObject();
      UINetwork net = null;
    if (wo instanceof UINetwork) {
      net = (UINetwork)wo;
    } else {
      net = getParentNetwork(wo);
    }
   
    if (toplevel && net != null) {
      UINetwork netparent = net.getNetworkParent();
      while (netparent != null) {
        net = netparent;
        netparent = net.getNetworkParent();
      }
    }

    return net;
    }
 
    /**
     * Find the NodeViewer parent of a WorldObject
     * @param wo the world object to start the search from
     * @return the NodeViewer parent of the world object, null if it does not exist
     */
  protected static NodeViewer getParentViewer(WorldObject wo) {
    if (wo instanceof NodeViewer)
      return (NodeViewer)wo;
   
    while (wo != null) {
      if (wo instanceof ElasticGround) {
        World world = wo.getWorld();
        if (world instanceof NodeViewer) {
          return (NodeViewer)world;
        } else {
          wo = wo.getParent();
        }
      } else {
        wo = wo.getParent();
      }
    }
    return null;
  }
   
    /**
     * Find the UINetwork parent of a WorldObject
     * @param wo the world object to start the search from
     * @return the UINetwork parent of the world object, null if it does not exist
     */
  protected static UINetwork getParentNetwork(WorldObject wo) {
    if (wo instanceof UINetwork)
      return ((UINetwork)wo).getNetworkParent();
   
    while (wo != null) {
      if (wo instanceof UINetwork) {
        return (UINetwork)wo;
      } else if (wo instanceof ElasticGround) {
        World world = wo.getWorld();
        if (world instanceof NodeViewer) {
          wo = ((NodeViewer)world).getViewerParent();
        } else {
          wo = wo.getParent();
        }
      } else {
        wo = wo.getParent();
      }
    }
    return null;
  }
 
 
  // moves a WorldObject, and all the Windows it lies in, to the front
  protected static void moveStackToFront(WorldObject wo) {
    wo.moveToFront();
   
    // move all parent network windows to the front
    UINetwork pnet = getParentNetwork(wo);
    while (pnet != null) {
        if (pnet.isViewerWindowVisible()) {
            pnet.moveViewerWindowToFront();
        }
      pnet = getParentNetwork(pnet);
    }
  }
 
  ///////////////////////////////////////////////////////////////////////////
  /// Private members

  private ArrayList<WorldObjectImpl> selectedObjects = null; // current selected objects
  private ArrayList<WorldObjectImpl> allObjects = null;      // used in marquee code
  private ArrayList<WorldObjectImpl> marqueeObjects = null// used in marquee code

  private DragAction dragAction;
 
  private PPath marquee = null;
  private Paint marqueePaint;
  private float marqueePaintTransparency = 1.0f;
  private WorldSkyImpl marqueeParent = null; // Node that marquee is added to
  private Paint marqueeStrokePaint;
 
  private WorldObjectImpl pressNode = null; // Node pressed on (or null if none)
  private Point2D presspt = null;
  private Point2D canvasPressPt = null;

  private WorldImpl world; // associated world
  private WorldGroundImpl selectableParent = null; // ground of associated world

  private float strokeNum = 0;

  private Stroke[] strokes = null;

  private PanEventHandler panHandler;

  /**
   * Creates a selection event handler.
   *
   * @param marqueeParent
   *            The node to which the event handler dynamically adds a marquee
   *            (temporarily) to represent the area being selected.
   * @param selectableParent
   *            The node whose children will be selected by this event
   *            handler.
   */
  public SelectionHandler(WorldImpl world, PanEventHandler panHandler) {
    this.world = world;
    this.marqueeParent = world.getSky();
    this.selectableParent = world.getGround();
    this.panHandler = panHandler;
    panHandler.setSelectionHandler(this);
    setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK));
   
    float[] dash = { DASH_WIDTH, DASH_WIDTH };
    strokes = new Stroke[NUM_STROKES];
    for (int i = 0; i < NUM_STROKES; i++) {
      strokes[i] = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, dash, i);
    }

    selectedObjects = new ArrayList<WorldObjectImpl>();
    allObjects = new ArrayList<WorldObjectImpl>();
    marqueeObjects = new ArrayList<WorldObjectImpl>();
   
    addSelectionHandler(this);
  }
 
  public void finalize() {
    removeSelectionHandler(this);
  }
 
  ///////////////////////////////////////////////////////////////////////////
  /// Selection changed
 
  private boolean isActiveSelectionHandler() {
    return (this == getActiveSelectionHandler());
  }
 
  private void activeSelectionChanged() {
    setActiveSelectionHandler(this);
    PNotificationCenter.defaultCenter().postNotification(SELECTION_CHANGED_NOTIFICATION, this);
    selectionChanged(getSelection());
  }
 
  private void passiveSelectionChanged() {
    PNotificationCenter.defaultCenter().postNotification(SELECTION_CHANGED_NOTIFICATION, this);
    if(isActiveSelectionHandler())
      selectionChanged(getSelection());
  }
 
  ///////////////////////////////////////////////////////////////////////////
  /// Selection
 
  protected void initializeSelection(PInputEvent pie) {
    canvasPressPt = pie.getCanvasPosition();
    presspt = pie.getPosition();

    pressNode = null;
    for (PNode node = pie.getPath().getPickedNode(); node != null; node = node.getParent()) {
      if (node instanceof PiccoloNodeInWorld) {
        WorldObjectImpl wo = (WorldObjectImpl) ((PiccoloNodeInWorld) node).getWorldObject();
       
        if (wo != null && wo.isSelectable()) {
          if (!(wo instanceof Window && ((Window)wo).isMaximized())) {
            // this object is not a maximized window, so move to front
            moveStackToFront(wo);
          }
         
          if (wo instanceof Window) {
            // select the parent (Network, ensemble, etc.) of the clicked window
            WorldObjectImpl parent = (WorldObjectImpl)wo.getParent();
            if (parent != null && parent.getWorld() != null) {
              parent.getWorld().getSelectionHandler().unselectAll();
              parent.getWorld().getSelectionHandler().select(parent);
            }
          }
         
          pressNode = wo;
          return;
        }
      }
    }
  }

  /**
   * Determine if the specified node is selectable (i.e., if it is a child of
   * the one the list of selectable parents.
   */
  protected boolean isSelectable(WorldObject node) {
    return (node != null && selectableParent.isAncestorOf(node));
  }
 
  protected void startStandardOptionSelection(PInputEvent pie) {
    // Option indicator is down, toggle selection
    if (isSelectable(pressNode)) {
      if (isSelected(pressNode)) {
        unselect(pressNode);
      } else {
        select(pressNode);
      }
    }
  }

  protected void startStandardSelection(PInputEvent pie) {
    // Option indicator not down - clear selection, and start fresh
    if (!isSelected(pressNode)) {
      unselectAll();

      if (isSelectable(pressNode)) {
        select(pressNode);
      }
    }
  }

  public boolean isOptionSelection(PInputEvent pie) {
    return pie.isShiftDown();
  }

  public boolean isSelected(WorldObjectImpl node) {
    return ( node != null && selectedObjects.contains(node) );
  }

  public void decorateSelectedNode(WorldObjectImpl node) {
    SelectionBorder frame = new SelectionBorder(world, node);

    node.setSelected(true);
    node.getPiccolo().addAttribute(SELECTION_HANDLER_FRAME_ATTR, frame);
  }
 
  public void undecorateSelectedNode(WorldObjectImpl node) {

    Object frame = node.getPiccolo().getAttribute(SELECTION_HANDLER_FRAME_ATTR);
    if (frame != null && frame instanceof SelectionBorder) {
      ((SelectionBorder) frame).destroy();

    }
    node.setSelected(false);
    node.getPiccolo().addAttribute(SELECTION_HANDLER_FRAME_ATTR, null);
  }

  /**
   * Returns a copy of the currently selected nodes.
   */
  public ArrayList<WorldObject> getSelection() {
    ArrayList<WorldObject> sel = new ArrayList<WorldObject>(selectedObjects);
   
    boolean changes = false;
    for (int i = sel.size() - 1; i >= 0; i--) {
      if (sel.get(i).isDestroyed()) {
//        internalUnselect(sel.get(i));
        selectedObjects.remove(sel.get(i));
        sel.remove(i);
        changes = true;
      }
    }
    if (changes)
      passiveSelectionChanged();
   
    return sel;
  }
 
  private boolean internalSelect(WorldObjectImpl node) {
    if (!isSelected(node)) {
      selectedObjects.add(node);
      decorateSelectedNode(node);
      return true;
    } else
      return false;
  }

  public void select(Collection<WorldObjectImpl> items) {
    boolean changes = false;
    Iterator<WorldObjectImpl> itemIt = items.iterator();
    while (itemIt.hasNext()) {
      WorldObjectImpl node = itemIt.next();
      changes |= internalSelect(node);
    }
    if (changes) {
      activeSelectionChanged();
    }
  }

  public void select(WorldObjectImpl node) {
    select( Arrays.asList(new WorldObjectImpl[] {node}) );
  }
 
  private boolean internalUnselect(WorldObjectImpl node) {
    if (isSelected(node)) {
      undecorateSelectedNode(node);
      selectedObjects.remove(node);
      return true;
    } else
      return false;
  }

  public void unselect(Collection<WorldObjectImpl> items) {
    boolean changes = false;
    Iterator<WorldObjectImpl> itemIt = items.iterator();
    while (itemIt.hasNext()) {
      WorldObjectImpl node = (WorldObjectImpl) itemIt.next();
      changes |= internalUnselect(node);
    }
    if (changes) {
      passiveSelectionChanged();
    }
  }

  public void unselect(WorldObjectImpl node) {
    unselect( Arrays.asList(new WorldObjectImpl[] {node}) );
  }

  public void unselectAll() {
    // Because unselect() removes from selection, we need to
    // take a copy of it first so it isn't changed while we're iterating
    unselect(new ArrayList<WorldObjectImpl>(selectedObjects));
  }
 
  ///////////////////////////////////////////////////////////////////////////
  /// Dragging, including overridden methods from PDragSequenceEventHandler
 
  protected void startDrag(PInputEvent e) {
    super.startDrag(e);

    initializeSelection(e);

    if (shouldStartMarqueeMode()) {
      initializeMarquee(e);

      if (!isOptionSelection(e)) {
        startMarqueeSelection(e);
      } else {
        startOptionMarqueeSelection(e);
      }
    } else {
      if (!isOptionSelection(e)) {
        startStandardSelection(e);
      } else {
        startStandardOptionSelection(e);
      }

      Collection<WorldObject> nodes = getSelection();
      if (nodes.size() > 0) {
        dragAction = new DragAction(nodes);
        panHandler.setInverted(true);
      }

    }
  }

  protected void drag(PInputEvent e) {
    super.drag(e);

    if (shouldStartMarqueeMode() && marquee != null) {
      updateMarquee(e);

      if (!isOptionSelection(e)) {
        computeMarqueeSelection(e);
      } else {
        computeOptionMarqueeSelection(e);
      }
    } else {
      dragStandardSelection(e);

    }
  }

  /**
   * This gets called continuously during the drag, and is used to animate the
   * marquee
   */
  protected void dragActivityStep(PInputEvent aEvent) {
    if (marquee != null) {
      float origStrokeNum = strokeNum;
     
      // Increment by partial steps to slow down animation
      strokeNum = (strokeNum + 0.5f) % NUM_STROKES;
      if ((int) strokeNum != (int) origStrokeNum) {
        marquee.setStroke(strokes[(int) strokeNum]);
      }
    }
  }

  protected void dragStandardSelection(PInputEvent e) {

    Iterator<WorldObjectImpl> selectionEn = selectedObjects.iterator();

    if (selectionEn.hasNext()) {
      e.setHandled(true);
      PDimension d = e.getDeltaRelativeTo(selectableParent.getPiccolo());

      while (selectionEn.hasNext()) {
        WorldObjectImpl node = selectionEn.next();
        if (!node.isAnimating()) {
          PDimension gDist = new PDimension();
          gDist.setSize(d);

          node.localToParent(node.globalToLocal(gDist));

          node.dragOffset(gDist.getWidth(), gDist.getHeight());
        }
      }
    }
  }

  protected void endDrag(PInputEvent e) {
    super.endDrag(e);
    panHandler.setInverted(false);
    endSelection(true);
  }

  public void endSelection(boolean unselect) {
    if (marquee != null) {
      // Remove marquee
      marquee.removeFromParent();
      marquee = null;
    }
    if (!shouldStartMarqueeMode()) {
      // store the parent, in case pressNode is destroyed and we want to select it
      WorldObject parent = null;
      if (pressNode != null)
        parent = pressNode.getParent();
     
      // end the drag action
      if (dragAction != null) {
        dragAction.setFinalPositions();
        dragAction.doAction();
        dragAction = null;
      }
     
      // if pressNode is destroyed, unselect it and try to find a valid parent to select
      if (pressNode != null && pressNode.isDestroyed()) {
        while (parent != null && (parent.isDestroyed() || !isSelectable(parent))) {
          parent = parent.getParent();
        }
        if (parent instanceof WorldObjectImpl) {
          internalUnselect(pressNode);
          select((WorldObjectImpl)parent);
        } else {
          unselect(pressNode);
        }
      }

      // if a window was dragged, deselect it
      if (unselect && (pressNode == null || pressNode instanceof Window)) {
        unselectAll();
      }
     
      // cleanup
      endStandardSelection();
    }
  }
 
  protected void endStandardSelection() {
    pressNode = null;
  }
 
  ///////////////////////////////////////////////////////////////////////////
  /// Marquee
  protected void initializeMarquee(PInputEvent e) {
    marquee = PPath.createRectangle((float) presspt.getX(), (float) presspt.getY(), 0, 0);
    marquee.setPaint(marqueePaint);
    marquee.setTransparency(marqueePaintTransparency);
    marquee.setStrokePaint(marqueeStrokePaint);
    marquee.setStroke(strokes[0]);

    marqueeParent.getPiccolo().addChild(marquee);

    marqueeObjects.clear();
  }
 
  protected PBounds getMarqueeBounds() {
    if (marquee != null) {
      return marquee.getBounds();
    }
    return new PBounds();
  }

  /**
   * Indicates the color used to paint the marquee.
   *
   * @return the paint for interior of the marquee
   */
  public Paint getMarqueePaint() {
    return marqueePaint;
  }

  /**
   * Indicates the transparency level for the interior of the marquee.
   *
   * @return Returns the marquee paint transparency, zero to one
   */
  public float getMarqueePaintTransparency() {
    return marqueePaintTransparency;
  }

  /**
   * Sets the color used to paint the marquee.
   *
   * @param paint
   *            the paint color
   */
  public void setMarqueePaint(Paint paint) {
    this.marqueePaint = paint;
  }

  /**
   * Sets the transparency level for the interior of the marquee.
   *
   * @param marqueePaintTransparency
   *            The marquee paint transparency to set.
   */
  public void setMarqueePaintTransparency(float marqueePaintTransparency) {
    this.marqueePaintTransparency = marqueePaintTransparency;
  }

  public void setMarqueeStrokePaint(Paint marqueeStrokePaint) {
    this.marqueeStrokePaint = marqueeStrokePaint;
  }
 
  @SuppressWarnings("unchecked")
  protected void updateMarquee(PInputEvent pie) {
    PBounds b = new PBounds();

    if (marqueeParent.getPiccolo() instanceof PCamera) {
      b.add(canvasPressPt);
      b.add(pie.getCanvasPosition());
    } else {
      b.add(presspt);
      b.add(pie.getPosition());
    }

    b.reset();
    b.add(presspt);
    b.add(pie.getPosition());

    PBounds marqueeBounds = (PBounds) b.clone();

    selectableParent.globalToLocal(marqueeBounds);
    marqueeParent.viewToLocal(marqueeBounds);
    // marquee.globalToLocal(b);   
   
    marquee.setPathToRectangle((float) marqueeBounds.x, (float) marqueeBounds.y, (float) marqueeBounds.width,
        (float) marqueeBounds.height);

    allObjects.clear();
    PNodeFilter filter = new BoundsFilter(b);

    Collection<PNode> items;

    items = selectableParent.getPiccolo().getAllNodes(filter, null);

    Iterator<PNode> itemsIt = items.iterator();
    while (itemsIt.hasNext()) {
      PNode next = itemsIt.next();
      if (next instanceof PiccoloNodeInWorld) {
        WorldObjectImpl wo = (WorldObjectImpl) ((PiccoloNodeInWorld) next).getWorldObject();
        allObjects.add(wo);
      }

    }

  }
 
  protected void computeMarqueeSelection(PInputEvent pie) {
    ArrayList<WorldObjectImpl> unselectList = new ArrayList<WorldObjectImpl>();
   
    // Make just the items in the list selected
    // Do this efficiently by first unselecting things not in the list
    Iterator<WorldObjectImpl> selectionEn = selectedObjects.iterator();
    while (selectionEn.hasNext()) {
      WorldObjectImpl node = selectionEn.next();
      if (!allObjects.contains(node)) {
        unselectList.add(node);
      }
    }
    unselect(unselectList);

    // Then select the rest
    selectionEn = allObjects.iterator();
    while (selectionEn.hasNext()) {
      WorldObjectImpl node = selectionEn.next();
      if (!selectedObjects.contains(node) && !marqueeObjects.contains(node) && isSelectable(node)) {
        marqueeObjects.add(node);
      } else if (!isSelectable(node)) {
        selectionEn.remove();
      }
    }

    select(allObjects);
  }

  protected void computeOptionMarqueeSelection(PInputEvent pie) {
    ArrayList<WorldObjectImpl> unselectList = new ArrayList<WorldObjectImpl>();

    Iterator<WorldObjectImpl> selectionEn = selectedObjects.iterator();
    while (selectionEn.hasNext()) {
      WorldObjectImpl node = selectionEn.next();
      if (!allObjects.contains(node) && marqueeObjects.contains(node)) {
        marqueeObjects.remove(node);
        unselectList.add(node);
      }
    }
    unselect(unselectList);

    // Then select the rest
    selectionEn = allObjects.iterator();
    while (selectionEn.hasNext()) {
      WorldObjectImpl node = selectionEn.next();
      if (!selectedObjects.contains(node) && !marqueeObjects.contains(node) && isSelectable(node)) {
        marqueeObjects.add(node);
      } else if (!isSelectable(node)) {
        selectionEn.remove();
      }
    }

    select(allObjects);
  }

  protected boolean shouldStartMarqueeMode() {
    return ((pressNode == null || pressNode instanceof Window) && world.isSelectionMode());
  }

  protected void startMarqueeSelection(PInputEvent e) {
    unselectAll();
  }

  protected void startOptionMarqueeSelection(PInputEvent e) {
    unselectAll();
  }
 
  ///////////////////////////////////////////////////////////////////////////
  /// Inner classes

  protected class BoundsFilter implements PNodeFilter {
    PBounds bounds;
    PBounds localBounds = new PBounds();

    protected BoundsFilter(PBounds bounds) {
      this.bounds = bounds;
    }

    public boolean accept(PNode node) {
      localBounds.setRect(bounds);
      node.globalToLocal(localBounds);

      boolean boundsIntersects = node.intersects(localBounds);
      boolean isMarquee = (node == marquee);

      if (node instanceof PiccoloNodeInWorld) {
        WorldObject wo = ((PiccoloNodeInWorld) node).getWorldObject();

        if (wo.isSelectable()) {
          return (node.getPickable() && boundsIntersects && !isMarquee && !(wo == selectableParent));
        }
      }
      return false;

    }

    public boolean acceptChildrenOf(PNode node) {
      return node == selectableParent.getPiccolo();
    }

  }


}
TOP

Related Classes of ca.nengo.ui.lib.world.handlers.SelectionHandler

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.