/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ /* * Copyright (c) 2002-@year@, University of Maryland * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list of conditions * and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the * distribution. * * Neither the name of the University of Maryland nor the names of its contributors may be used to * endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Piccolo was written at the Human-Computer Interaction Laboratory www.cs.umd.edu/hcil by Jesse Grosjean * under the supervision of Ben Bederson. The Piccolo website is www.cs.umd.edu/hcil/piccolo. */ package de.cismet.cismap.commons.gui.piccolo; import edu.umd.cs.piccolo.PNode; import edu.umd.cs.piccolo.event.PBasicInputEventHandler; import edu.umd.cs.piccolo.event.PDragSequenceEventHandler; import edu.umd.cs.piccolo.event.PInputEvent; import edu.umd.cs.piccolo.event.PInputEventFilter; import edu.umd.cs.piccolo.nodes.PPath; import edu.umd.cs.piccolo.util.PAffineTransform; import edu.umd.cs.piccolo.util.PBounds; import edu.umd.cs.piccolo.util.PDimension; import edu.umd.cs.piccolox.util.PLocator; import java.awt.Color; import java.awt.Shape; import java.awt.event.InputEvent; import java.awt.geom.Ellipse2D; import java.awt.geom.Point2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.ObjectInputStream; import de.cismet.cismap.commons.gui.MappingComponent; /** * <b>PHandle</b> is used to modify some aspect of Piccolo when it is dragged. Each handle has a PLocator that it uses * to automatically position itself. See PBoundsHandle for an example of a handle that resizes the bounds of another * node. * * @author Jesse Grosjean * @version 1.0 */ public class PHandle extends PPath { //~ Static fields/initializers --------------------------------------------- public static final double DEFAULT_HANDLE_SIZE = 8; public static final Shape DEFAULT_HANDLE_SHAPE = new Ellipse2D.Double( 0f, 0f, DEFAULT_HANDLE_SIZE, DEFAULT_HANDLE_SIZE); // public static Shape DEFAULT_HANDLE_SHAPE = new Rectangle.Double(0f, 0f, DEFAULT_HANDLE_SIZE, // DEFAULT_HANDLE_SIZE); public static final Color DEFAULT_COLOR = new Color(1f, 1f, 1f, 0.4f); // Color.white; public static final Color DEFAULT_SELECTED_COLOR = Color.red; private static PAffineTransform TEMP_TRANSFORM = new PAffineTransform(); //~ Instance fields -------------------------------------------------------- boolean inDragOperation = false; private final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(this.getClass()); private PLocator locator; private PDragSequenceEventHandler handleDragger; private boolean selected = false; private MappingComponent mc = null; //~ Constructors ----------------------------------------------------------- /** * Construct a new handle that will use the given locator to locate itself on its parent node. * * @param aLocator DOCUMENT ME! * @param mc DOCUMENT ME! */ public PHandle(final PLocator aLocator, final MappingComponent mc) { // super(new Rectangle2D.Double(0f, 0f, 1f,1f)); super(DEFAULT_HANDLE_SHAPE); this.mc = mc; // setStroke(new FixedWidthStroke()); // log.fatal("Scale:"+((double)(DEFAULT_HANDLE_SIZE/PPaintContext.CURRENT_PAINT_CONTEXT.getScale()))); locator = aLocator; setPaint(getDefaultColor()); installHandleEventHandlers(); startResizeBounds(); relocateHandle(); } //~ Methods ---------------------------------------------------------------- /** * DOCUMENT ME! * * @return DOCUMENT ME! */ protected Color getDefaultColor() { return DEFAULT_COLOR; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ protected Color getDefaultSelectedColor() { return DEFAULT_SELECTED_COLOR; } /** * zum \u00FCberschreiben. */ public void removeHandle() { } /** * DOCUMENT ME! */ public void duplicateHandle() { } /** * DOCUMENT ME! */ protected void installHandleEventHandlers() { handleDragger = new PDragSequenceEventHandler() { @Override protected void startDrag(final PInputEvent event) { if (log.isDebugEnabled()) { log.debug("Handle Start Drag"); // NOI18N } super.startDrag(event); inDragOperation = true; startHandleDrag(event.getPositionRelativeTo(PHandle.this), event); } @Override protected void drag(final PInputEvent event) { if (log.isDebugEnabled()) { log.debug("Handle Drag"); // NOI18N } super.drag(event); final PDimension aDelta = event.getDeltaRelativeTo(PHandle.this); if ((aDelta.getWidth() != 0) || (aDelta.getHeight() != 0)) { dragHandle(aDelta, event); } } @Override protected void endDrag(final PInputEvent event) { if (log.isDebugEnabled()) { log.debug("Handle End Drag"); // NOI18N } super.endDrag(event); inDragOperation = false; endHandleDrag(event.getPositionRelativeTo(PHandle.this), event); } }; addPropertyChangeListener(PNode.PROPERTY_TRANSFORM, new PropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent evt) { relocateHandle(); } }); handleDragger.setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); handleDragger.getEventFilter().setMarksAcceptedEventsAsHandled(true); handleDragger.getEventFilter().setAcceptsMouseEntered(false); handleDragger.getEventFilter().setAcceptsMouseExited(false); handleDragger.getEventFilter().setAcceptsMouseMoved(false); // no need for moved events for handle interaction, // so reject them so we don't consume them addInputEventListener(handleDragger); // Test final PBasicInputEventHandler moveAndClickListener = new PBasicInputEventHandler() { @Override public void mouseClicked(final edu.umd.cs.piccolo.event.PInputEvent pInputEvent) { if (log.isDebugEnabled()) { log.debug("Handle Mouse Clicked"); // NOI18N } handleClicked(pInputEvent); } @Override public void mouseMoved(final edu.umd.cs.piccolo.event.PInputEvent pInputEvent) { // log.debug("Handle Mouse Moved"); if (!inDragOperation) { mouseMovedNotInDragOperation(pInputEvent); } } }; addInputEventListener(moveAndClickListener); } /** * Return the event handler that is responsible for the drag handle interaction. * * @return DOCUMENT ME! */ public PDragSequenceEventHandler getHandleDraggerHandler() { return handleDragger; } /** * Get the locator that this handle uses to position itself on its parent node. * * @return DOCUMENT ME! */ public PLocator getLocator() { return locator; } /** * Set the locator that this handle uses to position itself on its parent node. * * @param aLocator DOCUMENT ME! */ public void setLocator(final PLocator aLocator) { locator = aLocator; invalidatePaint(); relocateHandle(); } // **************************************************************** // Handle Dragging - These are the methods the subclasses should // normally override to give a handle unique behavior. // **************************************************************** /** * Override this method to get notified when the handle starts to get dragged. * * @param aLocalPoint DOCUMENT ME! * @param aEvent DOCUMENT ME! */ public void startHandleDrag(final Point2D aLocalPoint, final PInputEvent aEvent) { } /** * Override this method to get notified as the handle is dragged. * * @param aLocalDimension DOCUMENT ME! * @param aEvent DOCUMENT ME! */ public void dragHandle(final PDimension aLocalDimension, final PInputEvent aEvent) { } /** * Override this method to get notified when the handle stops getting dragged. * * @param aLocalPoint DOCUMENT ME! * @param aEvent DOCUMENT ME! */ public void endHandleDrag(final Point2D aLocalPoint, final PInputEvent aEvent) { } /** * DOCUMENT ME! * * @param pInputEvent DOCUMENT ME! */ public void handleClicked(final edu.umd.cs.piccolo.event.PInputEvent pInputEvent) { } /** * DOCUMENT ME! * * @param pInputEvent DOCUMENT ME! */ public void mouseMovedNotInDragOperation(final edu.umd.cs.piccolo.event.PInputEvent pInputEvent) { } // **************************************************************** // Layout - When a handle's parent's layout changes the handle // invalidates its own layout and then repositions itself on its // parents bounds using its locator to determine that new // position. // **************************************************************** @Override public void setParent(final PNode newParent) { super.setParent(newParent); relocateHandle(); } @Override public void parentBoundsChanged() { relocateHandle(); } /** * Force this handle to relocate itself using its locator. */ public void relocateHandle() { if (locator != null) { final PBounds b = getBoundsReference(); final Point2D aPoint = locator.locatePoint(null); // log.fatal("*vorher:" + aPoint); mc.getCamera().viewToLocal(aPoint); // log.fatal("*nachher:" + aPoint); // if (locator instanceof PNodeLocator) { // PNode located = ((PNodeLocator)locator).getNode(); // PNode parent = getParent(); // // located.localToGlobal(aPoint); // globalToLocal(aPoint); // // if (parent != located && parent instanceof PCamera) { // ((PCamera)parent).viewToLocal(aPoint); // } // } final double newCenterX = aPoint.getX(); final double newCenterY = aPoint.getY(); if ((newCenterX != b.getCenterX()) || (newCenterY != b.getCenterY())) { this.setBounds(0, 0, DEFAULT_HANDLE_SIZE, DEFAULT_HANDLE_SIZE); centerBoundsOnPoint(newCenterX, newCenterY); } } } /** * Serialization.**************************************************************** * * @param in DOCUMENT ME! * * @throws IOException DOCUMENT ME! * @throws ClassNotFoundException DOCUMENT ME! */ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); installHandleEventHandlers(); } /** * double scale=-1; public void paint(PPaintContext aPaintContext) { super.paint(aPaintContext); //// double * newscale=aPaintContext.getScale(); //// if (scale!=newscale) { //// double * xxx=(double)(DEFAULT_HANDLE_SIZE/newscale); //// this.scale(1/aPaintContext.getScale()); //// } // // // // * double newscale=aPaintContext.getScale(); // if (scale!=newscale) { // // // double * xxx=(double)(DEFAULT_HANDLE_SIZE/newscale); //log.fatal("Breite:"+xxx+ "(x,y): * ("+(double)locator.locateX()+","+(double)locator.locateY()+")"); // * setBounds((double)locator.locateX()-(xxx/2),(double)locator.locateY()+(xxx/2), xxx,xxx); // * //setPathToEllipse((double)0, (double)0, xxx,xxx); // // //centerBoundsOnPoint((double)locator.locateX(), * (double)locator.locateY()); // scale=newscale; // } } public void setPathToEllipse(double x, double y, double * width, double height) { TEMP_ELLIPSE.setFrame(x, y, width, height); setPathTo(TEMP_ELLIPSE); } //private static * final Ellipse2D.Double TEMP_ELLIPSE = new Ellipse2D.Double(); private static final Rectangle2D.Double * TEMP_ELLIPSE = new Rectangle2D.Double(); * * @return DOCUMENT ME! */ public boolean isSelected() { return selected; } /** * DOCUMENT ME! * * @param selected DOCUMENT ME! */ public void setSelected(final boolean selected) { this.selected = selected; if (selected) { setPaint(getDefaultSelectedColor()); } else { setPaint(getDefaultColor()); } repaint(); } }