/* * 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; } }