]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/AbstractClickable.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / element / handler / impl / AbstractClickable.java
diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/AbstractClickable.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/AbstractClickable.java
new file mode 100644 (file)
index 0000000..ecd1d4c
--- /dev/null
@@ -0,0 +1,198 @@
+/*******************************************************************************\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