// Copyright (c) 1996-98 The Regents of the University of California. All
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation for educational, research and non-profit
// purposes, without fee, and without a written agreement is hereby granted,
// provided that the above copyright notice and this paragraph appear in all
// copies. Permission to incorporate this software into commercial products may
// be obtained by contacting the University of California. David F. Redmiles
// Department of Information and Computer Science (ICS) University of
// California Irvine, California 92697-3425 Phone: 714-824-3823. This software
// program and documentation are copyrighted by The Regents of the University
// of California. The software program and documentation are supplied "as is",
// without any accompanying services from The Regents. The Regents do not
// warrant that the operation of the program will be uninterrupted or
// error-free. The end-user understands that the program was developed for
// research purposes and is advised not to rely exclusively on the program for
// any reason. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY
// PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
// DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY
// DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
// SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
// ENHANCEMENTS, OR MODIFICATIONS.
// File: ModeModify.java
// Classes: ModeModify
// Original Author: ics125b spring 1996
// $Id: ModeModify.java,v 1.13 1997/06/10 23:43:12 jrobbins Exp $
package uci.graphedit;
import java.awt.Event;
import java.awt.Point;
/** A Mode to process events from the Editor when the user is
* modifying a DiagramElement. Right now users can drag one or more
* DiagramElement's around the drawing area, or they can move a handle
* on a single DiagramElement. The DiagramElement is responsible for
* reacting to the movement of a handle, but so far they all resize
* themselves. In the future, some DiagramElement's may have handles
* that set properties other than size (e.g., spline curvature).
*
* FEATURE: editing_modes_modify
*/
public class ModeModify extends Mode {
/** The point relative to the original postition of the
* DiagramElement where the dragging started. Keeping this point
* allows the user to "grip" any part of the DiagramElement, rather
* than just dragging its position (or "pin") around. */
protected Point _anchor;
/** the mouse location for the most recent drag event */
protected int _lastX = 1000, _lastY = 1000;
/** the mouse location for the first mouse down event*/
protected int _startX, _startY;
/** has the mouse moved enough to indicate that the user really
* wants to modify somthing? */
protected boolean _minDeltaAchieved;
/** Minimum amoun that the user must move the mouse to indicate that he
* really wants to modify something. */
public static final int MIN_DELTA = 4;
/** the ID of the handle that the user is dragging */
protected Handle _curHandle = new Handle(-1);
public static final int NO_CONSTRAINT = 0;
public static final int HORIZONTAL_CONSTRAINT = 1;
public static final int VERTICAL_CONSTRAINT = 2;
protected int _constraint = NO_CONSTRAINT;
/** Construct a new ModeModify with the given parent, and set the
* Anchor point to a default location (the _anchor's proper position
* will be determioned on mouse down). */
ModeModify(Editor par) {
super(par);
_anchor = new Point(0,0);
}
private static Point snapPt = new Point(0, 0);
/** When the user drags the mouse two things can happen: (1) if the
* user is dragging the body of one or more DiagramElement's then
* they are all moved around the drawing area, or (2) if the user
* started dragging on a handle of one DiagramElement then the user
* can drag the handle around the drawing area and the
* DiagramElement reacts to that.
*
* FEATURE: drag_object
*
* FEATURE: drag_object_constrained
*
* FEATURE: drag_handle
*
* FEATURE: drag_handle_constrained
*
* FEATURE: locked_objects
*
* BUG: arc_translate
*/
public boolean mouseDrag(Event e, int x, int y) {
int dx, dy, snapX, snapY;
if (!checkMinDelta(x, y)) return true;
Selection sel = parent.selection();
if (sel.locked()) {
Globals.showStatus("Cannot Modify Locked Objects");
return true;
}
synchronized (snapPt) {
snapPt.move(x, y);
parent.snap(snapPt);
snapX = snapPt.x;
snapY = snapPt.y;
}
dx = snapX - _lastX;
dy = snapY - _lastY;
if (e.controlDown() && _constraint == NO_CONSTRAINT) {
if (dx != 0) _constraint = HORIZONTAL_CONSTRAINT;
if (dy != 0) _constraint = VERTICAL_CONSTRAINT;
}
if (_constraint == HORIZONTAL_CONSTRAINT) dy = 0;
if (_constraint == VERTICAL_CONSTRAINT) dx = 0;
if (dx == 0 && dy == 0) return true;
sel.startTrans();
if (_curHandle.index == -1) sel.translate(dx, dy);
else sel.dragHandle(snapX, snapY, _anchor.x, _anchor.y, _curHandle);
sel.endTrans();
_lastX = snapX; _lastY = snapY;
return true;
}
/** When the user presses the mouse button on a DiagramElement,
* this Mode starts preparing for future drag events by finding if
* a handle was clicked on. This event is passed from ModeSelect. */
public boolean mouseDown(Event e, int x, int y) {
start();
Selection sel = parent.selection();
if (sel.isEmpty()) { done(); }
if (sel.locked()) {
Globals.showStatus("Cannot Modify Locked Objects");
return true;
}
/* needs-more-work: _anchor point sign convention is backwards */
_anchor.x = sel.position().x - x;
_anchor.y = sel.position().y - y;
_curHandle.index = sel.pickHandle(x, y);
sel.endTrans();
synchronized (snapPt) {
snapPt.move(x, y);
parent.snap(snapPt);
_startX = _lastX = snapPt.x;
_startY = _lastY = snapPt.y;
}
return true;
}
/** On mouse up the modification interaction is done. */
public boolean mouseUp(Event e, int x, int y) {
done();
return true;
}
public void start() {
_minDeltaAchieved = false;
super.start();
}
/** Reply true if the user had moved the mouse enough to signify
* that (s)he really wants to make a change.
*
* FEATURE: minimum_modify_delta
*/
public boolean checkMinDelta(int x, int y) {
if (x > _startX + MIN_DELTA ||
x < _startX - MIN_DELTA ||
y > _startY + MIN_DELTA ||
y < _startY - MIN_DELTA)
_minDeltaAchieved = true;
return _minDeltaAchieved;
}
} /* end class ModeModify */