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
12 package org.simantics.g2d.diagram.impl;
\r
14 import java.awt.Color;
\r
15 import java.awt.geom.AffineTransform;
\r
16 import java.awt.geom.Point2D;
\r
17 import java.awt.geom.Rectangle2D;
\r
18 import java.util.Comparator;
\r
19 import java.util.List;
\r
20 import java.util.Map;
\r
21 import java.util.concurrent.atomic.AtomicBoolean;
\r
23 import org.simantics.g2d.canvas.Hints;
\r
24 import org.simantics.g2d.canvas.ICanvasContext;
\r
25 import org.simantics.g2d.canvas.ICanvasParticipant;
\r
26 import org.simantics.g2d.canvas.IContentContext;
\r
27 import org.simantics.g2d.canvas.IMouseCaptureContext;
\r
28 import org.simantics.g2d.canvas.IMouseCursorContext;
\r
29 import org.simantics.g2d.canvas.impl.MouseCaptureContext;
\r
30 import org.simantics.g2d.canvas.impl.MouseCursorContext;
\r
31 import org.simantics.g2d.canvas.impl.PaintableContextImpl;
\r
32 import org.simantics.g2d.chassis.ITooltipProvider;
\r
33 import org.simantics.g2d.diagram.DiagramClass;
\r
34 import org.simantics.g2d.diagram.DiagramHints;
\r
35 import org.simantics.g2d.diagram.IDiagram;
\r
36 import org.simantics.g2d.diagram.participant.DiagramParticipant;
\r
37 import org.simantics.g2d.diagram.participant.ElementInteractor;
\r
38 import org.simantics.g2d.diagram.participant.ElementPainter;
\r
39 import org.simantics.g2d.diagram.participant.Selection;
\r
40 import org.simantics.g2d.diagram.participant.TerminalPainter;
\r
41 import org.simantics.g2d.diagram.participant.ZOrderHandler;
\r
42 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;
\r
43 import org.simantics.g2d.element.IElement;
\r
44 import org.simantics.g2d.multileveldiagram.TransitionFunction;
\r
45 import org.simantics.g2d.multileveldiagram.ZoomTransitionParticipant;
\r
46 import org.simantics.g2d.participant.BackgroundPainter;
\r
47 import org.simantics.g2d.participant.CanvasGrab;
\r
48 import org.simantics.g2d.participant.GridPainter;
\r
49 import org.simantics.g2d.participant.HandPainter;
\r
50 import org.simantics.g2d.participant.KeyToCommand;
\r
51 import org.simantics.g2d.participant.KeyUtil;
\r
52 import org.simantics.g2d.participant.MouseUtil;
\r
53 import org.simantics.g2d.participant.PointerPainter;
\r
54 import org.simantics.g2d.participant.RulerPainter;
\r
55 import org.simantics.g2d.participant.SubCanvas;
\r
56 import org.simantics.g2d.participant.SymbolUtil;
\r
57 import org.simantics.g2d.participant.TimeParticipant;
\r
58 import org.simantics.g2d.participant.TransformUtil;
\r
59 import org.simantics.g2d.scenegraph.SceneGraphConstants;
\r
60 import org.simantics.scenegraph.g2d.G2DParentNode;
\r
61 import org.simantics.scenegraph.g2d.G2DSceneGraph;
\r
62 import org.simantics.scenegraph.g2d.events.Event;
\r
63 import org.simantics.scenegraph.g2d.events.EventHandlerStack;
\r
64 import org.simantics.scenegraph.g2d.events.EventQueue;
\r
65 import org.simantics.scenegraph.g2d.events.IEventHandlerStack;
\r
66 import org.simantics.scenegraph.g2d.events.IEventQueue;
\r
67 import org.simantics.scenegraph.g2d.events.MouseEvent;
\r
68 import org.simantics.scenegraph.g2d.events.MouseEventCoalescer;
\r
69 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
\r
70 import org.simantics.scenegraph.g2d.events.IEventQueue.IEventQueueListener;
\r
71 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent;
\r
72 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;
\r
73 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;
\r
74 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent;
\r
75 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent;
\r
76 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;
\r
77 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent;
\r
78 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;
\r
79 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;
\r
80 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent;
\r
81 import org.simantics.scenegraph.g2d.events.command.CommandKeyBinding;
\r
82 import org.simantics.utils.datastructures.context.Context;
\r
83 import org.simantics.utils.datastructures.context.IContext;
\r
84 import org.simantics.utils.datastructures.context.IContextListener;
\r
85 import org.simantics.utils.datastructures.hints.HintContext;
\r
86 import org.simantics.utils.datastructures.hints.HintStack;
\r
87 import org.simantics.utils.datastructures.hints.IHintContext;
\r
88 import org.simantics.utils.datastructures.hints.IHintListener;
\r
89 import org.simantics.utils.datastructures.hints.IHintStack;
\r
90 import org.simantics.utils.threads.IThreadWorkQueue;
\r
91 import org.simantics.utils.threads.ThreadUtils;
\r
94 * Creates subcanvas on top of parent canvas. Size and position of the subcanvas
\r
97 * Beware: every CanvasParticipant that handles mouseEvents must be replaced
\r
98 * since mouse coordinates must be translated. Currently Implemented
\r
99 * participants: - MouseUtil - ElementInteractor
\r
101 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
\r
103 * TODO: CanvasContext implementation needs to implement scene graph methods too
\r
105 public class ElementDiagram implements IDiagram {
\r
106 private final ICanvasContext ctx;
\r
108 private final ICanvasContext parentCtx;
\r
110 private IDiagram diagram;
\r
112 private final SubCanvas subCanvas;
\r
114 private Rectangle2D canvasRect = new Rectangle2D.Double(0, 0, 200, 200);
\r
116 private int canvasPosX = 100;
\r
118 private int canvasPosY = 100;
\r
120 public ElementDiagram(ICanvasContext parentCtx) {
\r
121 this.parentCtx = parentCtx;
\r
122 ctx = createCanvas(parentCtx.getThreadAccess(),parentCtx.getSceneGraph());
\r
123 ICanvasParticipant mouseUtil = ctx.getSingleItem(MouseUtil.class);
\r
124 if (mouseUtil != null) {
\r
125 ctx.remove(mouseUtil);
\r
126 ctx.add(new ElementDiagramMouseUtil());
\r
127 // ctx.add(new MouseUtil());
\r
129 ICanvasParticipant elementInteractor = ctx.getSingleItem(ElementInteractor.class);
\r
130 if (elementInteractor != null) {
\r
131 ctx.remove(elementInteractor);
\r
132 ctx.add(new ElementDiagramElementInteractor());
\r
134 diagram = createDiagram();
\r
135 ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);
\r
136 subCanvas = new SubCanvas(ctx, 10000, Integer.MAX_VALUE - 100, 10000);
\r
137 parentCtx.add(subCanvas);
\r
140 public void setSize(int x, int y, int width, int height) {
\r
143 canvasRect = new Rectangle2D.Double(0, 0, width, height);
\r
144 getCanvas().getCanvasNode().setTransform(new AffineTransform(1,0,0,1,x,y));
\r
148 public Rectangle2D getSize() {
\r
153 * Override this for custom functionality
\r
157 public IDiagram createDiagram() {
\r
158 IDiagram d = Diagram.spawnNew(DiagramClass.DEFAULT);
\r
163 * Override this for custom functionality
\r
168 public ICanvasContext createCanvas(IThreadWorkQueue thread, G2DSceneGraph sg) {
\r
169 return createDefaultCanvas(thread,sg);
\r
172 public void setDiagram(IDiagram diagram) {
\r
173 this.diagram = diagram;
\r
174 ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);
\r
177 public ICanvasContext getCanvas() {
\r
181 public ICanvasContext getParentCanvas() {
\r
185 public SubCanvas getSubCanvas() {
\r
189 public IDiagram getDiagram() {
\r
194 public void addElement(IElement element) {
\r
195 diagram.addElement(element);
\r
199 public void removeElement(IElement element) {
\r
200 diagram.removeElement(element);
\r
204 public void addCompositionListener(CompositionListener listener) {
\r
205 diagram.addCompositionListener(listener);
\r
209 public void addCompositionVetoListener(CompositionVetoListener listener) {
\r
210 diagram.addCompositionVetoListener(listener);
\r
214 public void addHintListener(IHintListener listener) {
\r
215 diagram.addHintListener(listener);
\r
219 public void addHintListener(IThreadWorkQueue threadAccess, IHintListener listener) {
\r
220 diagram.addHintListener(threadAccess, listener);
\r
224 public void addKeyHintListener(IThreadWorkQueue threadAccess, Key key, IHintListener listener) {
\r
225 diagram.addKeyHintListener(threadAccess, key, listener);
\r
229 public void addKeyHintListener(Key key, IHintListener listener) {
\r
230 diagram.addKeyHintListener(key, listener);
\r
234 public boolean bringToTop(IElement e) {
\r
235 return diagram.bringToTop(e);
\r
239 public boolean bringUp(IElement e) {
\r
240 return diagram.bringUp(e);
\r
244 public void destroy() {
\r
249 public void dispose() {
\r
254 public DiagramClass getDiagramClass() {
\r
255 return diagram.getDiagramClass();
\r
259 public boolean containsElement(IElement element) {
\r
260 return diagram.containsElement(element);
\r
264 public List<IElement> getElements() {
\r
265 return diagram.getElements();
\r
269 public void sort(Comparator<IElement> comparator) {
\r
270 diagram.sort(comparator);
\r
274 public List<IElement> getSnapshot() {
\r
275 return diagram.getSnapshot();
\r
279 public void clearWithoutNotification() {
\r
280 diagram.clearWithoutNotification();
\r
284 public boolean containsHint(Key key) {
\r
285 return diagram.containsHint(key);
\r
289 public <E> E getHint(Key key) {
\r
290 return diagram.getHint(key);
\r
294 public Map<Key, Object> getHints() {
\r
295 return diagram.getHints();
\r
299 public Map<Key, Object> getHintsUnsafe() {
\r
300 return diagram.getHintsUnsafe();
\r
304 public <E extends Key> Map<E, Object> getHintsOfClass(Class<E> clazz) {
\r
305 return diagram.getHintsOfClass(clazz);
\r
309 public boolean moveTo(IElement e, int position) {
\r
310 return diagram.moveTo(e, position);
\r
314 public void removeCompositionListener(CompositionListener listener) {
\r
315 diagram.removeCompositionListener(listener);
\r
319 public void removeCompositionVetoListener(CompositionVetoListener listener) {
\r
320 diagram.removeCompositionVetoListener(listener);
\r
324 public <E> E removeHint(Key key) {
\r
325 return diagram.removeHint(key);
\r
329 public void removeHintListener(IHintListener listener) {
\r
330 diagram.removeHintListener(listener);
\r
334 public void removeHintListener(IThreadWorkQueue threadAccess, IHintListener listener) {
\r
335 diagram.removeHintListener(threadAccess, listener);
\r
339 public void removeKeyHintListener(IThreadWorkQueue threadAccess, Key key, IHintListener listener) {
\r
340 diagram.removeKeyHintListener(threadAccess, key, listener);
\r
344 public void removeKeyHintListener(Key key, IHintListener listener) {
\r
345 diagram.removeKeyHintListener(key, listener);
\r
349 public boolean sendDown(IElement e) {
\r
350 return diagram.sendDown(e);
\r
354 public boolean sendToBottom(IElement e) {
\r
355 return diagram.sendToBottom(e);
\r
359 public void setHint(Key key, Object value) {
\r
360 diagram.setHint(key, value);
\r
364 public void setHints(Map<Key, Object> hints) {
\r
365 diagram.setHints(hints);
\r
368 public ICanvasContext createDefaultCanvas(IThreadWorkQueue thread, G2DSceneGraph sg) {
\r
369 // Create canvas context and a layer of interactors
\r
370 ICanvasContext canvasContext = new ElementDiagramCanvasContext(thread,sg);
\r
371 IHintContext h = canvasContext.getDefaultHintContext();
\r
373 //canvasContext.add(new PanZoomRotateHandler()); // Must be before
\r
376 // Support & Util Participants
\r
377 canvasContext.add(new TransformUtil());
\r
378 canvasContext.add(new MouseUtil());
\r
379 canvasContext.add(new KeyUtil());
\r
380 canvasContext.add(new CanvasGrab());
\r
381 canvasContext.add(new SymbolUtil());
\r
382 canvasContext.add(new TimeParticipant());
\r
384 // Debug participant(s)
\r
385 // canvasContext.add( new PointerPainter() );
\r
386 canvasContext.add(new HandPainter());
\r
387 h.setHint(PointerPainter.KEY_PAINT_POINTER, true);
\r
389 // Pan & Zoom & Rotate
\r
390 // canvasContext.add( new MousePanZoomInteractor() );
\r
391 // canvasContext.add( new MultitouchPanZoomRotateInteractor() );
\r
392 // canvasContext.add( new OrientationRestorer() );
\r
394 // Grid & Ruler & Background
\r
395 canvasContext.add(new GridPainter());
\r
396 canvasContext.add(new RulerPainter());
\r
397 canvasContext.add(new BackgroundPainter());
\r
398 h.setHint(Hints.KEY_GRID_COLOR, new Color(0.9f, 0.9f, 0.9f));
\r
399 h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.LIGHT_GRAY);
\r
402 canvasContext.add(new KeyToCommand(CommandKeyBinding.DEFAULT_BINDINGS));
\r
404 // //// Diagram Participants //////
\r
405 canvasContext.add(new PointerInteractor());
\r
406 canvasContext.add(new ElementInteractor());
\r
407 canvasContext.add(new Selection());
\r
408 canvasContext.add(new DiagramParticipant());
\r
409 canvasContext.add(new ElementPainter());
\r
410 canvasContext.add(new TerminalPainter(true, true, false, true));
\r
411 //canvasContext.add(new ElementHeartbeater());
\r
412 canvasContext.add(new ZOrderHandler());
\r
413 canvasContext.add(new ZoomTransitionParticipant(TransitionFunction.SIGMOID));
\r
414 h.setHint(Hints.KEY_TOOL, Hints.PANTOOL);
\r
416 return canvasContext;
\r
419 public class ElementDiagramCanvasContext extends Context<ICanvasParticipant> implements ICanvasContext {
\r
421 protected HintStack hintStack = new HintStack();
\r
423 protected HintContext bottomHintContext = new HintContext();
\r
425 protected IEventHandlerStack eventHandlerStack = null;
\r
427 protected boolean eventHandlingOrdered = false;
\r
429 protected EventQueue eventQueue = null;
\r
431 protected IContentContext paintableCtx = new PaintableContextImpl();
\r
433 protected final IThreadWorkQueue thread;
\r
435 protected IMouseCaptureContext mouseCaptureCtx = new MouseCaptureContext();
\r
437 protected IMouseCursorContext mouseCursorCtx = new MouseCursorContext();
\r
439 protected G2DSceneGraph sg;
\r
440 protected G2DParentNode canvasNode = null;
\r
442 protected ITooltipProvider tooltip;
\r
446 * @param thread context thread, or null if sync policy not used
\r
448 public ElementDiagramCanvasContext(IThreadWorkQueue thread, G2DSceneGraph sg) {
\r
449 super(ICanvasParticipant.class);
\r
450 if (thread == null)
\r
451 throw new IllegalArgumentException("null");
\r
452 this.thread = thread;
\r
453 eventHandlerStack = new EventHandlerStack(thread);
\r
454 eventQueue = new EventQueue(eventHandlerStack);
\r
455 hintStack.addHintContext(bottomHintContext, Integer.MIN_VALUE);
\r
460 canvasNode = sg.addNode("elementd" + SceneGraphConstants.NAVIGATION_NODE_NAME , G2DParentNode.class); // Add dummy parent node
\r
461 canvasNode.setZIndex(1000);
\r
463 this.addContextListener(thread, new IContextListener<ICanvasParticipant>() {
\r
465 public void itemAdded(IContext<ICanvasParticipant> sender, ICanvasParticipant item) {
\r
466 item.addedToContext(ElementDiagramCanvasContext.this);
\r
470 public void itemRemoved(IContext<ICanvasParticipant> sender, ICanvasParticipant item) {
\r
471 item.removedFromContext(ElementDiagramCanvasContext.this);
\r
475 eventQueue.addEventCoalesceler(MouseEventCoalescer.INSTANCE);
\r
476 // Order event handling if events are added to the queue
\r
477 eventQueue.addQueueListener(new IEventQueueListener() {
\r
479 public void onEventAdded(IEventQueue queue, Event e, int index) {
\r
480 asyncHandleEvents();
\r
484 public void onQueueEmpty(IEventQueue queue) {
\r
489 public IHintStack getHintStack() {
\r
490 assertNotDisposed();
\r
494 private final Runnable eventHandling = new Runnable() {
\r
496 public void run() {
\r
497 eventHandlingOrdered = false;
\r
498 eventQueue.handleEvents();
\r
502 synchronized void asyncHandleEvents() {
\r
503 if (eventHandlingOrdered)
\r
505 eventHandlingOrdered = true;
\r
506 ThreadUtils.asyncExec(thread, eventHandling);
\r
509 synchronized void syncHandleEvents() {
\r
510 if (eventHandlingOrdered)
\r
512 eventHandlingOrdered = true;
\r
513 ThreadUtils.syncExec(thread, eventHandling);
\r
517 public IEventHandlerStack getEventHandlerStack() {
\r
518 assertNotDisposed();
\r
519 return eventHandlerStack;
\r
523 public IThreadWorkQueue getThreadAccess() {
\r
524 // assertNotDisposed();
\r
529 protected void doDispose() {
\r
530 ThreadUtils.syncExec(getThreadAccess(), new Runnable() {
\r
532 public void run() {
\r
535 // HN: added to decrease memory leaks
\r
537 // Makes sure that scene graph nodes free their resources!
\r
546 public IHintContext getDefaultHintContext() {
\r
547 return bottomHintContext;
\r
551 public IMouseCursorContext getMouseCursorContext() {
\r
552 return mouseCursorCtx;
\r
556 public void setMouseCursorContext(IMouseCursorContext ctx) {
\r
557 this.mouseCursorCtx = ctx;
\r
561 public IMouseCaptureContext getMouseCaptureContext() {
\r
562 return mouseCaptureCtx;
\r
566 public void setMouseCaptureContext(IMouseCaptureContext mctx) {
\r
567 this.mouseCaptureCtx = mctx;
\r
571 public IEventQueue getEventQueue() {
\r
576 public IContentContext getContentContext() {
\r
577 return paintableCtx;
\r
581 public void setContentContext(IContentContext ctx) {
\r
582 this.paintableCtx = ctx;
\r
586 public G2DSceneGraph getSceneGraph() {
\r
591 public G2DParentNode getCanvasNode() {
\r
596 public void setCanvasNode(G2DParentNode node) {
\r
597 throw new RuntimeException("Cannot set canvasNode");
\r
601 protected final AtomicBoolean locked = new AtomicBoolean(false);
\r
604 public boolean isLocked() {
\r
605 return this.locked.get();
\r
609 public void setLocked(boolean locked) {
\r
610 boolean previous = this.locked.getAndSet(locked);
\r
611 if (!locked && previous != locked) {
\r
612 // The context was unlocked!
\r
613 getContentContext().setDirty();
\r
618 public ITooltipProvider getTooltipProvider() {
\r
623 public void setTooltipProvider(ITooltipProvider tooltipProvider) {
\r
624 this.tooltip = tooltipProvider;
\r
629 public class ElementDiagramMouseUtil extends MouseUtil {
\r
632 @EventHandler(priority = Integer.MAX_VALUE)
\r
633 public boolean handleMouseEvent(MouseEvent e) {
\r
634 MouseEvent ne = createMouseEvent(e);
\r
636 return handleMouseEvent2(ne);
\r
641 * Copy-pasted MouseUtil.handleMouseEvent with one modification;
\r
642 * Generating MouseClickEvents has been removed, because it created
\r
643 * duplicated events (with incorrect coordinates).
\r
648 public boolean handleMouseEvent2(MouseEvent e) {
\r
649 assertDependencies();
\r
650 if (e instanceof MouseEnterEvent) {
\r
651 Point2D canvasPosition = util.controlToCanvas(e.controlPosition, null);
\r
653 MouseInfo mi = new MouseInfo(e.mouseId, e.controlPosition, canvasPosition, e.buttons);
\r
654 miceInfo.put(e.mouseId, mi);
\r
655 } else if (e instanceof MouseExitEvent) {
\r
656 miceInfo.remove(e.mouseId);
\r
657 } else if (e instanceof MouseMovedEvent) {
\r
658 Point2D canvasPosition = util.controlToCanvas(e.controlPosition, null);
\r
659 double deltaDistance = 0;
\r
660 MouseInfo mi = miceInfo.get(e.mouseId);
\r
662 mi = new MouseInfo(e.mouseId, e.controlPosition, canvasPosition, 0/*e.buttons*/);
\r
663 miceInfo.put(e.mouseId, mi);
\r
665 deltaDistance = e.controlPosition.distance(mi.controlPosition);
\r
666 mi.controlPosition = e.controlPosition;
\r
667 mi.canvasPosition = canvasPosition;
\r
670 if (deltaDistance > 0)
\r
671 mi.addDistanceForButtons(deltaDistance);
\r
673 // Send mouse drag events.
\r
674 for (ButtonInfo bi : mi.buttonPressInfo.values()) {
\r
677 if (bi.deltaMotion <= profile.movementTolerance)
\r
682 MouseDragBegin db = new MouseDragBegin(this, e.time, e.mouseId, e.buttons, e.stateMask, bi.button,
\r
683 bi.canvasPosition, bi.controlPosition, e.controlPosition, e.screenPosition);
\r
684 getContext().getEventQueue().queueFirst(db);
\r
687 } else if (e instanceof MouseButtonPressedEvent) {
\r
688 Point2D canvasPosition = util.controlToCanvas(e.controlPosition, null);
\r
689 MouseButtonPressedEvent me = (MouseButtonPressedEvent) e;
\r
690 MouseInfo mi = miceInfo.get(e.mouseId);
\r
692 mi = new MouseInfo(e.mouseId, e.controlPosition, canvasPosition, e.buttons);
\r
693 miceInfo.put(e.mouseId, mi);
\r
695 mi.controlPosition = e.controlPosition;
\r
696 mi.canvasPosition = canvasPosition;
\r
698 mi.setButtonPressed(me.button, e.stateMask, e.controlPosition, canvasPosition, e.time);
\r
699 } else if (e instanceof MouseButtonReleasedEvent) {
\r
700 MouseButtonReleasedEvent me = (MouseButtonReleasedEvent) e;
\r
701 Point2D canvasPosition = util.controlToCanvas(me.controlPosition, null);
\r
702 MouseInfo mi = miceInfo.get(me.mouseId);
\r
704 mi = new MouseInfo(e.mouseId, me.controlPosition, canvasPosition, 0/*me.buttons*/);
\r
705 miceInfo.put(me.mouseId, mi);
\r
707 mi.controlPosition = me.controlPosition;
\r
708 mi.canvasPosition = canvasPosition;
\r
710 ButtonInfo bi = mi.releaseButton(me.button, me.time);
\r
714 if (me.holdTime > profile.clickHoldTimeTolerance)
\r
716 if (bi.deltaMotion > profile.movementTolerance)
\r
720 long timeSinceLastClick = me.time - bi.lastClickEventTime;
\r
721 bi.lastClickEventTime = me.time;
\r
723 // reset click counter
\r
724 if (timeSinceLastClick > profile.consecutiveToleranceTime)
\r
734 public class ElementDiagramElementInteractor extends ElementInteractor {
\r
736 @EventHandler(priority = INTERACTOR_PRIORITY)
\r
737 public boolean handleMouseEvent(MouseEvent me) {
\r
738 MouseEvent ne = createMouseEvent(me);
\r
740 return super.handleMouseEvent(ne);
\r
745 public MouseEvent createMouseEvent(MouseEvent e) {
\r
746 MouseEvent newEvent = null;
\r
747 double x = e.controlPosition.getX();
\r
748 double y = e.controlPosition.getY();
\r
749 Point2D newPos = new Point2D.Double(x - canvasPosX, y - canvasPosY);
\r
751 if (!canvasRect.contains(newPos))
\r
752 return new MouseExitEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos, e.screenPosition);
\r
753 if (e instanceof MouseButtonPressedEvent) {
\r
754 newEvent = new MouseButtonPressedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask,
\r
755 ((MouseButtonEvent) e).button, newPos, e.screenPosition);
\r
756 } else if (e instanceof MouseButtonReleasedEvent) {
\r
757 newEvent = new MouseButtonReleasedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask,
\r
758 ((MouseButtonEvent) e).button, ((MouseButtonReleasedEvent) e).holdTime, newPos, e.screenPosition);
\r
759 } else if (e instanceof MouseDoubleClickedEvent) {
\r
760 newEvent = new MouseDoubleClickedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask,
\r
761 ((MouseButtonEvent) e).button, newPos, e.screenPosition);
\r
762 } else if (e instanceof MouseClickEvent) {
\r
763 newEvent = new MouseClickEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask,
\r
764 ((MouseButtonEvent) e).button, ((MouseClickEvent) e).clickCount, newPos, e.screenPosition);
\r
765 } else if (e instanceof MouseDragBegin) {
\r
766 newEvent = new MouseDragBegin(e.context, e.time, e.mouseId, e.buttons, e.stateMask,
\r
767 ((MouseButtonEvent) e).button, ((MouseDragBegin) e).startCanvasPos,
\r
768 ((MouseDragBegin) e).startControlPos, newPos, e.screenPosition);
\r
769 } else if (e instanceof MouseEnterEvent) {
\r
770 newEvent = new MouseEnterEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos,
\r
772 } else if (e instanceof MouseExitEvent) {
\r
773 newEvent = new MouseExitEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos,
\r
775 } else if (e instanceof MouseMovedEvent) {
\r
776 newEvent = new MouseMovedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos,
\r
778 } else if (e instanceof MouseWheelMovedEvent) {
\r
779 newEvent = new MouseWheelMovedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos,
\r
780 e.screenPosition, ((MouseWheelMovedEvent) e).scrollType, ((MouseWheelMovedEvent) e).scrollAmount,
\r
781 ((MouseWheelMovedEvent) e).wheelRotation);
\r
783 throw new Error("Unknow event " + e.getClass() + " " + e);
\r
785 // System.out.println(newPos + " " + newEvent + " "+ e);
\r