1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
14 * @author Toni Kalajainen
\r
16 package org.simantics.g2d.participant;
\r
18 import java.awt.Cursor;
\r
19 import java.awt.geom.Point2D;
\r
21 import org.simantics.g2d.canvas.ICanvasContext;
\r
22 import org.simantics.g2d.canvas.IMouseCursorContext;
\r
23 import org.simantics.g2d.canvas.IMouseCursorHandle;
\r
24 import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;
\r
25 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
\r
26 import org.simantics.g2d.participant.MouseUtil.MouseInfo;
\r
27 import org.simantics.scenegraph.g2d.events.Event;
\r
28 import org.simantics.scenegraph.g2d.events.MouseEvent;
\r
29 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
\r
30 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyReleasedEvent;
\r
31 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;
\r
32 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;
\r
33 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;
\r
34 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent;
\r
35 import org.simantics.scenegraph.g2d.nodes.NavigationNode;
\r
36 import org.simantics.utils.datastructures.hints.IHintContext.Key;
\r
37 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
\r
42 * Keyboard pan & zoom & zoom to fit etc
\r
44 * This interactor depends on : - TransformUtil - MouseUtil - KeyUtil -
\r
45 * PanZoomRotateHandler
\r
47 * TODO Add rotate mode
\r
49 * @deprecated this logic has been moved into scenegraph {@link NavigationNode}.
\r
50 * Using this participant will cause double navigation.
\r
53 public class MousePanZoomInteractor extends AbstractCanvasParticipant {
\r
55 @Dependency TransformUtil util;
\r
56 @Dependency MouseUtil mice;
\r
57 @Dependency KeyUtil keys;
\r
58 @Dependency PanZoomRotateHandler pzr;
\r
60 /** Event priority for initiating pan / zoom */
\r
61 public final static int MOUSE_PAN_PRIORITY = Integer.MAX_VALUE - 2000;
\r
63 /** Event priority when panning is enabled */
\r
64 public final static int PAN_PRIORITY = Integer.MAX_VALUE - 1000;
\r
65 public final static int ZOOM_PRIORITY = Integer.MAX_VALUE - 1000 +1;
\r
67 /** Cursor when panning */
\r
68 public final static Cursor PAN_CURSOR = new Cursor(Cursor.MOVE_CURSOR);
\r
70 /** Cursor when panning */
\r
71 public final static Cursor ZOOM_CURSOR = new Cursor(Cursor.N_RESIZE_CURSOR);
\r
73 /** Is pan enabled */
\r
74 public final static Key KEY_MOUSE_PAN_ENABLED = new KeyOf(Boolean.class);
\r
76 /** Is zoom enabled */
\r
77 public final static Key KEY_MOUSE_ZOOM_ENABLED = new KeyOf(Boolean.class);
\r
79 /** are mouse wheel action enabled */
\r
80 public final static Key KEY_MOUSE_WHEEL_ZOOM_PAN_ENABLED = new KeyOf(Boolean.class);
\r
82 /** The speed of mouse zoom , eg 0..100..X */
\r
83 public final static Key KEY_MOUSE_ZOOM_SPEED = new KeyOf(Double.class);
\r
85 /** Default mouse zoom speed */
\r
86 public final static double DEFAULT_MOUSE_ZOOM_SPEED = 100;
\r
88 /** The speed of mouse zoom , eg 0..100..X */
\r
89 public final static Key KEY_MOUSE_WHEEL_ZOOM_SPEED = new KeyOf(Double.class);
\r
91 /** Default mouse zoom speed */
\r
92 public final static double DEFAULT_MOUSE_WHEEL_ZOOM_SPEED = 1000;
\r
94 /** The speed of mouse zoom , eg 0..100..X */
\r
95 public final static Key KEY_MOUSE_WHEEL_TRANSLATE_AMOUNT = new KeyOf(Double.class);
\r
97 /** Default mouse zoom speed */
\r
98 public final static double DEFAULT_MOUSE_WHEEL_TRANSLATE_AMOUNT = 10;
\r
101 public void addedToContext(ICanvasContext ctx) {
\r
102 super.addedToContext(ctx);
\r
103 // Set Default values
\r
104 setHint(KEY_MOUSE_ZOOM_SPEED, DEFAULT_MOUSE_ZOOM_SPEED);
\r
105 setHint(KEY_MOUSE_ZOOM_ENABLED, true);
\r
106 setHint(KEY_MOUSE_PAN_ENABLED, true);
\r
107 setHint(KEY_MOUSE_WHEEL_ZOOM_PAN_ENABLED, true);
\r
108 setHint(KEY_MOUSE_WHEEL_ZOOM_SPEED, DEFAULT_MOUSE_WHEEL_ZOOM_SPEED);
\r
109 setHint(KEY_MOUSE_WHEEL_TRANSLATE_AMOUNT, DEFAULT_MOUSE_WHEEL_TRANSLATE_AMOUNT);
\r
113 * Inits mouse pan and zoom interactors.
\r
114 * Eats mouse presses if shift is pressed.
\r
119 @EventHandler(priority = MOUSE_PAN_PRIORITY)
\r
120 public boolean handleEvent(MouseEvent e) {
\r
121 assertDependencies();
\r
122 if (e.context instanceof MouseUtil)
\r
125 if ((e instanceof MouseButtonPressedEvent) && (e.stateMask & MouseEvent.SHIFT_MASK) != 0 && ((MouseButtonPressedEvent)e).button==MouseEvent.LEFT_BUTTON)
\r
128 // Mouse pan & zoom
\r
129 if (e instanceof MouseMovedEvent) {
\r
130 MouseMovedEvent mme = (MouseMovedEvent) e;
\r
131 MouseInfo mi = mice.getMouseInfo(mme.mouseId);
\r
134 if ((e.stateMask & MouseEvent.SHIFT_MASK) != 0 & mi.isMouseButtonPressed(MouseEvent.LEFT_BUTTON))
\r
136 if (!isPanEnabled())
\r
138 if (!isPanning()) {
\r
139 getContext().add( new PanMode(mme.mouseId, mme.controlPosition, MouseEvent.LEFT_BUTTON) );
\r
143 if (mi.isMouseButtonPressed(MouseEvent.MIDDLE_BUTTON))
\r
145 if (!isPanEnabled())
\r
147 if (!isPanning()) {
\r
148 getContext().add( new PanMode(mme.mouseId, mme.controlPosition, MouseEvent.MIDDLE_BUTTON) );
\r
152 if ((e.stateMask & MouseEvent.SHIFT_MASK) != 0 & mi.isMouseButtonPressed(MouseEvent.RIGHT_BUTTON))
\r
154 if (!isZoomEnabled())
\r
156 if (!isZooming()) {
\r
157 Point2D diagramPosition = util.getInverseTransform().transform(mme.controlPosition, new Point2D.Double());
\r
159 getContext().add( new ZoomMode(mme.mouseId, mme.controlPosition, diagramPosition, MouseEvent.RIGHT_BUTTON) );
\r
165 // Mouse wheel zoom / scroll
\r
166 if (e instanceof MouseWheelMovedEvent) {
\r
167 if (!isMouseWheelZoomPanEnabled())
\r
169 MouseWheelMovedEvent we = (MouseWheelMovedEvent) e;
\r
170 //if (!mm.isMouseButtonPressed(we.mouseId, MouseEvent.MIDDLE_BUTTON))
\r
174 if (we.scrollType == MouseWheelMovedEvent.WHEEL_UNIT_SCROLL)
\r
176 double dy = we.wheelRotation * getMouseWheelTranslateAmount();
\r
178 util.translateWithControlCoordinates(new Point2D.Double(dy, 0));
\r
180 util.translateWithControlCoordinates(new Point2D.Double(0, dy));
\r
186 if (we.scrollType == MouseWheelMovedEvent.WHEEL_UNIT_SCROLL)
\r
188 double dy = we.wheelRotation;
\r
189 double zoom = getMouseWheelZoomSpeed();
\r
190 double base = 1.00 + (zoom / 10000);
\r
191 double scaleFactor = Math.pow(base, dy);
\r
193 scaleFactor = pzr.limitScaleFactor(scaleFactor);
\r
194 util.zoomAroundControlPoint(scaleFactor, we.controlPosition);
\r
195 //ti.zoom(scaleFactor);
\r
203 public boolean isPanEnabled()
\r
205 Boolean h = getHint(KEY_MOUSE_PAN_ENABLED);
\r
206 if (h==null) return false;
\r
210 public boolean isPanning()
\r
212 return !getContext().getItemsByClass(PanMode.class).isEmpty();
\r
215 public boolean isZooming()
\r
217 return !getContext().getItemsByClass(ZoomMode.class).isEmpty();
\r
220 public boolean isZoomEnabled()
\r
222 Boolean h = getHint(KEY_MOUSE_ZOOM_ENABLED);
\r
223 if (h==null) return false;
\r
227 public boolean isMouseWheelZoomPanEnabled()
\r
229 Boolean h = getHint(KEY_MOUSE_WHEEL_ZOOM_PAN_ENABLED);
\r
230 if (h==null) return false;
\r
235 * is Shift key down
\r
238 /*public boolean shift()
\r
240 return keys.isKeyPressed(KeyEvent.VK_SHIFT);
\r
243 public boolean ctrl()
\r
245 return keys.isKeyPressed(KeyEvent.VK_CONTROL);
\r
248 public double getMouseZoomSpeed()
\r
250 Double h = getHint(KEY_MOUSE_ZOOM_SPEED);
\r
251 if (h==null) return DEFAULT_MOUSE_ZOOM_SPEED;
\r
255 public double getMouseWheelZoomSpeed()
\r
257 Double h = getHint(KEY_MOUSE_WHEEL_ZOOM_SPEED);
\r
258 if (h==null) return DEFAULT_MOUSE_WHEEL_ZOOM_SPEED;
\r
262 public double getMouseWheelTranslateAmount()
\r
264 Double h = getHint(KEY_MOUSE_WHEEL_TRANSLATE_AMOUNT);
\r
265 if (h==null) return DEFAULT_MOUSE_WHEEL_TRANSLATE_AMOUNT;
\r
270 * Shift and left mouse button is pressed, do panning
\r
272 class PanMode extends AbstractCanvasParticipant
\r
274 @Dependency TransformUtil util;
\r
277 // Mouse system coordinates
\r
279 IMouseCursorHandle cursor;
\r
281 public PanMode(int mouseId, Point2D mousePos, int releaseButton) {
\r
283 this.mouseId = mouseId;
\r
284 this.mousePos = new Point2D.Double(mousePos.getX(), mousePos.getY());
\r
285 this.releaseButton = releaseButton;
\r
289 public void addedToContext(ICanvasContext ctx) {
\r
290 super.addedToContext(ctx);
\r
291 IMouseCursorContext mctx = getContext().getMouseCursorContext();
\r
293 cursor = mctx.setCursor(mouseId, PAN_CURSOR);
\r
296 @EventHandler(priority = PAN_PRIORITY)
\r
297 public boolean handleEvent(Event e) {
\r
298 if (e instanceof MouseButtonReleasedEvent) {
\r
299 MouseButtonReleasedEvent mpe = (MouseButtonReleasedEvent) e;
\r
300 if (mpe.button == releaseButton && mpe.mouseId == mouseId)
\r
307 if (e instanceof KeyReleasedEvent) {
\r
308 KeyReleasedEvent ke = (KeyReleasedEvent) e;
\r
309 if (ke.keyCode == java.awt.event.KeyEvent.VK_SHIFT)
\r
316 if (e instanceof MouseMovedEvent) {
\r
317 if (e.getContext() instanceof MouseUtil) return true;
\r
318 MouseMovedEvent mme = (MouseMovedEvent) e;
\r
319 if (mme.mouseId == mouseId) {
\r
320 Point2D oldPos = mousePos;
\r
321 Point2D newPos = mme.controlPosition;
\r
323 double dx = newPos.getX() - oldPos.getX();
\r
324 double dy = newPos.getY() - oldPos.getY();
\r
325 if (dx==0 && dy==0) return true;
\r
327 this.mousePos.setLocation(newPos);
\r
329 util.translateWithControlCoordinates(new Point2D.Double(dx, dy));
\r
338 public void removedFromContext(ICanvasContext ctx) {
\r
339 if (cursor!=null) {
\r
343 super.removedFromContext(ctx);
\r
349 * Shift and right mouse button is pressed, do zooming
\r
351 class ZoomMode extends AbstractCanvasParticipant
\r
356 // Mouse system coordinates
\r
357 Point2D prevMousePos;
\r
358 Point2D origControlMousePos;
\r
359 Point2D origDiagramMousePos;
\r
360 IMouseCursorHandle cursor;
\r
362 public ZoomMode(int mouseId, Point2D controlMousePos, Point2D mouseDiagramPos, int releaseButton) {
\r
364 this.mouseId = mouseId;
\r
365 this.prevMousePos = (Point2D) controlMousePos.clone();
\r
366 this.origControlMousePos = (Point2D) controlMousePos.clone();
\r
367 this.origDiagramMousePos = (Point2D) mouseDiagramPos.clone();
\r
368 this.releaseButton = releaseButton;
\r
372 public void addedToContext(ICanvasContext ctx) {
\r
373 super.addedToContext(ctx);
\r
374 IMouseCursorContext mctx = getContext().getMouseCursorContext();
\r
376 cursor = mctx.setCursor(mouseId, ZOOM_CURSOR);
\r
379 @EventHandler(priority = ZOOM_PRIORITY)
\r
380 public boolean handleEvent(Event e) {
\r
381 if (e instanceof MouseButtonReleasedEvent) {
\r
382 MouseButtonReleasedEvent mpe = (MouseButtonReleasedEvent) e;
\r
383 if (mpe.button == releaseButton && mpe.mouseId == mouseId)
\r
390 if (e instanceof KeyReleasedEvent) {
\r
391 KeyReleasedEvent ke = (KeyReleasedEvent) e;
\r
392 if (ke.keyCode == java.awt.event.KeyEvent.VK_SHIFT)
\r
399 if (e instanceof MouseMovedEvent) {
\r
400 if (e.getContext() instanceof MouseUtil) return true;
\r
401 MouseMovedEvent mme = (MouseMovedEvent) e;
\r
402 if (mme.mouseId == mouseId) {
\r
403 Point2D oldPos = prevMousePos;
\r
404 Point2D newPos = mme.controlPosition;
\r
406 double dy = newPos.getY() - oldPos.getY();
\r
407 // double dx = newPos.getX() - oldPos.getX();
\r
408 this.prevMousePos.setLocation(newPos);
\r
410 double zoomSpeed = getMouseZoomSpeed();
\r
411 double base = 1.00 + (zoomSpeed / 10000);
\r
412 double scaleFactor = Math.pow(base, -dy);
\r
414 scaleFactor = pzr.limitScaleFactor(scaleFactor);
\r
415 util.zoomAroundDiagramPoint(scaleFactor, origDiagramMousePos);
\r
424 public void removedFromContext(ICanvasContext ctx) {
\r
425 if (cursor!=null) {
\r
430 super.removedFromContext(ctx);
\r