]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/AbstractClickable.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / element / handler / impl / AbstractClickable.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.g2d.element.handler.impl;
13
14 import java.awt.geom.Point2D;
15 import java.lang.reflect.Method;
16 import java.util.Map;
17
18 import org.simantics.g2d.canvas.ICanvasContext;
19 import org.simantics.g2d.diagram.participant.DiagramParticipant;
20 import org.simantics.g2d.element.ElementUtils;
21 import org.simantics.g2d.element.IElement;
22 import org.simantics.g2d.element.handler.Clickable;
23 import org.simantics.scenegraph.g2d.events.MouseEvent;
24 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;
25 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;
26 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;
27 import org.simantics.utils.datastructures.hints.IHintContext.Key;
28 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
29 import org.simantics.utils.threads.Executable;
30 import org.simantics.utils.threads.IThreadWorkQueue;
31 import org.simantics.utils.threads.SyncListenerList;
32 import org.simantics.utils.threads.ThreadUtils;
33
34 /**
35  * Base implementation for button handlers
36  * 
37  * 
38  * @author Toni Kalajainen
39  */
40 public abstract class AbstractClickable extends AbstractGrabbable implements Clickable {
41         
42         private static final long serialVersionUID = -8329973386869163106L;
43         
44         public static Key HOVER_KEY = new KeyOf(Boolean.class, "HOVER");
45         public static Key PRESS_STATUS_KEY = new KeyOf(PressStatus.class, "PRESS_STATUS");
46         
47         public AbstractClickable(Double strayDistance) {
48                 super(1000.0);
49         }
50         
51         public AbstractClickable() {
52                 super();
53         }       
54
55         /**
56          * Get element press status
57          * @param e
58          * @param ctx
59          * @return
60          */
61         public PressStatus getPressStatus(IElement e, ICanvasContext ctx)
62         {
63                 Map<Integer, GrabInfo> gis = getGrabs(e, ctx);
64                 if (gis==null || gis.size()==0) {
65                         Boolean hover = e.getHint(HOVER_KEY);
66                         if (hover != null && hover)
67                                 return PressStatus.HOVER;
68                         return PressStatus.NORMAL;
69                 }
70                 
71                 // is held down 
72                 boolean held = false;
73                 boolean pressing = false;
74                 
75                 for (GrabInfo gi : gis.values()) {
76                         held = true;
77                         pressing |= onPickCheck(e, ctx, gi.pointerId, gi.dragPosElement);
78                         if (pressing) break;
79                 }               
80                 
81                 if (pressing) return PressStatus.PRESSED;
82                 if (held) return PressStatus.HELD;
83                 Boolean hover = e.getHint(HOVER_KEY);
84                 if (hover != null && hover)
85                         return PressStatus.HOVER;
86
87                 return PressStatus.NORMAL;
88         }
89         
90         
91         @Override
92         public boolean handleMouseEvent(IElement e, ICanvasContext ctx,
93                         MouseEvent me) {
94                 //System.out.println("AbstractClickable.hME element:" + e + " me:" + me);
95                 boolean b = super.handleMouseEvent(e, ctx, me);
96                 Boolean hovering;
97                 // DND drag starts causes DragBegin + ButtonReleasedEvents, and hovering must be set false
98                 if (!(me instanceof MouseExitEvent || me instanceof MouseDragBegin || me instanceof MouseButtonReleasedEvent))
99                         hovering = Boolean.valueOf(onPickCheck(e, ctx, me.mouseId, ElementUtils.controlToElementCoordinate(e, ctx, me.controlPosition, null)));
100                 else
101                         hovering = false;
102                 if (!hovering.equals(e.getHint(HOVER_KEY))) {
103                         e.setHint(HOVER_KEY, hovering);
104                 }
105                 
106                 // hackety hack
107                 PressStatus newStatus = getPressStatus(e, ctx);
108                 if (!newStatus.equals(e.getHint(PRESS_STATUS_KEY)))
109                         e.setHint(PRESS_STATUS_KEY, newStatus) ;
110                 return b;
111         }
112         
113         @Override
114         protected void onDrag(GrabInfo gi, ICanvasContext ctx) {
115                 
116         }
117
118         @Override
119         protected void onGrab(GrabInfo gi, ICanvasContext ctx) {
120         }
121
122         @Override
123         protected void onGrabCancel(GrabInfo gi, ICanvasContext ctx) {
124         }
125
126         @Override
127         protected void onRelease(GrabInfo gi, ICanvasContext ctx) {
128                 // pick is pick until last mouse releases
129                 if (getGrabCount(gi.e, ctx)>0) return;
130                 
131                 boolean pick = onPickCheck(gi.e, ctx, gi.pointerId, gi.dragPosElement);
132                 if (pick) {
133                         onClicked(gi, ctx);
134                         fireClicked(gi.e, ctx);
135                 }
136         }
137         
138         protected boolean onGrabCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos)
139         {
140                 Point2D elementPos = ElementUtils.controlToElementCoordinate(e, ctx, pickPos, null); 
141                 return onPickCheck(e, ctx, pointerId, elementPos);
142         }
143         
144         protected abstract void onClicked(GrabInfo gi, ICanvasContext ctx);
145         
146         /**
147          * Pick check in element coordinates
148          * @param e
149          * @param ctx
150          * @param pointerId
151          * @param pickPos
152          * @return
153          */
154         protected abstract boolean onPickCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos);
155
156
157         private static final Key KEY_CLICK_LISTENERS = new KeyOf(SyncListenerList.class);
158         
159         @Override
160         public void addListener(final IElement e, final ICanvasContext ctx, final IThreadWorkQueue thread, final ClickListener listener) {
161                 ThreadUtils.syncExec(ctx.getThreadAccess(), new Runnable() {
162                         @Override
163                         public void run() {
164                                 DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);
165                                 SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);
166                                 if (list==null) {
167                                         list = new SyncListenerList<ClickListener>(ClickListener.class);
168                                         dp.setElementHint(e, KEY_CLICK_LISTENERS, list);
169                                 }
170                                 list.add(thread, listener);
171                         }});            
172         }
173
174         @Override
175         public void removeListener(final IElement e, final ICanvasContext ctx, final IThreadWorkQueue thread, final ClickListener listener) {
176                 ThreadUtils.syncExec(ctx.getThreadAccess(), new Runnable() {
177                         @Override
178                         public void run() {
179                                 DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);
180                                 SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);
181                                 if (list==null) return;
182                                 list.remove(thread, listener);
183                                 if (list.isEmpty())
184                                         dp.removeElementHint(e, KEY_CLICK_LISTENERS);
185                         }});            
186         }               
187         
188         private final static Method onClick = SyncListenerList.getMethod(ClickListener.class, "onClick");
189         public void fireClicked(IElement e, ICanvasContext ctx)
190         {
191                 DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);
192                 SyncListenerList<ClickListener> list = dp.getElementHint(e, KEY_CLICK_LISTENERS);
193                 if (list==null) return;
194                 Executable exes[] = list.getExecutables(onClick, e, ctx);
195                 ThreadUtils.multiSyncExec(exes);
196         }
197         
198 }