/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.participant; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Cursor; import java.awt.Shape; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.IMouseCursorContext; import org.simantics.g2d.canvas.IMouseCursorHandle; import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant; import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; import org.simantics.g2d.diagram.DiagramHints; import org.simantics.g2d.diagram.handler.PickContext; import org.simantics.g2d.diagram.participant.Selection; import org.simantics.g2d.diagram.participant.pointertool.AbstractMode; import org.simantics.g2d.participant.MouseUtil.MouseInfo; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.g2d.events.Event; import org.simantics.scenegraph.g2d.events.MouseEvent; import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent; import org.simantics.scenegraph.g2d.events.command.CommandEvent; import org.simantics.scenegraph.g2d.events.command.Commands; import org.simantics.scenegraph.g2d.nodes.ShapeNode; import org.simantics.utils.ObjectUtils; import org.simantics.utils.page.MarginUtils; /** * ZoomToAreaHandler starts an area zoom mode when a ZOOM_TO_AREA command is * issued. * * @author Tuukka Lehtonen */ public class ZoomToAreaHandler extends AbstractCanvasParticipant { public final static Cursor ZOOM_CURSOR = new Cursor(Cursor.CROSSHAIR_CURSOR); @EventHandler(priority = 0) public boolean handleZoomToArea(CommandEvent event) { if (Commands.ZOOM_TO_AREA.equals( event.command )) { if (!getContext().containsItemByClass(ZoomToAreaMode.class)) { getContext().add( new ZoomToAreaMode() ); setDirty(); } return true; } return false; } class ZoomToAreaMode extends AbstractMode { @Dependency TransformUtil util; @Dependency Selection selection; @Dependency PickContext pickContext; @Dependency KeyUtil keyUtil; @Dependency MouseUtil mouseUtil; @Dependency CanvasBoundsParticipant canvasBounds; public final BasicStroke STROKE = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 10f, new float[] {4,2}, 0); public static final int PAINT_PRIORITY = 30; Point2D startingPoint; Point2D currentPoint; IMouseCursorHandle cursor; public ZoomToAreaMode() { super(0); } @Override public void addedToContext(ICanvasContext ctx) { super.addedToContext(ctx); IMouseCursorContext mctx = getContext().getMouseCursorContext(); if (mctx != null) cursor = mctx.setCursor(getMouseId(), ZOOM_CURSOR); MouseInfo mi = mouseUtil.getMouseInfo(getMouseId()); if (mi != null) currentPoint = mi.canvasPosition; } @Override public void removedFromContext(ICanvasContext ctx) { if (cursor != null) { cursor.remove(); cursor = null; } super.removedFromContext(ctx); } @EventHandler(priority = 10) public boolean handleEvent(Event e) { if (e instanceof CommandEvent) { CommandEvent ce = (CommandEvent) e; if (ce.command.equals( Commands.CANCEL )){ setDirty(); remove(); return true; } } else if (e instanceof MouseMovedEvent) { MouseMovedEvent event = (MouseMovedEvent) e; if (event.mouseId != getMouseId()) return false; Point2D canvasPos = util.controlToCanvas(event.controlPosition, null); if (!ObjectUtils.objectEquals(currentPoint, canvasPos)) { currentPoint = canvasPos; update(getBox()); setDirty(); } return false; } else if (e instanceof MouseButtonEvent) { MouseButtonEvent event = (MouseButtonEvent) e; if (event.mouseId != getMouseId()) return false; if (event.button != MouseEvent.LEFT_BUTTON) return false; // Eat all other mouse button events besides press and click. // Must use mouse clicks here because otherwise selection // participants etc. might alter selections on the next incoming // mouse click event, which only confuses the user. if (e instanceof MouseClickEvent) { Point2D canvasPos = util.controlToCanvas(event.controlPosition, null); currentPoint = canvasPos; if (startingPoint == null) { // Start marking the box startingPoint = currentPoint; setDirty(); return true; } Rectangle2D area = new Rectangle2D.Double(); area.setFrameFromDiagonal(startingPoint, currentPoint); Rectangle2D controlArea = canvasBounds.getControlBounds(); util.fitArea(controlArea, area, PanZoomRotateHandler.getZoomToFitMargins(getHintStack())); setDirty(); remove(); return true; } return true; } return false; } /** * Get selection box in control coordinates * @return control coordinates */ protected Rectangle2D getBox() { if (startingPoint == null) return null; Point2D p1 = startingPoint; Point2D p2 = currentPoint; double ax = p1.getX(); double ay = p1.getY(); double bx = p2.getX(); double by = p2.getY(); if (bx < ax) { double temp = ax; ax = bx; bx = temp; } if (by < ay) { double temp = ay; ay = by; by = temp; } return new Rectangle2D.Double(ax, ay, bx - ax, by - ay); } protected Path2D getCrossHair(Rectangle2D controlBounds) { Point2D controlPos = util.canvasToControl(currentPoint, null); Path2D path = new Path2D.Double(); path.moveTo(controlBounds.getMinX(), controlPos.getY()); path.lineTo(controlBounds.getMaxX(), controlPos.getY()); path.moveTo(controlPos.getX(), controlBounds.getMinY()); path.lineTo(controlPos.getX(), controlBounds.getMaxY()); return path; } public synchronized Color getToolColor() { Color c = getHint(DiagramHints.KEY_SELECTION_FRAME_COLOR); if (c!=null) return c; return Color.BLACK; } protected ShapeNode node = null; @SGInit public void initSG(G2DParentNode parent) { node = parent.addNode("zoom to area", ShapeNode.class); node.setZIndex(PAINT_PRIORITY); node.setStroke(STROKE); node.setScaleStroke(true); node.setColor(getToolColor()); node.setFill(false); } void update(Shape shape) { if (node != null) { node.setShape(shape); } } @SGCleanup public void cleanupSG() { if (node != null) { node.remove(); node = null; } } } }