1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package ensemble.samples.scenegraph.events.gestureevent; 33 34 import javafx.application.Application; 35 import javafx.collections.FXCollections; 36 import javafx.collections.ObservableList; 37 import javafx.event.EventHandler; 38 import javafx.scene.Cursor; 39 import javafx.scene.Node; 40 import javafx.scene.Parent; 41 import javafx.scene.Scene; 42 import javafx.scene.control.ListView; 43 import javafx.scene.input.RotateEvent; 44 import javafx.scene.input.ScrollEvent; 45 import javafx.scene.input.SwipeEvent; 46 import javafx.scene.input.TouchEvent; 47 import javafx.scene.input.ZoomEvent; 48 import javafx.scene.layout.Pane; 49 import javafx.scene.layout.VBox; 50 import javafx.scene.paint.Color; 51 import javafx.scene.paint.CycleMethod; 52 import javafx.scene.paint.LinearGradient; 53 import javafx.scene.paint.Stop; 54 import javafx.scene.shape.Rectangle; 55 import javafx.stage.Stage; 56 57 /** 58 * A sample that demonstrates various multi-touch gesture events and their usage. 59 * Tap, scroll and pan to move the rectangle. Use pinch close and open zoom 60 * gestures to resize it. User rotate touch gesture to rotate it. 61 * Swipe events are reported but not wired to any other behavior. 62 * All events are logged to the console. You can also observe inertia scrolling. 63 * 64 * @sampleName Gesture Event 65 * @preview preview.png 66 * @related /Scenegraph/Events/MouseEvent 67 * @related /Scenegraph/Events/Multi-Touch 68 * @see javafx.scene.input.RotateEvent 69 * @see javafx.scene.input.ScrollEvent 70 * @see javafx.scene.input.SwipeEvent 71 * @see javafx.scene.input.TouchEvent 72 * @see javafx.scene.input.ZoomEvent 73 * @see javafx.scene.Cursor 74 * @see javafx.collections.FXCollections 75 * @see javafx.collections.ObservableList 76 * @see javafx.event.EventHandler 77 * @see javafx.scene.control.ListView 78 * @see javafx.scene.layout.VBox 79 * @see javafx.scene.paint.Color 80 * @see javafx.scene.paint.CycleMethod 81 * @see javafx.scene.paint.LinearGradient 82 * @see javafx.scene.paint.Stop 83 * @see javafx.scene.shape.Rectangle 84 * @see javafx.scene.layout.Pane 85 * @embedded 86 */ 87 public class GestureEventApp extends Application { 88 89 private final static int SAMPLE_SCREEN_WIDTH = 400; 90 private final static int SAMPLE_SCREEN_HEIGHT = 380; 91 private final static int CONSOLE_WIDTH = 400; 92 private final static int CONSOLE_HEIGHT = 80; 93 private final static int BORDER_HEIGHT = SAMPLE_SCREEN_HEIGHT - CONSOLE_HEIGHT; 94 95 // some offset minus BORDER_HEIGHT so it's not off in the corner 96 private final static int SMALL_REC_Y = 20 - BORDER_HEIGHT; 97 98 //some offset so it's not off in the corner 99 private final static int SMALL_REC_X = 30; 100 101 //create a console for logging mouse events 102 final ListView<String> console = new ListView<>(); 103 104 //create a observableArrayList of logged events that will be listed in console 105 final ObservableList<String> consoleObservableList = FXCollections.observableArrayList(); 106 107 private String lastEvent = ""; 108 private int lastEventCount = 0; 109 110 public Parent createContent() { 111 //set up the console 112 console.setItems(consoleObservableList); 113 console.setPrefSize(CONSOLE_WIDTH, CONSOLE_HEIGHT); 114 console.setMinSize(ListView.USE_PREF_SIZE, ListView.USE_PREF_SIZE); 115 console.setMaxSize(ListView.USE_PREF_SIZE, ListView.USE_PREF_SIZE); 116 VBox root = new VBox(); 117 root.setSpacing(2); 118 root.setPrefSize(SAMPLE_SCREEN_WIDTH, SAMPLE_SCREEN_HEIGHT); 119 root.setMinSize(SAMPLE_SCREEN_WIDTH, SAMPLE_SCREEN_HEIGHT); 120 root.setMaxSize(SAMPLE_SCREEN_WIDTH, SAMPLE_SCREEN_HEIGHT); 121 122 Rectangle border = new Rectangle(400, BORDER_HEIGHT); 123 border.setStroke(Color.GRAY); 124 border.setFill(new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, new Stop[]{ 125 new Stop(1, Color.rgb(156, 216, 255)), 126 new Stop(0, Color.rgb(156, 216, 255, 0.5)) 127 })); 128 129 final Rectangle smallRec = createRectangle(); 130 smallRec.setTranslateX(SMALL_REC_X); 131 smallRec.setTranslateY(SMALL_REC_Y); 132 Pane box = new Pane(); 133 box.getChildren().addAll(border, smallRec); 134 setEventListeners(root, smallRec, "From background--"); 135 root.getChildren().addAll(console, border, smallRec); 136 137 return root; 138 } 139 140 private Rectangle createRectangle() { 141 final Rectangle smallRec = new Rectangle(100, 100, 100, 100); 142 LinearGradient gradient1 = new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE, new Stop[]{ 143 new Stop(0, Color.ANTIQUEWHITE), 144 new Stop(1, Color.CORAL) 145 }); 146 smallRec.setFill(gradient1); 147 smallRec.setStroke(Color.BLACK); 148 smallRec.setCursor(Cursor.HAND); 149 setEventListeners(smallRec, smallRec, "From rectangle--"); 150 151 return smallRec; 152 } 153 154 private void showOnConsole(String text) { 155 if (lastEvent.equals(text)) { 156 lastEventCount++; 157 consoleObservableList.set(consoleObservableList.size() - 1, 158 text + " (" + lastEventCount + " times)"); 159 } else { 160 if (consoleObservableList.size() == 500) { 161 consoleObservableList.remove(0); 162 } 163 consoleObservableList.add(text); 164 console.scrollTo(consoleObservableList.size()); 165 lastEvent = text; 166 lastEventCount = 1; 167 } 168 } 169 170 private void setEventListeners(final Node listeningNode, final Rectangle rec, final String msgPrefix) { 171 listeningNode.setOnSwipeDown((SwipeEvent se) -> { 172 showOnConsole(msgPrefix + "SwipeDown event"); 173 se.consume(); 174 }); 175 176 listeningNode.setOnSwipeUp((SwipeEvent se) -> { 177 showOnConsole(msgPrefix + "SwipeUp event"); 178 se.consume(); 179 }); 180 181 listeningNode.setOnSwipeLeft((SwipeEvent se) -> { 182 showOnConsole(msgPrefix + "SwipeLeft event"); 183 se.consume(); 184 }); 185 186 listeningNode.setOnSwipeRight((SwipeEvent se) -> { 187 showOnConsole(msgPrefix + "SwipeRight event"); 188 se.consume(); 189 }); 190 191 listeningNode.setOnTouchStationary((TouchEvent se) -> { 192 showOnConsole(msgPrefix + "TouchStationary event"); 193 se.consume(); 194 }); 195 196 listeningNode.setOnScroll((ScrollEvent event) -> { 197 // scroll amount 198 double translateX = event.getDeltaX(); 199 double translateY = event.getDeltaY(); 200 201 if ((rec.getTranslateX() + translateX > 0) && (rec.getTranslateX() + translateX < 300)) { 202 rec.setTranslateX(rec.getTranslateX() + translateX); 203 } 204 if ((rec.getTranslateY() + translateY > SMALL_REC_Y - 20) && (rec.getTranslateY() + translateY < 180 + SMALL_REC_Y)) { 205 rec.setTranslateY(rec.getTranslateY() + translateY); 206 } 207 showOnConsole(msgPrefix + "Scroll event"); 208 event.consume(); 209 }); 210 211 listeningNode.setOnZoom((ZoomEvent event) -> { 212 rec.setScaleX(rec.getScaleX() * event.getZoomFactor()); 213 rec.setScaleY(rec.getScaleY() * event.getZoomFactor()); 214 showOnConsole(msgPrefix + "Zoom event"); 215 event.consume(); 216 }); 217 218 listeningNode.setOnRotate((RotateEvent event) -> { 219 rec.setRotate(rec.getRotate() + event.getAngle()); 220 showOnConsole(msgPrefix + "Rotate event"); 221 event.consume(); 222 }); 223 224 listeningNode.setOnScrollStarted((ScrollEvent event) -> { 225 showOnConsole(msgPrefix + "Scroll started"); 226 event.consume(); 227 }); 228 229 listeningNode.setOnScrollFinished((ScrollEvent event) -> { 230 showOnConsole(msgPrefix + "Scroll finished"); 231 event.consume(); 232 }); 233 234 listeningNode.setOnZoomStarted((ZoomEvent event) -> { 235 showOnConsole(msgPrefix + "Zoom started"); 236 event.consume(); 237 }); 238 239 listeningNode.setOnZoomFinished((ZoomEvent event) -> { 240 showOnConsole(msgPrefix + "Zoom finished"); 241 event.consume(); 242 }); 243 244 listeningNode.setOnRotationStarted((RotateEvent event) -> { 245 showOnConsole(msgPrefix + "Rotation started"); 246 event.consume(); 247 }); 248 249 listeningNode.setOnRotationFinished((RotateEvent event) -> { 250 showOnConsole(msgPrefix + "Rotation finished"); 251 event.consume(); 252 }); 253 } 254 255 @Override 256 public void start(Stage primaryStage) throws Exception { 257 primaryStage.setScene(new Scene(createContent())); 258 primaryStage.show(); 259 } 260 261 /** 262 * Java main for when running without JavaFX launcher 263 * @param args command line arguments 264 */ 265 public static void main(String[] args) { 266 launch(args); 267 } 268 }