Package games.stendhal.client.gui

Source Code of games.stendhal.client.gui.DragLayer

/* $Id: DragLayer.java,v 1.5 2011/05/11 09:25:46 kiheru Exp $ */
/***************************************************************************
*                   (C) Copyright 2003-2010 - Stendhal                    *
***************************************************************************
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
package games.stendhal.client.gui;

import games.stendhal.client.entity.IEntity;
import games.stendhal.client.entity.StackableItem;
import games.stendhal.client.gui.j2d.entity.Entity2DView;
import games.stendhal.client.gui.j2d.entity.EntityViewFactory;
import games.stendhal.client.gui.j2d.entity.StackableItem2DView;

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;

import javax.swing.JComponent;
import javax.swing.SwingUtilities;

/**
* A glass pane component for drawing dragged items. Using ideas (though no
* code) from Alexander Potochkin of the swing team. His blog entry describing
* the tricks used:
* http://weblogs.java.net/blog/2006/09/20/well-behaved-glasspane
*/
public class DragLayer extends JComponent implements AWTEventListener {
  /**
   * serial version uid
   */
  private static final long serialVersionUID = -726066169323112688L;

  private static DragLayer instance;
 
  /** The dragged entity, or <code>null</code> if nothing is being dragged. */
  private Entity2DView dragged;
  /** Current mouse location. */
  private Point point;
 
  private int oldX, oldY, width, height;
 
  /**
   * Create a new DragLayer.
   */
  private DragLayer() {
    /*
     * Not a pretty way to listen to mouse events, but adding a mouse
     * movement listener eats any events that should go below. Redispatching
     * them does not really work (despite being what the official swing
     * tutorial recommends), because enter and leave events to the
     * components have already been lost.
     *
     * Adding a mouse movement listener after the drag has started does not
     * work either, because it does not get the mouse events belonging to
     * the drag, but starts working only later.
     */
    Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
   
    setOpaque(false);
  }
 
  @Override
  public boolean contains(int x, int y) {
    /*
     * To get the correct mouse cursors, the pane needs to lie a bit to
     * AWT and claim to not contain any point of the screen. Then the mouse
     * handling is properly passed to the components below.
     */
    return false;
  }

  /**
   * Get the DragLayer instance.
   *
   * @return drag layer
   */
  public static DragLayer get() {
    if (instance == null) {
      instance = new DragLayer();
    }
    return instance;
  }
 
  /**
   * Start dragging an entity. The DragLayer will take care of drawing,
   * updating the position and dropping it to the right DropTarget.
   *
   * @param entity dragged entity
   */
  public void startDrag(IEntity entity) {
    if (entity != null) {
      Entity2DView dragged = (Entity2DView) EntityViewFactory.create(entity);
      /*
       * Make it contained, so that the view knows to ignore the entity
       * coordinates
       */
      dragged.setContained(true);
      /*
       * Hide quantity until it can be made context sensitive to drag
       * modifiers.
       */
      if (dragged instanceof StackableItem2DView) {
        ((StackableItem2DView) dragged).setShowQuantity(false);
      }
     
      this.dragged = dragged;
    }
  }
 
  @Override
  public void paintComponent(Graphics g) {
    if ((point != null) && (dragged != null)) {
      Graphics2D g2d = (Graphics2D) g;
      g2d.translate(point.x, point.y);
      dragged.draw(g2d);
    }
  }

  /**
   * Stop dragging the item, and let the component below the cursor handle
   * the dropped entity.
   *
   * @param event The mouse event that triggered the drop
   */
  private void stopDrag(MouseEvent event) {
    Container parent = getParent();
    Point containerPoint = SwingUtilities.convertPoint(this, point, parent);
    // Find out the underlying component 
    Component component = SwingUtilities.getDeepestComponentAt(parent, containerPoint.x, containerPoint.y);
   
    if ((component != null) && (component instanceof DropTarget)) {
      IEntity entity = dragged.getEntity();
      if (entity != null) {
        Point componentPoint = SwingUtilities.convertPoint(this, point, component);
        if (showAmountChooser(event, entity)) {
          // Delegate dropping to the amount chooser
          DropAmountChooser chooser = new DropAmountChooser((StackableItem) entity, (DropTarget) component, componentPoint);
          chooser.show(component, componentPoint);
        } else {
          // Dropping everything
          ((DropTarget) component).dropEntity(entity, -1, componentPoint);
        }
      }
    }

    dragged = null;
  }
 
  /**
   * Determine if the user should be given a chooser popup for selecting the
   * amount of items to be dropped.
   *
   * @param event the mouse event that triggered the drop
   * @param entity dropped entity
   *
   * @return <code>true</code> if a chooser should be displayed,
   *   <code>false</code> otherwise
   */
  private boolean showAmountChooser(MouseEvent event, IEntity entity) {
    if (((event.getModifiersEx() & (MouseEvent.CTRL_DOWN_MASK|MouseEvent.META_DOWN_MASK)) != 0)
        && (entity instanceof StackableItem)) {
      return ((StackableItem) entity).getQuantity() > 1;
    }
    return false;
  }

  /*
   * (non-Javadoc)
   * @see java.awt.event.AWTEventListener#eventDispatched(java.awt.AWTEvent)
   */
  public void eventDispatched(AWTEvent e) {
    if (e instanceof MouseEvent) {
      MouseEvent event = (MouseEvent) e;

      MouseEvent converted = SwingUtilities.convertMouseEvent(event.getComponent(), event, this);
      point = converted.getPoint();

      if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
        requestDraw();
      } else if ((event.getID() == MouseEvent.MOUSE_RELEASED) && (dragged != null)) {
        stopDrag(event);
        requestDraw();
        point = null;
      }
      // We are interested only in DnD, so we can ignore any other events
    }
  }
 
  /**
   * Request drawing the component after a drag related mouse event
   */
  private void requestDraw() {
    /*
     * Optimize the repaints a bit. Drawing the whole layer is
     * expensive due to the paint requests to the components below,
     * so try to keep the drawn area small.
     */
    if ((width != 0) && (height != 0)) {
      /*
       * Paint over the old occupied area. This will probably be
       * merged with the next repaint by the RepaintManager.
       */
      repaint(oldX, oldY, width, height);
    }
    oldX = point.x;
    oldY = point.y;
    if (dragged != null) {
      width = dragged.getWidth();
      height = dragged.getHeight();
      repaint(point.x, point.y, width, height);
    } else {
      width = 0;
      height = 0;
    }
  }
}
TOP

Related Classes of games.stendhal.client.gui.DragLayer

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.