gov.nasa.worldwind.util.AbstractResizeHotSpot Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.util;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.event.SelectEvent;
import java.awt.*;
import java.awt.event.*;
/**
* A HotSpot for resizing a frame or window. This class handles the resize input events, but does does not actually draw
* the resize controls. The HotSpot is defined by a direction, for example, {@link AVKey#NORTH} indicates that the
* HotSpot resizes the frame vertically from the north edge (the user clicks the top edge of the frame and drags
* vertically).
*
* An instance of this class should be added to the picked object when the edge or corner of the frame is picked.
*
* Subclasses must the implement {#getSize}, {#setSize}, {#getScreenPoint}, and {#setScreenPoint} to manipulate the
* frame that they want to resize.
*
* @author pabercrombie
* @version $Id: AbstractResizeHotSpot.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public abstract class AbstractResizeHotSpot extends AbstractHotSpot
{
protected static final int NORTH = 1;
protected static final int SOUTH = 2;
protected static final int EAST = 4;
protected static final int WEST = 8;
protected static final int NORTHWEST = NORTH + WEST;
protected static final int NORTHEAST = NORTH + EAST;
protected static final int SOUTHWEST = SOUTH + WEST;
protected static final int SOUTHEAST = SOUTH + EAST;
protected boolean dragging;
protected Point dragRefPoint;
protected Dimension refSize;
protected Point refLocation;
protected boolean allowVerticalResize = true;
protected boolean allowHorizontalResize = true;
/**
* True if the window needs to be moved in the X direction as it is resized. For example, if the upper left corner
* is being dragged, the window should move to keep that corner under the cursor.
*/
protected boolean adjustLocationX;
/** True if the window needs to be moved in the Y direction as it is resized. */
protected boolean adjustLocationY;
protected int xSign = 1;
protected int ySign = 1;
protected int cursor;
protected void setDirection(String direction)
{
int dir = 0;
if (AVKey.NORTH.equals(direction))
dir = NORTH;
else if (AVKey.SOUTH.equals(direction))
dir = SOUTH;
else if (AVKey.EAST.equals(direction))
dir = EAST;
else if (AVKey.WEST.equals(direction))
dir = WEST;
else if (AVKey.NORTHEAST.equals(direction))
dir = NORTHEAST;
else if (AVKey.NORTHWEST.equals(direction))
dir = NORTHWEST;
else if (AVKey.SOUTHEAST.equals(direction))
dir = SOUTHEAST;
else if (AVKey.SOUTHWEST.equals(direction))
dir = SOUTHWEST;
this.setDirection(dir);
}
protected void setDirection(int direction)
{
this.adjustLocationX =
NORTH == direction
|| WEST == direction
|| SOUTHWEST == direction
|| NORTHWEST == direction;
this.adjustLocationY =
NORTH == direction
|| WEST == direction
|| NORTHWEST == direction
|| NORTHEAST == direction;
if (NORTH == direction || SOUTH == direction)
{
this.allowVerticalResize = true;
this.allowHorizontalResize = false;
}
else if (EAST == direction || WEST == direction)
{
this.allowVerticalResize = false;
this.allowHorizontalResize = true;
}
else
{
this.allowVerticalResize = true;
this.allowHorizontalResize = true;
}
if (WEST == direction || SOUTHWEST == direction || NORTHWEST == direction)
this.xSign = -1;
else
this.xSign = 1;
if (NORTH == direction || NORTHEAST == direction || NORTHWEST == direction)
this.ySign = -1;
else
this.ySign = 1;
if (NORTH == direction)
this.cursor = Cursor.N_RESIZE_CURSOR;
else if (SOUTH == direction)
this.cursor = Cursor.S_RESIZE_CURSOR;
else if (EAST == direction)
this.cursor = Cursor.E_RESIZE_CURSOR;
else if (WEST == direction)
this.cursor = Cursor.W_RESIZE_CURSOR;
else if (NORTHEAST == direction)
this.cursor = Cursor.NE_RESIZE_CURSOR;
else if (SOUTHEAST == direction)
this.cursor = Cursor.SE_RESIZE_CURSOR;
else if (SOUTHWEST == direction)
this.cursor = Cursor.SW_RESIZE_CURSOR;
else if (NORTHWEST == direction)
this.cursor = Cursor.NW_RESIZE_CURSOR;
}
/**
* Set the resize direction based on which point on the frame was picked (if a point on the left of the frame is
* picked, the resize direction is west, if a point on the top edge is picked the resize direction is north, etc).
*
* @param pickPoint The point on the frame that was picked.
*/
protected void setDirectionFromPoint(Point pickPoint)
{
Point topLeft = this.getScreenPoint();
Dimension size = this.getSize();
if (topLeft == null || size == null)
return;
// Find the center of the frame
Point center = new Point(topLeft.x + size.width / 2, topLeft.y + size.height / 2);
// Find horizontal and vertical distance from pick point to center point
int dy = center.y - pickPoint.y;
int dx = pickPoint.x - center.x;
// Use the sign of dx and dy to determine if we are resizing up or down, left or right
int vdir = (dy > 0) ? NORTH : SOUTH;
int hdir = (dx > 0) ? EAST : WEST;
// Compare the aspect ratio of the frame to the aspect ratio of the rectangle formed by the pick point and the
// center point. If the aspect ratios are close to equal, resize both horizontally and vertically. Otherwise,
// resize only horizontally or only vertically.
double frameAspectRatio = (double) size.width / size.height;
double pickAspectRatio = Math.abs((double) dx / dy);
int dir;
double tolerance = frameAspectRatio * 0.1;
if (Math.abs(pickAspectRatio - frameAspectRatio) < tolerance)
dir = hdir + vdir;
else if (pickAspectRatio < frameAspectRatio)
dir = vdir;
else
dir = hdir;
this.setDirection(dir);
}
/**
* Is the control currently dragging?
*
* @return True if the control is dragging.
*/
public boolean isDragging()
{
return this.dragging;
}
/**
* Handle a {@link gov.nasa.worldwind.event.SelectEvent} and call {@link #beginDrag}, {@link #drag}, {@link
* #endDrag} as appropriate. Subclasses may override this method if they need to handle events other than drag
* events.
*
* @param event Select event.
*/
@Override
public void selected(SelectEvent event)
{
if (event == null || this.isConsumed(event))
return;
Point pickPoint = event.getPickPoint();
if (pickPoint != null)
{
if (event.isDrag())
{
if (!this.isDragging())
{
this.dragging = true;
this.beginDrag(pickPoint);
}
this.drag(pickPoint);
event.consume();
}
}
if (event.isDragEnd())
{
this.dragging = false;
this.endDrag();
event.consume();
}
}
/**
* Update the resize cursor when the mouse moves.
*
* @param e Mouse event.
*/
@Override
public void mouseMoved(MouseEvent e)
{
if (e == null || e.isConsumed())
return;
this.setDirectionFromPoint(e.getPoint());
}
protected void beginDrag(Point point)
{
this.dragRefPoint = point;
this.refSize = this.getSize();
this.refLocation = this.getScreenPoint();
}
public void drag(Point point)
{
int deltaX = 0;
int deltaY = 0;
if (this.refLocation == null || this.refSize == null)
return;
if (this.allowHorizontalResize)
deltaX = (point.x - this.dragRefPoint.x) * this.xSign;
if (this.allowVerticalResize)
deltaY = (point.y - this.dragRefPoint.y) * this.ySign;
int width = this.refSize.width + deltaX;
int height = this.refSize.height + deltaY;
if (this.isValidSize(width, height))
{
this.setSize(new Dimension(width, height));
if (this.adjustLocationX || this.adjustLocationY)
{
double x = this.refLocation.x - (this.adjustLocationX ? deltaX : 0);
double y = this.refLocation.y - (this.adjustLocationY ? deltaY : 0);
this.setScreenPoint(new Point((int) x, (int) y));
}
}
}
/** Called when a drag action ends. This implementation sets {@link #dragRefPoint} to null. */
protected void endDrag()
{
this.dragRefPoint = null;
}
/**
* Get a cursor for the type of resize that this hotspot handles.
*
* @return New cursor.
*/
@Override
public Cursor getCursor()
{
return Cursor.getPredefinedCursor(this.cursor);
}
/**
* {@inheritDoc}
*
* Overridden to reset state when the mouse leaves the resize area.
*
* @param active {@code true} if the HotSpot is being activated, {@code false} if it is being deactivated.
*/
@Override
public void setActive(boolean active)
{
// If the resize area is being deactivated, reset the cursor so that the next time the HotSpot becomes active
// we won't show the wrong cursor.
if (!active)
this.cursor = Cursor.DEFAULT_CURSOR;
super.setActive(active);
}
/**
* Is a frame size valid? This method is called before attempting to resize the frame. If this method returns false,
* the resize operation is not attempted. This implementation ensures that the proposed frame size is greater than
* or equal to the minimum frame size.
*
* @param width Frame width.
* @param height Frame height.
*
* @return True if this frame size is valid.
*
* @see #getMinimumSize()
*/
protected boolean isValidSize(int width, int height)
{
Dimension minSize = this.getMinimumSize();
return width >= minSize.width && height >= minSize.height;
}
/**
* Get the minimum size of the frame. The user is not allowed to resize the frame to be smaller than this size. This
* implementation returns 0, 0.
*
* @return Minimum frame size.
*
* @see #isValidSize(int, int)
*/
protected Dimension getMinimumSize()
{
return new Dimension(0, 0);
}
/**
* Get the size of the frame.
*
* @return Frame size in pixels.
*/
protected abstract Dimension getSize();
/**
* Set the size of the frame.
*
* @param newSize New frame size in pixels.
*/
protected abstract void setSize(Dimension newSize);
/**
* Get the screen point of the upper left corner of the frame.
*
* @return Screen point measured from upper left corner of the screen (AWT coordinates).
*/
protected abstract Point getScreenPoint();
/**
* Set the screen point of the upper left corner of the frame.
*
* @param newPoint New screen point measured from upper left corner of the screen (AWT coordinates).
*/
protected abstract void setScreenPoint(Point newPoint);
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy