Package ca.nengo.ui.lib.world.piccolo

Source Code of ca.nengo.ui.lib.world.piccolo.WorldImpl

package ca.nengo.ui.lib.world.piccolo;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.JPopupMenu;

import ca.nengo.ui.NengoGraphics;
import ca.nengo.ui.actions.PasteAction;
import ca.nengo.ui.lib.Style.NengoStyle;
import ca.nengo.ui.lib.actions.ActionException;
import ca.nengo.ui.lib.actions.RemoveObjectsAction;
import ca.nengo.ui.lib.actions.StandardAction;
import ca.nengo.ui.lib.actions.ZoomToFitAction;
import ca.nengo.ui.lib.util.UIEnvironment;
import ca.nengo.ui.lib.util.menus.PopupMenuBuilder;
import ca.nengo.ui.lib.world.Interactable;
import ca.nengo.ui.lib.world.World;
import ca.nengo.ui.lib.world.WorldObject;
import ca.nengo.ui.lib.world.handlers.AbstractStatusHandler;
import ca.nengo.ui.lib.world.handlers.EventConsumer;
import ca.nengo.ui.lib.world.handlers.KeyboardHandler;
import ca.nengo.ui.lib.world.handlers.MouseHandler;
import ca.nengo.ui.lib.world.handlers.PanEventHandler;
import ca.nengo.ui.lib.world.handlers.SelectionHandler;
import ca.nengo.ui.lib.world.handlers.TooltipPickHandler;
import ca.nengo.ui.lib.world.handlers.TopWorldStatusHandler;
import ca.nengo.ui.lib.world.piccolo.objects.TooltipWrapper;
import ca.nengo.ui.lib.world.piccolo.objects.Window;
import ca.nengo.ui.lib.world.piccolo.primitives.PXGrid;
import ca.nengo.ui.lib.world.piccolo.primitives.PXLayer;
import ca.nengo.ui.models.NodeContainer;
import ca.nengo.ui.util.NengoClipboard;
import edu.umd.cs.piccolo.PRoot;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.util.PBounds;

/**
* Implementation of World. World holds World Objects and has navigation and
* interaction handlers.
*
* @author Shu Wu
*/
public class WorldImpl extends WorldObjectImpl implements World, Interactable {

  /**
   * Padding to use around objects when zooming in on them
   */
  private static final double OBJECT_ZOOM_PADDING = 100;

  /**
   * Whether tooltips are enabled
   */
  private static boolean tooltipsEnabled = true;

  public static Rectangle2D getObjectBounds(Collection<WorldObject> objects) {
    double startX = Double.POSITIVE_INFINITY;
    double startY = Double.POSITIVE_INFINITY;
    double endX = Double.NEGATIVE_INFINITY;
    double endY = Double.NEGATIVE_INFINITY;

    for (WorldObject wo : objects) {
      Point2D position = wo.localToGlobal(new Point2D.Double(0, 0));
      Rectangle2D bounds = wo.localToGlobal(wo.getBounds());

      double x = position.getX();
      double y = position.getY();

      if (x < startX) {
        startX = x;
      }
      if (x + bounds.getWidth() > endX) {
        endX = x + bounds.getWidth();
      }

      if (y < startY) {
        startY = y;
      }
      if (y + bounds.getHeight() > endY) {
        endY = y + bounds.getHeight();
      }

    }

    if (objects.size() > 0) {
      return new Rectangle2D.Double(startX, startY, endX - startX, endY - startY);
    } else {
      throw new InvalidParameterException("no objects");
    }

  }

  public static boolean isTooltipsVisible() {
    return tooltipsEnabled;
  }

  public static void setTooltipsVisible(boolean tooltipsVisible) {
    WorldImpl.tooltipsEnabled = tooltipsVisible;
  }

  /**
   * Layer attached to the camera which shows the zoomable grid
   */
  private PXLayer gridLayer;

  /**
   * If true, then selection mode. If false, then navigation mode.
   */
  private boolean isSelectionMode;

  private KeyboardHandler keyboardHandler;

