1 /* 2 * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.scene.input; 27 28 import com.sun.javafx.scene.input.InputEventUtils; 29 import com.sun.javafx.scene.input.TouchPointHelper; 30 import java.io.IOException; 31 import java.io.Serializable; 32 import javafx.beans.NamedArg; 33 import javafx.event.EventTarget; 34 import javafx.geometry.Point3D; 35 import javafx.scene.Node; 36 import javafx.scene.Scene; 37 38 /** 39 * Touch point represents a single point of a multi-touch action, typically 40 * one finger touching a screen. It is contained in {@link TouchEvent}. 41 * <p> 42 * The touch point has its coordinates, state (see {@link State}) and ID. The 43 * ID is sequential number of this touch point unique in scope of a single 44 * multi-touch gesture. 45 * <p> 46 * Each touch point is by default delivered to a single node during its whole 47 * trajectory - to the node on which it was pressed. There is a grabbing API 48 * to modify this behavior. The above means that when touch point is pressed, 49 * it is automatically grabbed by the top-most node on the press coordinates. 50 * Any time during the gesture {@code grab()} and {@code ungrab()} methods 51 * can be used to alter the event delivery target. When grabbed by a different 52 * node, it will next time be targeted to it; when ungrabbed, it will be 53 * always targeted to the top-most node on the current location. 54 * 55 * @since JavaFX 2.2 56 */ 57 public final class TouchPoint implements Serializable{ 58 59 static { 60 // This is used by classes in different packages to get access to 61 // private and package private methods. 62 TouchPointHelper.setTouchPointAccessor(new TouchPointHelper.TouchPointAccessor() { 63 64 @Override 65 public void reset(TouchPoint touchPoint) { 66 touchPoint.reset(); 67 } 68 }); 69 } 70 71 private transient EventTarget target; 72 private transient Object source; 73 74 /** 75 * Creates new instance of TouchPoint. 76 * @param id ID of the new touch point 77 * @param state state of the new touch point 78 * @param x The x with respect to the scene. 79 * @param y The y with respect to the scene. 80 * @param screenX The x coordinate relative to screen. 81 * @param screenY The y coordinate relative to screen. 82 * @param pickResult pick result. Can be null, in this case a 2D pick result 83 * without any further values is constructed 84 * based on the scene coordinates and target 85 * @since JavaFX 8.0 86 */ 87 public TouchPoint(@NamedArg("id") int id, @NamedArg("state") State state, @NamedArg("x") double x, @NamedArg("y") double y, @NamedArg("screenX") double screenX, 88 @NamedArg("screenY") double screenY, @NamedArg("target") EventTarget target, @NamedArg("pickResult") PickResult pickResult) { 89 this.target = target; 90 this.id = id; 91 this.state = state; 92 this.x = x; 93 this.y = y; 94 this.sceneX = x; 95 this.sceneY = y; 96 this.screenX = screenX; 97 this.screenY = screenY; 98 this.pickResult = pickResult != null ? pickResult : new PickResult(target, x, y); 99 final Point3D p = InputEventUtils.recomputeCoordinates(this.pickResult, null); 100 this.x = p.getX(); 101 this.y = p.getY(); 102 this.z = p.getZ(); 103 } 104 105 /** 106 * Recomputes this touch point (coordinates, relevancy) for the given event 107 * source object. 108 * @param oldSource Source object of the current values 109 * @param newSource Source object to compute values for 110 */ 111 void recomputeToSource(Object oldSource, Object newSource) { 112 113 final Point3D newCoordinates = InputEventUtils.recomputeCoordinates( 114 pickResult, newSource); 115 116 x = newCoordinates.getX(); 117 y = newCoordinates.getY(); 118 z = newCoordinates.getZ(); 119 120 source = newSource; 121 } 122 123 /** 124 * Distinguishes between touch points targeted to the given node or some 125 * of its children from touch points targeted somewhere else. This allows 126 * for testing all touch points carried by one touch event on their 127 * relevance for a given node. 128 * @param target Node or other event target to be tested 129 * @return true if this touch point is targeted to the given target or 130 * some of its children 131 */ 132 public boolean belongsTo(EventTarget target) { 133 134 if (this.target instanceof Node) { 135 Node n = (Node) this.target; 136 137 if (target instanceof Scene) { 138 return n.getScene() == target; 139 } 140 while (n != null) { 141 if (n == target) { 142 return true; 143 } 144 n = n.getParent(); 145 } 146 } 147 148 return target == this.target; 149 } 150 151 private void reset() { 152 final Point3D p = InputEventUtils.recomputeCoordinates(pickResult, null); 153 x = p.getX(); 154 y = p.getY(); 155 z = p.getZ(); 156 } 157 158 private EventTarget grabbed = null; 159 160 /** 161 * Gets event target which has grabbed this touch point. 162 * @return The current grabbed target, null if the touch point is ungrabbed 163 */ 164 public EventTarget getGrabbed() { 165 return grabbed; 166 } 167 168 /** 169 * Grabs this touch point by current event source. Next event containing 170 * this touch point will be targeted to the same node whose event handler 171 * called this method. 172 */ 173 public void grab() { 174 if (source instanceof EventTarget) { 175 grabbed = (EventTarget) source; 176 } else { 177 throw new IllegalStateException("Cannot grab touch point, " 178 + "source is not an instance of EventTarget: " + source); 179 } 180 } 181 182 /** 183 * Grabs this touch point by the given target. Next event containing this 184 * touch point will be targeted to it. 185 * @param target Target by which to grab the touch point 186 */ 187 public void grab(EventTarget target) { 188 grabbed = target; 189 } 190 191 /** 192 * Ungrabs this touch point from its target. Since the next event this 193 * touch point will be delivered to the top-most node picked on its 194 * respective location until it is grabbed again or released. 195 */ 196 public void ungrab() { 197 grabbed = null; 198 } 199 200 private int id; 201 202 /** 203 * Gets identifier of this touch point. The number is sequential and unique 204 * in scope of one multi touch gesture. The first pressed touch point has id 205 * {@code 1}, each subsequently pressed touch points gets the next ordinal 206 * number until all touch points are released and the counter is reset. 207 * 208 * @return the identifier of this touch point. 209 */ 210 public final int getId() { 211 return id; 212 } 213 214 private State state; 215 216 /** 217 * Gets state of this touch point 218 * @return state of this touch point 219 */ 220 public final State getState() { 221 return state; 222 } 223 224 225 private transient double x; 226 227 /** 228 * Gets the horizontal position of the touch point relative to the 229 * origin of the TouchEvent's source. 230 * 231 * @return the horizontal position of the touch point relative to the 232 * origin of the TouchEvent's source. 233 */ 234 public final double getX() { 235 return x; 236 } 237 238 private transient double y; 239 240 /** 241 * Gets the vertical position of the touch point relative to the 242 * origin of the TouchEvent's source. 243 * 244 * @return the vertical position of the touch point relative to the 245 * origin of the TouchEvent's source. 246 */ 247 public final double getY() { 248 return y; 249 } 250 251 /** 252 * Depth z position of the event relative to the 253 * origin of the MouseEvent's node. 254 */ 255 private transient double z; 256 257 /** 258 * Depth position of the event relative to the 259 * origin of the MouseEvent's source. 260 * 261 * @return depth position of the event relative to the 262 * origin of the MouseEvent's source. 263 * @since JavaFX 8.0 264 */ 265 public final double getZ() { 266 return z; 267 } 268 269 private double screenX; 270 271 /** 272 * Gets the absolute horizontal position of the touch point. 273 * @return the absolute horizontal position of the touch point 274 */ 275 public final double getScreenX() { 276 return screenX; 277 } 278 279 private double screenY; 280 281 /** 282 * Gets the absolute vertical position of the touch point. 283 * @return the absolute vertical position of the touch point 284 */ 285 public final double getScreenY() { 286 return screenY; 287 } 288 289 private double sceneX; 290 291 /** 292 * Gets the horizontal position of the touch point relative to the 293 * origin of the {@code Scene} that contains the TouchEvent's source. 294 * If the node is not in a {@code Scene}, then the value is relative to 295 * the boundsInParent of the root-most parent of the TouchEvent's node. 296 * Note that in 3D scene, this represents the flat coordinates after 297 * applying the projection transformations. 298 * 299 * @return the horizontal position of the touch point relative to the 300 * origin of the {@code Scene} that contains the TouchEvent's source 301 */ 302 public final double getSceneX() { 303 return sceneX; 304 } 305 306 private double sceneY; 307 308 /** 309 * Gets the vertical position of the touch point relative to the 310 * origin of the {@code Scene} that contains the TouchEvent's source. 311 * If the node is not in a {@code Scene}, then the value is relative to 312 * the boundsInParent of the root-most parent of the TouchEvent's node. 313 * Note that in 3D scene, this represents the flat coordinates after 314 * applying the projection transformations. 315 * 316 * @return the vertical position of the touch point relative to the 317 * origin of the {@code Scene} that contains the TouchEvent's source 318 */ 319 public final double getSceneY() { 320 return sceneY; 321 } 322 323 /** 324 * Information about the pick if the picked {@code Node} is a 325 * {@code Shape3D} node and its pickOnBounds is false. 326 */ 327 private PickResult pickResult; 328 329 /** 330 * Returns information about the pick. 331 * 332 * @return new PickResult object that contains information about the pick 333 * @since JavaFX 8.0 334 */ 335 public final PickResult getPickResult() { 336 return pickResult; 337 } 338 339 /** 340 * Gets event target on which the touch event carrying this touch point 341 * is fired. 342 * @return Event target for this touch point 343 */ 344 public EventTarget getTarget() { 345 return target; 346 } 347 348 /** 349 * Returns a string representation of this {@code TouchPoint} object. 350 * @return a string representation of this {@code TouchPoint} object. 351 */ 352 @Override public String toString() { 353 final StringBuilder sb = new StringBuilder("TouchPoint ["); 354 355 sb.append("state = ").append(getState()); 356 sb.append(", id = ").append(getId()); 357 sb.append(", target = ").append(getTarget()); 358 sb.append(", x = ").append(getX()).append(", y = ").append(getY()) 359 .append(", z = ").append(getZ()); 360 sb.append(", pickResult = ").append(getPickResult()); 361 362 return sb.append("]").toString(); 363 } 364 365 private void readObject(java.io.ObjectInputStream in) 366 throws IOException, ClassNotFoundException { 367 in.defaultReadObject(); 368 x = sceneX; 369 y = sceneY; 370 } 371 372 /** 373 * Represents current state of the touch point 374 * 375 * @since JavaFX 2.2 376 */ 377 public enum State { 378 /** 379 * The touch point has just been pressed (touched for the first time) 380 */ 381 PRESSED, 382 /** 383 * The touch point has been moved 384 */ 385 MOVED, 386 /** 387 * The touch point remains pressed and still (without moving) 388 */ 389 STATIONARY, 390 /** 391 * The touch point has been released 392 */ 393 RELEASED 394 } 395 }