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.participant;
\r
14 import java.awt.geom.Point2D;
\r
15 import java.util.ArrayList;
\r
16 import java.util.Collection;
\r
17 import java.util.Collections;
\r
18 import java.util.Comparator;
\r
19 import java.util.HashMap;
\r
20 import java.util.List;
\r
21 import java.util.Map;
\r
23 import org.simantics.g2d.canvas.IMouseCaptureContext;
\r
24 import org.simantics.g2d.canvas.IMouseCaptureHandle;
\r
25 import org.simantics.g2d.canvas.IMouseCaptureHandleListener;
\r
26 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
\r
27 import org.simantics.g2d.diagram.handler.PickContext;
\r
28 import org.simantics.g2d.diagram.handler.PickRequest;
\r
29 import org.simantics.g2d.diagram.handler.PickRequest.PickSorter;
\r
30 import org.simantics.g2d.element.IElement;
\r
31 import org.simantics.g2d.element.handler.HandleMouseEvent;
\r
32 import org.simantics.g2d.participant.TransformUtil;
\r
33 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
\r
34 import org.simantics.scenegraph.g2d.events.MouseEvent;
\r
35 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent;
\r
36 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;
\r
39 * This participant sends mouse events to elements that have a {@link HandleMouseEvent}
\r
42 * @see HandleMouseEvent
\r
43 * @author Toni Kalajainen
\r
45 public class ElementInteractor extends AbstractDiagramParticipant {
\r
47 @Dependency PickContext pick;
\r
48 @Dependency TransformUtil util;
\r
50 private PickSorter pickSorter;
\r
52 public static final int INTERACTOR_PRIORITY = Integer.MAX_VALUE-1;
\r
54 Map<Integer, ElementMouseCaptureHandle> mouseCaptureMap =
\r
55 new HashMap<Integer, ElementMouseCaptureHandle>();
\r
56 Map<Integer, IElement> mouseFocus = new HashMap<Integer, IElement>();
\r
58 public ElementInteractor() {
\r
61 public ElementInteractor(PickSorter pickSorter) {
\r
62 this.pickSorter = pickSorter;
\r
65 private class ElementMouseCaptureHandle implements IMouseCaptureHandle {
\r
66 IMouseCaptureHandle origHandle;
\r
69 public void addMouseCaptureHandleListener(IMouseCaptureHandleListener listener) {
\r
70 origHandle.addMouseCaptureHandleListener(listener);
\r
73 public int mouseId() {
\r
74 return origHandle.mouseId();
\r
77 public void release() {
\r
78 mouseCaptureMap.remove(origHandle.mouseId());
\r
79 origHandle.release();
\r
82 public void removeMouseCaptureHandleListener(IMouseCaptureHandleListener listener) {
\r
83 origHandle.removeMouseCaptureHandleListener(listener);
\r
88 * Capture mouse events to an element.
\r
91 * @return capture handle or null if capture is not available in the context
\r
93 public IMouseCaptureHandle captureMouse(IElement element, int mouseId)
\r
95 // Release old capture
\r
96 ElementMouseCaptureHandle prevHnd = mouseCaptureMap.get(mouseId);
\r
97 if (prevHnd!=null) {
\r
99 mouseCaptureMap.remove(mouseId);
\r
102 // Check that capture is available
\r
103 IMouseCaptureContext mcc = getContext().getMouseCaptureContext();
\r
104 if (mcc==null) return null;
\r
106 // make new capture
\r
107 ElementMouseCaptureHandle hnd = new ElementMouseCaptureHandle();
\r
108 hnd.origHandle = mcc.captureMouse(mouseId);
\r
109 hnd.element = element;
\r
110 mouseCaptureMap.put(mouseId, hnd);
\r
115 * Get all grabs of an element
\r
119 public Collection<IMouseCaptureHandle> getGrabsOfElement(IElement e)
\r
121 List<IMouseCaptureHandle> result = new ArrayList<IMouseCaptureHandle>();
\r
122 for (ElementMouseCaptureHandle eh : mouseCaptureMap.values())
\r
123 if (eh.element == e)
\r
128 public IMouseCaptureHandle getGrabOfElement(IElement e, int mouseId)
\r
130 for (ElementMouseCaptureHandle eh : mouseCaptureMap.values())
\r
131 if (eh.element == e && eh.mouseId() == mouseId)
\r
136 @EventHandler(priority = INTERACTOR_PRIORITY)
\r
137 public boolean handleMouseEvent(MouseEvent me) {
\r
138 assertDependencies();
\r
140 // Determine element for capture
\r
141 IElement currentFocus = null;
\r
142 ElementMouseCaptureHandle hnd = mouseCaptureMap.get(me.mouseId);
\r
143 // Mouse is captured
\r
145 currentFocus = hnd.element;
\r
146 //System.out.println("capture: " + hnd);
\r
148 // Pick element under the mouse
\r
149 Point2D controlPos = me.controlPosition;
\r
150 Point2D diagramPos = util.controlToCanvas(controlPos, null);
\r
151 PickRequest req = new PickRequest(diagramPos);
\r
152 req.pickSorter = pickSorter;
\r
153 //req.pickSorter = PickRequest.PickSorter.CONNECTIONS_LAST;
\r
154 ArrayList<IElement> result = new ArrayList<IElement>();
\r
155 pick.pick(diagram, req, result);
\r
156 if (result.size()>0) {
\r
157 _sortByOrder(result);
\r
158 currentFocus = result.get(result.size()-1);
\r
159 //System.out.println("Focus " + currentFocus + " " + result.size());
\r
164 // Send enter & exit events to elements
\r
165 IElement prevFocus = mouseFocus.get(me.mouseId);
\r
166 // Focus has changed
\r
167 if (currentFocus!=prevFocus) {
\r
168 if (prevFocus!=null) {
\r
169 MouseExitEvent exit = new MouseExitEvent(getContext(), me.time, me.mouseId, me.buttons, me.stateMask, me.controlPosition, me.screenPosition);
\r
170 sendElementMouseEvent(prevFocus, exit);
\r
172 if (currentFocus!=null) {
\r
173 MouseEnterEvent enter = new MouseEnterEvent(getContext(), me.time, me.mouseId, me.buttons, me.stateMask, me.controlPosition, me.screenPosition);
\r
174 sendElementMouseEvent(currentFocus, enter);
\r
177 mouseFocus.put(me.mouseId, currentFocus);
\r
179 // Send event to all handlers
\r
180 if (currentFocus==null) return false;
\r
181 //return sendElementMouseEvent(currentFocus, me);
\r
182 sendElementMouseEvent(currentFocus, me);
\r
186 private boolean sendElementMouseEvent(IElement e, MouseEvent me)
\r
188 //System.out.println("sendElementMouseEvent(" + e + ", " + me + ")");
\r
189 // FIXME: eating events here will cause DND to not work. Workaround is to not eat the events. Need proper fix.
\r
190 for (HandleMouseEvent eh : e.getElementClass().getItemsByClass(HandleMouseEvent.class))
\r
192 if (eh.handleMouseEvent(e, getContext(), me)) return false;
\r
197 // copy-paste from ZOrderhandler (list is reverse, so element on top is first)
\r
198 void _sortByOrder(List<IElement> list)
\r
200 List<IElement> elements = diagram.getElements();
\r
201 final Map<IElement, Integer> position = new HashMap<IElement, Integer>();
\r
202 for (IElement e : list)
\r
203 position.put(e, elements.indexOf(e));
\r
204 Comparator<IElement> c = new Comparator<IElement>() {
\r
206 public int compare(IElement o1, IElement o2) {
\r
207 int pos1 = position.get(o1);
\r
208 int pos2 = position.get(o2);
\r
212 Collections.sort(list, c);
\r