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