X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fdiagram%2Fparticipant%2FElementInteractor.java;fp=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fdiagram%2Fparticipant%2FElementInteractor.java;h=aae577dfb663ddf96fa810ddd813106c9929e17c;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementInteractor.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementInteractor.java new file mode 100644 index 000000000..aae577dfb --- /dev/null +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementInteractor.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * 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.diagram.participant; + +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.simantics.g2d.canvas.IMouseCaptureContext; +import org.simantics.g2d.canvas.IMouseCaptureHandle; +import org.simantics.g2d.canvas.IMouseCaptureHandleListener; +import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; +import org.simantics.g2d.diagram.handler.PickContext; +import org.simantics.g2d.diagram.handler.PickRequest; +import org.simantics.g2d.diagram.handler.PickRequest.PickSorter; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.HandleMouseEvent; +import org.simantics.g2d.participant.TransformUtil; +import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; +import org.simantics.scenegraph.g2d.events.MouseEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent; + +/** + * This participant sends mouse events to elements that have a {@link HandleMouseEvent} + * handler. + * + * @see HandleMouseEvent + * @author Toni Kalajainen + */ +public class ElementInteractor extends AbstractDiagramParticipant { + + @Dependency PickContext pick; + @Dependency TransformUtil util; + + private PickSorter pickSorter; + + public static final int INTERACTOR_PRIORITY = Integer.MAX_VALUE-1; + + Map mouseCaptureMap = + new HashMap(); + Map mouseFocus = new HashMap(); + + public ElementInteractor() { + } + + public ElementInteractor(PickSorter pickSorter) { + this.pickSorter = pickSorter; + } + + private class ElementMouseCaptureHandle implements IMouseCaptureHandle { + IMouseCaptureHandle origHandle; + IElement element; + @Override + public void addMouseCaptureHandleListener(IMouseCaptureHandleListener listener) { + origHandle.addMouseCaptureHandleListener(listener); + } + @Override + public int mouseId() { + return origHandle.mouseId(); + } + @Override + public void release() { + mouseCaptureMap.remove(origHandle.mouseId()); + origHandle.release(); + } + @Override + public void removeMouseCaptureHandleListener(IMouseCaptureHandleListener listener) { + origHandle.removeMouseCaptureHandleListener(listener); + } + } + + /** + * Capture mouse events to an element. + * @param element + * @param mouseId + * @return capture handle or null if capture is not available in the context + */ + public IMouseCaptureHandle captureMouse(IElement element, int mouseId) + { + // Release old capture + ElementMouseCaptureHandle prevHnd = mouseCaptureMap.get(mouseId); + if (prevHnd!=null) { + prevHnd.release(); + mouseCaptureMap.remove(mouseId); + } + + // Check that capture is available + IMouseCaptureContext mcc = getContext().getMouseCaptureContext(); + if (mcc==null) return null; + + // make new capture + ElementMouseCaptureHandle hnd = new ElementMouseCaptureHandle(); + hnd.origHandle = mcc.captureMouse(mouseId); + hnd.element = element; + mouseCaptureMap.put(mouseId, hnd); + return hnd; + } + + /** + * Get all grabs of an element + * @param e element + * @return + */ + public Collection getGrabsOfElement(IElement e) + { + List result = new ArrayList(); + for (ElementMouseCaptureHandle eh : mouseCaptureMap.values()) + if (eh.element == e) + result.add(eh); + return result; + } + + public IMouseCaptureHandle getGrabOfElement(IElement e, int mouseId) + { + for (ElementMouseCaptureHandle eh : mouseCaptureMap.values()) + if (eh.element == e && eh.mouseId() == mouseId) + return eh; + return null; + } + + @EventHandler(priority = INTERACTOR_PRIORITY) + public boolean handleMouseEvent(MouseEvent me) { + assertDependencies(); + + // Determine element for capture + IElement currentFocus = null; + ElementMouseCaptureHandle hnd = mouseCaptureMap.get(me.mouseId); + // Mouse is captured + if (hnd != null) { + currentFocus = hnd.element; + //System.out.println("capture: " + hnd); + } else { + // Pick element under the mouse + Point2D controlPos = me.controlPosition; + Point2D diagramPos = util.controlToCanvas(controlPos, null); + PickRequest req = new PickRequest(diagramPos); + req.pickSorter = pickSorter; + //req.pickSorter = PickRequest.PickSorter.CONNECTIONS_LAST; + ArrayList result = new ArrayList(); + pick.pick(diagram, req, result); + if (result.size()>0) { + _sortByOrder(result); + currentFocus = result.get(result.size()-1); + //System.out.println("Focus " + currentFocus + " " + result.size()); + } + + } + + // Send enter & exit events to elements + IElement prevFocus = mouseFocus.get(me.mouseId); + // Focus has changed + if (currentFocus!=prevFocus) { + if (prevFocus!=null) { + MouseExitEvent exit = new MouseExitEvent(getContext(), me.time, me.mouseId, me.buttons, me.stateMask, me.controlPosition, me.screenPosition); + sendElementMouseEvent(prevFocus, exit); + } + if (currentFocus!=null) { + MouseEnterEvent enter = new MouseEnterEvent(getContext(), me.time, me.mouseId, me.buttons, me.stateMask, me.controlPosition, me.screenPosition); + sendElementMouseEvent(currentFocus, enter); + } + } + mouseFocus.put(me.mouseId, currentFocus); + + // Send event to all handlers + if (currentFocus==null) return false; + //return sendElementMouseEvent(currentFocus, me); + sendElementMouseEvent(currentFocus, me); + return false; + } + + private boolean sendElementMouseEvent(IElement e, MouseEvent me) + { + //System.out.println("sendElementMouseEvent(" + e + ", " + me + ")"); + // FIXME: eating events here will cause DND to not work. Workaround is to not eat the events. Need proper fix. + for (HandleMouseEvent eh : e.getElementClass().getItemsByClass(HandleMouseEvent.class)) + { + if (eh.handleMouseEvent(e, getContext(), me)) return false; + } + return false; + } + + // copy-paste from ZOrderhandler (list is reverse, so element on top is first) + void _sortByOrder(List list) + { + List elements = diagram.getElements(); + final Map position = new HashMap(); + for (IElement e : list) + position.put(e, elements.indexOf(e)); + Comparator c = new Comparator() { + @Override + public int compare(IElement o1, IElement o2) { + int pos1 = position.get(o1); + int pos2 = position.get(o2); + return pos1-pos2; + } + }; + Collections.sort(list, c); + } + +}