  /**
   * PLayer which holds the ground layer
   */
  private PXLayer layer;

  /**
   * Ground which can be zoomed and navigated
   */
  private WorldGroundImpl myGround;

  /**
   * Sky, which looks at the ground and whose position and scale remains
   * static
   */
  private WorldSkyImpl mySky;

  /**
   * Panning handler
   */
  private final PanEventHandler panHandler;

  /**
   * Selection handler
   */
  private SelectionHandler selectionEventHandler;

  /**
   * Status bar handler
   */
  private PBasicInputEventHandler statusBarHandler;

  /**
   * @param name
   * @param ground
   */
  public WorldImpl(String name, WorldGroundImpl ground) {
    this(name, new WorldSkyImpl(), ground);
  }

  /**
   * Default constructor
   *
   * @param name
   *            Name of this world
   */
  public WorldImpl(String name, WorldSkyImpl sky, WorldGroundImpl ground) {
    super(name);

    /*
     * Create layer
     */
    layer = new PXLayer();
    getPRoot().addChild(layer);

    /*
     * Create ground
     */
    ground.setWorld(this);
    myGround = ground;
    layer.addChild(myGround.getPiccolo());

    /*
     * Create sky
     */
    mySky = sky;
    mySky.addLayer(layer);
    addChild(mySky);

    /*
     * Create handlers
     */
    panHandler = new PanEventHandler();
    keyboardHandler = new KeyboardHandler(this);
    mySky.getCamera().addInputEventListener(keyboardHandler);
    mySky.getCamera().addInputEventListener(new TooltipPickHandler(this, 1000, 0));
    mySky.getCamera().addInputEventListener(new MouseHandler(this));

    selectionEventHandler = new SelectionHandler(this, panHandler);
    selectionEventHandler.setMarqueePaint(NengoStyle.COLOR_BORDER_SELECTED);
    selectionEventHandler.setMarqueeStrokePaint(NengoStyle.COLOR_BORDER_SELECTED);
    selectionEventHandler.setMarqueePaintTransparency(0.1f);

    getPiccolo().addInputEventListener(new EventConsumer());
    setStatusBarHandler(new TopWorldStatusHandler(this));

    /*
     * Set position and scale
     */
    // animateToSkyPosition(0, 0);
    getSky().setViewScale(0.7f);

    /*
     * Create the grid
     */
    gridLayer = PXGrid.createGrid(getSky().getCamera(), UIEnvironment.getInstance()
        .getUniverse().getRoot(), NengoStyle.COLOR_DARKBORDER, 1500);

    /*
     * Let the top canvas have a handle on this world
     */
    UIEnvironment.getInstance().getUniverse().addWorld(this);

    /*
     * Miscellaneous
     */
    setBounds(0, 0, 800, 600);

    initSelectionMode();

  }

  private PRoot getPRoot() {
    /*
     * This world's root is always to top-level root associated with the
     * canvas
     */
    return UIEnvironment.getInstance().getUniverse().getRoot();
  }

  private void initSelectionMode() {
    isSelectionMode = false;
    mySky.getCamera().addInputEventListener(panHandler);
    mySky.getCamera().addInputEventListener(selectionEventHandler);
  }

  /**
   * Create context menu
   *
   * @return Menu builder
   */
  protected void constructMenu(PopupMenuBuilder menu, Double posX, Double posY) {
    NengoClipboard clipboard = NengoGraphics.getInstance().getClipboard();
    if (clipboard.hasContents()) {
      ArrayList<String> clipboardNames = clipboard.getContentsNames();
      String selectionName = "";
      if (clipboardNames.size() == 1) {
        selectionName = clipboardNames.get(0);
      } else {
        selectionName = "selection";
      }
      PasteAction pasteAction = new PasteAction("Paste '" + selectionName + "' here", (NodeContainer)this, false);
      pasteAction.setPosition(posX, posY);
      menu.addAction(pasteAction);
    }
    menu.addAction(new ZoomToFitAction("Zoom to fit", this));
    /*MenuBuilder windowsMenu = menu.addSubMenu("Windows");
    windowsMenu.addAction(new CloseAllWindows("Close all"));
    windowsMenu.addAction(new MinimizeAllWindows("Minimize all"));*/
  }

