-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.g2d.element.handler.impl;\r
-\r
-import java.awt.geom.Point2D;\r
-import java.lang.reflect.Method;\r
-import java.util.Map;\r
-\r
-import org.simantics.g2d.canvas.ICanvasContext;\r
-import org.simantics.g2d.diagram.participant.DiagramParticipant;\r
-import org.simantics.g2d.element.ElementUtils;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.g2d.element.handler.Clickable;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;\r
-import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
-import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
-import org.simantics.utils.threads.Executable;\r
-import org.simantics.utils.threads.IThreadWorkQueue;\r
-import org.simantics.utils.threads.SyncListenerList;\r
-import org.simantics.utils.threads.ThreadUtils;\r
-\r
-/**\r
- * Base implementation for button handlers\r
- * \r
- * \r
- * @author Toni Kalajainen\r
- */\r
-public abstract class AbstractClickable extends AbstractGrabbable implements Clickable {\r
- \r
- private static final long serialVersionUID = -8329973386869163106L;\r
- \r
- public static Key HOVER_KEY = new KeyOf(Boolean.class, "HOVER");\r
- public static Key PRESS_STATUS_KEY = new KeyOf(PressStatus.class, "PRESS_STATUS");\r
- \r
- public AbstractClickable(Double strayDistance) {\r
- super(1000.0);\r
- }\r
- \r
- public AbstractClickable() {\r
- super();\r
- } \r
-\r
- /**\r
- * Get element press status\r
- * @param e\r
- * @param ctx\r
- * @return\r
- */\r
- public PressStatus getPressStatus(IElement e, ICanvasContext ctx)\r
- {\r
- Map<Integer, GrabInfo> gis = getGrabs(e, ctx);\r
- if (gis==null || gis.size()==0) {\r
- Boolean hover = e.getHint(HOVER_KEY);\r
- if (hover != null && hover)\r
- return PressStatus.HOVER;\r
- return PressStatus.NORMAL;\r
- }\r
- \r
- // is held down \r
- boolean held = false;\r
- boolean pressing = false;\r
- \r
- for (GrabInfo gi : gis.values()) {\r
- held = true;\r
- pressing |= onPickCheck(e, ctx, gi.pointerId, gi.dragPosElement);\r
- if (pressing) break;\r
- } \r
- \r
- if (pressing) return PressStatus.PRESSED;\r
- if (held) return PressStatus.HELD;\r
- Boolean hover = e.getHint(HOVER_KEY);\r
- if (hover != null && hover)\r
- return PressStatus.HOVER;\r
-\r
- return PressStatus.NORMAL;\r
- }\r
- \r
- \r
- @Override\r
- public boolean handleMouseEvent(IElement e, ICanvasContext ctx,\r
- MouseEvent me) {\r
- //System.out.println("AbstractClickable.hME element:" + e + " me:" + me);\r
- boolean b = super.handleMouseEvent(e, ctx, me);\r
- Boolean hovering;\r
- // DND drag starts causes DragBegin + ButtonReleasedEvents, and hovering must be set false\r
- if (!(me instanceof MouseExitEvent || me instanceof MouseDragBegin || me instanceof MouseButtonReleasedEvent))\r
- hovering = Boolean.valueOf(onPickCheck(e, ctx, me.mouseId, ElementUtils.controlToElementCoordinate(e, ctx, me.controlPosition, null)));\r
- else\r
- hovering = false;\r
- if (!hovering.equals(e.getHint(HOVER_KEY))) {\r
- e.setHint(HOVER_KEY, hovering);\r
- }\r
- \r
- // hackety hack\r
- PressStatus newStatus = getPressStatus(e, ctx);\r
- if (!newStatus.equals(e.getHint(PRESS_STATUS_KEY)))\r
- e.setHint(PRESS_STATUS_KEY, newStatus) ;\r
- return b;\r
- }\r
- \r
- @Override\r
- protected void onDrag(GrabInfo gi, ICanvasContext ctx) {\r
- \r
- }\r
-\r
- @Override\r
- protected void onGrab(GrabInfo gi, ICanvasContext ctx) {\r
- }\r
-\r
- @Override\r
- protected void onGrabCancel(GrabInfo gi, ICanvasContext ctx) {\r
- }\r
-\r
- @Override\r
- protected void onRelease(GrabInfo gi, ICanvasContext ctx) {\r
- // pick is pick until last mouse releases\r
- if (getGrabCount(gi.e, ctx)>0) return;\r
- \r
- boolean pick = onPickCheck(gi.e, ctx, gi.pointerId, gi.dragPosElement);\r
- if (pick) {\r
- onClicked(gi, ctx);\r
- fireClicked(gi.e, ctx);\r
- }\r
- }\r
- \r
- protected boolean onGrabCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos)\r
- {\r
- Point2D elementPos = ElementUtils.controlToElementCoordinate(e, ctx, pickPos, null); \r
- return onPickCheck(e, ctx, pointerId, elementPos);\r
- }\r
- \r
- protected abstract void onClicked(GrabInfo gi, ICanvasContext ctx);\r
- \r
- /**\r
- * Pick check in element coordinates\r
- * @param e\r
- * @param ctx\r
- * @param pointerId\r
- * @param pickPos\r
- * @return\r
- */\r
- protected abstract boolean onPickCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos);\r
-\r
-\r
- private static final Key KEY_CLICK_LISTENERS = new KeyOf(SyncListenerList.class);\r
- \r
- @Override\r
- public void addListener(final IElement e, final ICanvasContext ctx, final IThreadWorkQueue thread, final ClickListener listener) {\r
- ThreadUtils.syncExec(ctx.getThreadAccess(), new Runnable() {\r
- @Override\r
- public void run() {\r
- DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
- SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);\r
- if (list==null) {\r
- list = new SyncListenerList<ClickListener>(ClickListener.class);\r
- dp.setElementHint(e, KEY_CLICK_LISTENERS, list);\r
- }\r
- list.add(thread, listener);\r
- }}); \r
- }\r
-\r
- @Override\r
- public void removeListener(final IElement e, final ICanvasContext ctx, final IThreadWorkQueue thread, final ClickListener listener) {\r
- ThreadUtils.syncExec(ctx.getThreadAccess(), new Runnable() {\r
- @Override\r
- public void run() {\r
- DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
- SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);\r
- if (list==null) return;\r
- list.remove(thread, listener);\r
- if (list.isEmpty())\r
- dp.removeElementHint(e, KEY_CLICK_LISTENERS);\r
- }}); \r
- } \r
- \r
- private final static Method onClick = SyncListenerList.getMethod(ClickListener.class, "onClick");\r
- public void fireClicked(IElement e, ICanvasContext ctx)\r
- {\r
- DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
- SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);\r
- if (list==null) return;\r
- Executable exes[] = list.getExecutables(onClick, e, ctx);\r
- ThreadUtils.multiSyncExec(exes);\r
- }\r
- \r
-}\r
+/*******************************************************************************
+ * 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.element.handler.impl;
+
+import java.awt.geom.Point2D;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.simantics.g2d.canvas.ICanvasContext;
+import org.simantics.g2d.diagram.participant.DiagramParticipant;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.element.handler.Clickable;
+import org.simantics.scenegraph.g2d.events.MouseEvent;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;
+import org.simantics.utils.datastructures.hints.IHintContext.Key;
+import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
+import org.simantics.utils.threads.Executable;
+import org.simantics.utils.threads.IThreadWorkQueue;
+import org.simantics.utils.threads.SyncListenerList;
+import org.simantics.utils.threads.ThreadUtils;
+
+/**
+ * Base implementation for button handlers
+ *
+ *
+ * @author Toni Kalajainen
+ */
+public abstract class AbstractClickable extends AbstractGrabbable implements Clickable {
+
+ private static final long serialVersionUID = -8329973386869163106L;
+
+ public static Key HOVER_KEY = new KeyOf(Boolean.class, "HOVER");
+ public static Key PRESS_STATUS_KEY = new KeyOf(PressStatus.class, "PRESS_STATUS");
+
+ public AbstractClickable(Double strayDistance) {
+ super(1000.0);
+ }
+
+ public AbstractClickable() {
+ super();
+ }
+
+ /**
+ * Get element press status
+ * @param e
+ * @param ctx
+ * @return
+ */
+ public PressStatus getPressStatus(IElement e, ICanvasContext ctx)
+ {
+ Map<Integer, GrabInfo> gis = getGrabs(e, ctx);
+ if (gis==null || gis.size()==0) {
+ Boolean hover = e.getHint(HOVER_KEY);
+ if (hover != null && hover)
+ return PressStatus.HOVER;
+ return PressStatus.NORMAL;
+ }
+
+ // is held down
+ boolean held = false;
+ boolean pressing = false;
+
+ for (GrabInfo gi : gis.values()) {
+ held = true;
+ pressing |= onPickCheck(e, ctx, gi.pointerId, gi.dragPosElement);
+ if (pressing) break;
+ }
+
+ if (pressing) return PressStatus.PRESSED;
+ if (held) return PressStatus.HELD;
+ Boolean hover = e.getHint(HOVER_KEY);
+ if (hover != null && hover)
+ return PressStatus.HOVER;
+
+ return PressStatus.NORMAL;
+ }
+
+
+ @Override
+ public boolean handleMouseEvent(IElement e, ICanvasContext ctx,
+ MouseEvent me) {
+ //System.out.println("AbstractClickable.hME element:" + e + " me:" + me);
+ boolean b = super.handleMouseEvent(e, ctx, me);
+ Boolean hovering;
+ // DND drag starts causes DragBegin + ButtonReleasedEvents, and hovering must be set false
+ if (!(me instanceof MouseExitEvent || me instanceof MouseDragBegin || me instanceof MouseButtonReleasedEvent))
+ hovering = Boolean.valueOf(onPickCheck(e, ctx, me.mouseId, ElementUtils.controlToElementCoordinate(e, ctx, me.controlPosition, null)));
+ else
+ hovering = false;
+ if (!hovering.equals(e.getHint(HOVER_KEY))) {
+ e.setHint(HOVER_KEY, hovering);
+ }
+
+ // hackety hack
+ PressStatus newStatus = getPressStatus(e, ctx);
+ if (!newStatus.equals(e.getHint(PRESS_STATUS_KEY)))
+ e.setHint(PRESS_STATUS_KEY, newStatus) ;
+ return b;
+ }
+
+ @Override
+ protected void onDrag(GrabInfo gi, ICanvasContext ctx) {
+
+ }
+
+ @Override
+ protected void onGrab(GrabInfo gi, ICanvasContext ctx) {
+ }
+
+ @Override
+ protected void onGrabCancel(GrabInfo gi, ICanvasContext ctx) {
+ }
+
+ @Override
+ protected void onRelease(GrabInfo gi, ICanvasContext ctx) {
+ // pick is pick until last mouse releases
+ if (getGrabCount(gi.e, ctx)>0) return;
+
+ boolean pick = onPickCheck(gi.e, ctx, gi.pointerId, gi.dragPosElement);
+ if (pick) {
+ onClicked(gi, ctx);
+ fireClicked(gi.e, ctx);
+ }
+ }
+
+ protected boolean onGrabCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos)
+ {
+ Point2D elementPos = ElementUtils.controlToElementCoordinate(e, ctx, pickPos, null);
+ return onPickCheck(e, ctx, pointerId, elementPos);
+ }
+
+ protected abstract void onClicked(GrabInfo gi, ICanvasContext ctx);
+
+ /**
+ * Pick check in element coordinates
+ * @param e
+ * @param ctx
+ * @param pointerId
+ * @param pickPos
+ * @return
+ */
+ protected abstract boolean onPickCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos);
+
+
+ private static final Key KEY_CLICK_LISTENERS = new KeyOf(SyncListenerList.class);
+
+ @Override
+ public void addListener(final IElement e, final ICanvasContext ctx, final IThreadWorkQueue thread, final ClickListener listener) {
+ ThreadUtils.syncExec(ctx.getThreadAccess(), new Runnable() {
+ @Override
+ public void run() {
+ DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);
+ SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);
+ if (list==null) {
+ list = new SyncListenerList<ClickListener>(ClickListener.class);
+ dp.setElementHint(e, KEY_CLICK_LISTENERS, list);
+ }
+ list.add(thread, listener);
+ }});
+ }
+
+ @Override
+ public void removeListener(final IElement e, final ICanvasContext ctx, final IThreadWorkQueue thread, final ClickListener listener) {
+ ThreadUtils.syncExec(ctx.getThreadAccess(), new Runnable() {
+ @Override
+ public void run() {
+ DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);
+ SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);
+ if (list==null) return;
+ list.remove(thread, listener);
+ if (list.isEmpty())
+ dp.removeElementHint(e, KEY_CLICK_LISTENERS);
+ }});
+ }
+
+ private final static Method onClick = SyncListenerList.getMethod(ClickListener.class, "onClick");
+ public void fireClicked(IElement e, ICanvasContext ctx)
+ {
+ DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);
+ SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);
+ if (list==null) return;
+ Executable exes[] = list.getExecutables(onClick, e, ctx);
+ ThreadUtils.multiSyncExec(exes);
+ }
+
+}