/*
* Licensed Materials - Property of Perforce Software, Inc.
* © Copyright Perforce Software, Inc. 2014, 2021
* © Copyright IBM Corp. 2009, 2014
* © Copyright ILOG 1996, 2009
* All Rights Reserved.
*
* Note to U.S. Government Users Restricted Rights:
* The Software and Documentation were developed at private expense and
* are "Commercial Items" as that term is defined at 48 CFR 2.101,
* consisting of "Commercial Computer Software" and
* "Commercial Computer Software Documentation", as such terms are
* used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
* as applicable.
*/
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import ilog.views.IlvManagerView;
import ilog.views.IlvManagerViewInteractor;
import ilog.views.IlvPoint;
import ilog.views.IlvRect;
import ilog.views.IlvTransformer;
import ilog.views.interactor.IlvPermanentInteractorInterface;
/**
* This interactor displays a rectangle which locks every nodes that intersect
* it.
*
* @author kaplan
* @since JViews 8.0
* @proofread
*/
public class RectangleInteractor extends IlvManagerViewInteractor implements IlvPermanentInteractorInterface {
private static final String ILLEGAL_SIZE = "size should be strictly greater than zero";
private int _size = 128;
final private IlvRect _rect = new IlvRect(0, 0, 128, 128);
private IlvRect _previousRect = null;
private boolean _dragging = false;
private boolean _permanent = true;
private boolean _allowDraw = true;
private ContentDemo _source;
/**
* Constructs and initializes a new instance of the
* <code>RectangleInteractor</code>.
*
* @param source
*/
public RectangleInteractor(ContentDemo source) {
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
_source = source;
}
Override
protected void attach(IlvManagerView view) {
view.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
super.attach(view);
}
/**
* Called when the interactor is detached from the view.
*/
Override
protected void detach() {
if (_dragging && _previousRect != null) { // remove traces
// _previousRect is stored in view's coords
_dragging = false;
getManagerView().invalidateRect(_previousRect);
_previousRect = null;
getManagerView().reDrawViews();
}
getManagerView().setCursor(Cursor.getDefaultCursor());
super.detach();
}
/**
* Sets the size of the rectangle.
*
* @param size
* The size to be set, in manager view coordinate values.
* @see #getSize
*/
public final void setSize(int size) {
if (size < 0)
throw new IllegalArgumentException(ILLEGAL_SIZE);
if (size != _size) {
int oldsize = _size;
_size = size;
_rect.width = _size;
_rect.height = _size;
if (_dragging) {
if (_previousRect != null) {
getManagerView().invalidateRect(_previousRect);
_previousRect = null;
}
_rect.move(_rect.x + (oldsize - size) / 2, _rect.y + (oldsize - size) / 2);
getManagerView().invalidateRect(_rect);
getManagerView().reDrawViews();
}
}
}
/**
* Returns the size of the rectangle in manager view coordinates. The default
* value is <code>128</code>.
*
* @return size
* @see #setSize
* @beaninfo
*/
public final int getSize() {
return _size;
}
/**
* Processes the mouse events. The rectangle appears when a mouse button is
* pressed. It is removed when a mouse button is released.
*
* @param e
* The mouse event.
*/
Override
protected void processMouseEvent(MouseEvent e) {
super.processMouseEvent(e);
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
_dragging = true;
final IlvPoint p = new IlvPoint(e.getX(), e.getY());
_rect.move(p.x - _rect.width * .5, p.y - _rect.height * .5);
getManagerView().invalidateRect(getDrawingRect());
getManagerView().reDrawViews();
callLockArea();
}
if (e.getID() == MouseEvent.MOUSE_RELEASED) {
_dragging = false;
if (_previousRect != null)
getManagerView().invalidateRect(_previousRect);
_previousRect = null;
getManagerView().reDrawViews();
if (!_permanent && getManagerView() != null)
getManagerView().popInteractor();
}
}
private void callLockArea() {
IlvRect drect = getDrawingRect();
IlvTransformer transformer = getTransformer();
transformer.boundingBox(drect, true);
// callback
_source.lockArea(drect);
}
/**
* Processes the mouse motion events. When the mouse is dragged, the rectangle
* is moved over the view.
*
* @param e
* The mouse motion event.
*/
Override
protected void processMouseMotionEvent(MouseEvent e) {
super.processMouseMotionEvent(e);
if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
IlvManagerView view = getManagerView();
if (view != null) {
IlvTransformer transformer = getTransformer();
final IlvPoint p = new IlvPoint(e.getX(), e.getY());
_rect.move(p.x - _rect.width * .5, p.y - _rect.height * .5);
IlvRect drect = getDrawingRect();
transformer.boundingBox(drect, true);
if (_previousRect != null)
transformer.boundingBox(_previousRect, true);
_allowDraw = false;
ensureVisible(p);
_allowDraw = true;
// transformer may have changed
transformer = getTransformer();
transformer.boundingBox(drect, false);
if (_previousRect != null)
transformer.boundingBox(_previousRect, false);
if (_previousRect != null)
// _previousRect is stored in view's coords
view.invalidateRect(_previousRect);
// and invalidate the new bbox
view.invalidateRect(drect);
// find a better way to do this
_previousRect = null;
// callback
callLockArea();
// redraw the region of the view where our
// graphic object has been drawn the previous time, as well
// as the graphic object in its new position
view.reDrawViews();
}
}
}
/**
* Called by the view when the view is drawn,;it actually calls the method
* that draws the rectangle using {@link #drawSensitiveArea}.
*
* @param g
* The view graphics.
*/
Override
protected void handleExpose(Graphics g) {
if (_dragging && _allowDraw) {
Rectangle clip = g.getClipBounds();
Dimension size = getManagerView().getSize();
Rectangle area = new Rectangle(Math.max(0, (int) Math.floor(_rect.x)), Math.max(0, (int) Math.floor(_rect.y)),
Math.min((int) Math.floor(size.width - _rect.x), (int) Math.floor(_rect.width)),
Math.min((int) Math.floor(size.height - _rect.y), (int) Math.floor(_rect.height)));
if (clip.contains(area)) {
draw(g);
} else if (clip.intersects(area)) {
// we are updating a clipping zone that may impact the rectangle
// even if the rectangle is not entirely in the clipping zone.
getManagerView().invalidateRect(_rect);
getManagerView().reDrawViews();
draw(g);
}
}
}
/**
* Returns a copy of the rectangle that drives this interactor.
*
* @return drawing rectangle
*/
protected IlvRect getDrawingRect() {
return new IlvRect(_rect);
}
private void draw(Graphics g) {
if (_previousRect == null)
_previousRect = new IlvRect();
IlvRect currentRect = getDrawingRect();
_previousRect.reshape(currentRect.x, currentRect.y, currentRect.width, currentRect.height);
drawSensitiveArea(g);
}
/**
* Draws the rectangle. If you redefine this method to add additional
* drawings, you must also redefine the {@link #getDrawingRect} method to
* return a rectangle containing the additional drawings.
*
* @param g
* The view graphics.
*/
protected void drawSensitiveArea(Graphics g) {
int cx = (int) Math.floor(_rect.x + _rect.width / 2);
int cy = (int) Math.floor(_rect.y + _rect.height / 2);
int x = cx - (int) Math.floor(_rect.width / 2);
int y = cy - (int) Math.floor(_rect.height / 2);
int w = (int) Math.floor(_rect.width);
int h = (int) Math.floor(_rect.height);
g.setColor(Color.black);
g.drawRect(x, y, w, h);
}
// IlvPermanentInteractorInterface implementation
/**
* Returns <code>false</code> if the interactor will be removed from the view
* once the object was created. The default value is <code>false</code>.
*
* @beaninfo
*/
Override
public final boolean isPermanent() {
return _permanent;
}
/**
* Allows you to specify if the interactor will or will not be removed from
* the view once the object is created. The default value is
* <code>false</code>.
*
* @param permanent
* If <code>true</code> the interactor will be removed, otherwise
* not.
*/
Override
public final void setPermanent(boolean permanent) {
_permanent = permanent;
}
}