  protected void constructSelectionMenu(Collection<WorldObject> selection, PopupMenuBuilder menu) {
    menu.addAction(new ZoomToFitAction("Zoom to fit", this));
    menu.addAction(new RemoveObjectsAction(selection, "Remove selected"));
  }

  @Override
  protected void prepareForDestroy() {
    UIEnvironment.getInstance().getUniverse().removeWorld(this);

    keyboardHandler.destroy();
    gridLayer.removeFromParent();
    layer.removeFromParent();

    getGround().destroy();
    getSky().destroy();

    super.prepareForDestroy();
  }

  /**
   * Sets the view position of the sky, and animates to it.
   *
   * @param x
   *            X Position relative to ground
   * @param y
   *            Y Position relative to ground
   */
  public void animateToSkyPosition(double x, double y) {
    Rectangle2D newBounds = new Rectangle2D.Double(x, y, 0, 0);

    mySky.animateViewToCenterBounds(newBounds, false, 600);
  }

  /**
   * Closes all windows which exist in this world
   */
  public void closeAllWindows() {
    for (Window window : getWindows()) {
      window.close();
    }

  }

  /**
   * @return A collection of all the windows in this world
   */
  public Collection<Window> getWindows() {
    Collection<Window> skyWindows = getSky().getWindows();
    Collection<Window> groundWindows = getGround().getWindows();

    ArrayList<Window> allWindows = new ArrayList<Window>(skyWindows.size()
        + groundWindows.size());

    for (Window window : skyWindows) {
      allWindows.add(window);
    }
    for (Window window : groundWindows) {
      allWindows.add(window);
    }

    return allWindows;
  }

  /*
   * (non-Javadoc)
   *
   * @see ca.shu.ui.lib.handlers.Interactable#showContextMenu(edu.umd.cs.piccolo.event.PInputEvent)
   */
  public JPopupMenu getContextMenu() {
    PopupMenuBuilder menu = new PopupMenuBuilder(getName());
    constructMenu(menu, null, null);

    return menu.toJPopupMenu();
  }
 
  public JPopupMenu getContextMenu(double posX, double posY) {
    PopupMenuBuilder menu = new PopupMenuBuilder(getName());
    constructMenu(menu, posX, posY);

    return menu.toJPopupMenu();
  }

  /**
   * @return ground
   */
  public WorldGroundImpl getGround() {
    return myGround;
  }

  /**
   * @return Selection Currently Selected nodes
   */
  public Collection<WorldObject> getSelection() {
    return selectionEventHandler.getSelection();
  }
 
  public SelectionHandler getSelectionHandler() {
    return selectionEventHandler;
  }

  /**
   * @return Context menu for currently selected items, null is none is to be
   *         shown
   */
  public final JPopupMenu getSelectionMenu(Collection<WorldObject> selection) {

    if (selection.size() > 1) {

      PopupMenuBuilder menu = new PopupMenuBuilder(selection.size() + " Objects selected");

      constructSelectionMenu(selection, menu);

      return menu.toJPopupMenu();
    } else {
      return null;
    }

  }

  /**
   * @return sky
   */
  public WorldSkyImpl getSky() {
    return mySky;
  }

  public boolean isAncestorOf(WorldObject wo) {
    if (wo == this)
      return true;

    if (getGround().isAncestorOf(wo)) {
      return true;
    } else {
      return super.isAncestorOf(wo);
    }
  }

  /**
   * @return if true, selection mode is enabled. if false, navigation mode is
   *         enabled instead.
   */
  public boolean isSelectionMode() {
    return isSelectionMode;
  }

  /**
   * Minimizes all windows that exist in this world
   */
  public void minimizeAllWindows() {
    for (Window window : getWindows()) {
      window.setWindowState(Window.WindowState.MINIMIZED);
    }
  }

  public boolean setBounds(double x, double y, double w, double h) {
    mySky.setBounds(x, y, w, h);
    return super.setBounds(x, y, w, h);
  }

  /**
   * @param enabled
   *            True if selection mode is enabled, False if navigation
   */
  public void setSelectionMode(boolean enabled) {
    if (isSelectionMode != enabled) {
      isSelectionMode = enabled;
      mySky.getCamera().removeInputEventListener(selectionEventHandler);
      selectionEventHandler.endSelection(false);
      if (!isSelectionMode) {
        initSelectionMode();
      } else {
        mySky.getCamera().removeInputEventListener(panHandler);
        mySky.getCamera().addInputEventListener(selectionEventHandler);
      }

      // layoutChildren();
    }
  }

  /**
   * Set the status bar handler, there can be only one.
   *
   * @param statusHandler
   *            New Status bar handler
   */
  public void setStatusBarHandler(AbstractStatusHandler statusHandler) {
    if (statusBarHandler != null) {
      getSky().getCamera().removeInputEventListener(statusBarHandler);
    }

    statusBarHandler = statusHandler;

    if (statusBarHandler != null) {
      getSky().getCamera().addInputEventListener(statusBarHandler);
    }
  }

  /**
   * @param objectSelected
   *            Object to show the tooltip for
   * @return Tooltip shown
   */
  public TooltipWrapper showTooltip(WorldObject objectSelected) {

    TooltipWrapper tooltip = new TooltipWrapper(getSky(), objectSelected.getTooltip(),
        objectSelected);

    tooltip.fadeIn();

    return tooltip;

  }

  /**
   * @param position
   *            Position in sky
   * @return Position on ground
   */
  public Point2D skyToGround(Point2D position) {
    mySky.localToView(position);

    return position;
  }

  public void zoomToBounds(Rectangle2D bounds) {
    zoomToBounds(bounds, 1000);
  }

  /**
   * Animate the sky to look at a portion of the ground at bounds
   *
   * @param bounds
   *            Bounds to look at
   * @return Reference to the activity which is animating the zoom and
   *         positioning
   */
  public void zoomToBounds(Rectangle2D bounds, long time) {
    PBounds biggerBounds = new PBounds(bounds.getX() - OBJECT_ZOOM_PADDING, bounds.getY()
        - OBJECT_ZOOM_PADDING, bounds.getWidth() + OBJECT_ZOOM_PADDING * 2, bounds
        .getHeight()
        + OBJECT_ZOOM_PADDING * 2);

    getSky().animateViewToCenterBounds(biggerBounds, true, time);

  }

  public void zoomToFit() {
    if (getSelection().size() > 0) {
      Rectangle2D bounds = WorldImpl.getObjectBounds(getSelection());
      zoomToBounds(bounds);
    } else {
      zoomToBounds(getGround().getPiccolo().getUnionOfChildrenBounds(null));
    }

  }

  /**
   * @param object
   *            Object to zoom to
   * @return reference to animation activity
   */
  public void zoomToObject(WorldObject object) {
    Rectangle2D bounds = object.getParent().localToGlobal(object.getFullBounds());

    zoomToBounds(bounds);
  }

  /**
   * Action to close all windows
   *
   * @author Shu Wu
   */
  class CloseAllWindows extends StandardAction {

    private static final long serialVersionUID = 1L;

    public CloseAllWindows(String actionName) {
      super("Close all windows", actionName);
    }

    @Override
    protected void action() throws ActionException {
      closeAllWindows();

    }

  }

  /**
   * Action to minimize all windows
   *
   * @author Shu Wu
   */
  class MinimizeAllWindows extends StandardAction {

    private static final long serialVersionUID = 1L;

    public MinimizeAllWindows(String actionName) {
      super("Minimize all windows", actionName);
    }

    @Override
    protected void action() throws ActionException {
      minimizeAllWindows();

    }

  }

}
TOP

Related Classes of ca.nengo.ui.lib.world.piccolo.WorldImpl

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.