1 /* 2 * Copyright (c) 2012, 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 com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.relocater; 33 34 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName; 35 import com.oracle.javafx.scenebuilder.kit.util.MathUtils; 36 import java.util.ArrayList; 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.Map; 40 import java.util.Objects; 41 import javafx.geometry.Bounds; 42 import javafx.scene.Node; 43 import javafx.scene.layout.AnchorPane; 44 45 /** 46 * 47 * 48 */ 49 public class AnchorPaneRelocater extends AbstractRelocater<AnchorPane> { 50 51 private final double originalLayoutX; 52 private final double originalLayoutY; 53 private final Double originalLeftAnchor; 54 private final Double originalRightAnchor; 55 private final Double originalTopAnchor; 56 private final Double originalBottomAnchor; 57 private final PropertyName layoutXName = new PropertyName("layoutX"); 58 private final PropertyName layoutYName = new PropertyName("layoutY"); 59 private final PropertyName leftAnchorName = new PropertyName("leftAnchor", AnchorPane.class); 60 private final PropertyName rightAnchorName = new PropertyName("rightAnchor", AnchorPane.class); 61 private final PropertyName topAnchorName = new PropertyName("topAnchor", AnchorPane.class); 62 private final PropertyName bottomAnchorName = new PropertyName("bottomAnchor", AnchorPane.class); 63 private final List<PropertyName> propertyNames = new ArrayList<>(); 64 65 public AnchorPaneRelocater(Node sceneGraphObject) { 66 super(sceneGraphObject, AnchorPane.class); 67 this.originalLayoutX = sceneGraphObject.getLayoutX(); 68 this.originalLayoutY = sceneGraphObject.getLayoutY(); 69 this.originalLeftAnchor = AnchorPane.getLeftAnchor(sceneGraphObject); 70 this.originalRightAnchor = AnchorPane.getRightAnchor(sceneGraphObject); 71 this.originalTopAnchor = AnchorPane.getTopAnchor(sceneGraphObject); 72 this.originalBottomAnchor = AnchorPane.getBottomAnchor(sceneGraphObject); 73 74 if ((originalLeftAnchor == null) && (originalRightAnchor == null)) { 75 propertyNames.add(layoutXName); 76 } else { 77 if (originalLeftAnchor != null) { 78 propertyNames.add(leftAnchorName); 79 propertyNames.add(layoutXName); 80 } 81 if (originalRightAnchor != null) { 82 propertyNames.add(rightAnchorName); 83 } 84 } 85 if ((originalTopAnchor == null) && (originalBottomAnchor == null)) { 86 propertyNames.add(layoutYName); 87 } else { 88 if (originalTopAnchor != null) { 89 propertyNames.add(topAnchorName); 90 propertyNames.add(layoutYName); 91 } 92 if (originalBottomAnchor != null) { 93 propertyNames.add(bottomAnchorName); 94 } 95 } 96 } 97 98 99 /* 100 * AbstractRelocater 101 */ 102 @Override 103 public void moveToLayoutX(double newLayoutX, Bounds newLayoutBounds) { 104 if ((originalLeftAnchor == null) && (originalRightAnchor == null)) { 105 sceneGraphObject.setLayoutX(Math.round(newLayoutX)); 106 } else { 107 final Bounds parentLayoutBounds = sceneGraphObject.getParent().getLayoutBounds(); 108 if (originalLeftAnchor != null) { 109 final double leftAnchor = computeLeftAnchor(parentLayoutBounds, newLayoutBounds, newLayoutX); 110 AnchorPane.setLeftAnchor(sceneGraphObject, (double)Math.round(leftAnchor)); 111 } 112 if (originalRightAnchor != null) { 113 final double rightAnchor = computeRightAnchor(parentLayoutBounds, newLayoutBounds, newLayoutX); 114 AnchorPane.setRightAnchor(sceneGraphObject, (double)Math.round(rightAnchor)); 115 } 116 } 117 } 118 119 @Override 120 public void moveToLayoutY(double newLayoutY, Bounds newLayoutBounds) { 121 if ((originalTopAnchor == null) && (originalBottomAnchor == null)) { 122 sceneGraphObject.setLayoutY(Math.round(newLayoutY)); 123 } else { 124 final Bounds parentLayoutBounds = sceneGraphObject.getParent().getLayoutBounds(); 125 if (originalTopAnchor != null) { 126 final double topAnchor = computeTopAnchor(parentLayoutBounds, newLayoutBounds, newLayoutY); 127 AnchorPane.setTopAnchor(sceneGraphObject, (double)Math.round(topAnchor)); 128 } 129 if (originalBottomAnchor != null) { 130 final double bottomAnchor = computeBottomAnchor(parentLayoutBounds, newLayoutBounds, newLayoutY); 131 AnchorPane.setBottomAnchor(sceneGraphObject, (double)Math.round(bottomAnchor)); 132 } 133 } 134 } 135 136 @Override 137 public void revertToOriginalLocation() { 138 sceneGraphObject.setLayoutX(originalLayoutX); 139 sceneGraphObject.setLayoutY(originalLayoutY); 140 AnchorPane.setLeftAnchor(sceneGraphObject, originalLeftAnchor); 141 AnchorPane.setRightAnchor(sceneGraphObject, originalRightAnchor); 142 AnchorPane.setTopAnchor(sceneGraphObject, originalTopAnchor); 143 AnchorPane.setBottomAnchor(sceneGraphObject, originalBottomAnchor); 144 } 145 146 @Override 147 public List<PropertyName> getPropertyNames() { 148 return propertyNames; 149 } 150 151 @Override 152 public Object getValue(PropertyName propertyName) { 153 assert propertyName != null; 154 assert propertyNames.contains(propertyName) : "propertyName=" + propertyName; 155 156 final Object result; 157 if (propertyName.equals(layoutXName)) { 158 result = sceneGraphObject.getLayoutX(); 159 } else if (propertyName.equals(layoutYName)) { 160 result = sceneGraphObject.getLayoutY(); 161 } else if (propertyName.equals(leftAnchorName)) { 162 result = AnchorPane.getLeftAnchor(sceneGraphObject); 163 } else if (propertyName.equals(rightAnchorName)) { 164 result = AnchorPane.getRightAnchor(sceneGraphObject); 165 } else if (propertyName.equals(topAnchorName)) { 166 result = AnchorPane.getTopAnchor(sceneGraphObject); 167 } else if (propertyName.equals(bottomAnchorName)) { 168 result = AnchorPane.getBottomAnchor(sceneGraphObject); 169 } else { 170 // Emergency code 171 result = null; 172 } 173 174 return result; 175 } 176 177 @Override 178 public Map<PropertyName, Object> getChangeMap() { 179 final Map<PropertyName, Object> result = new HashMap<>(); 180 if ((originalLeftAnchor == null) && (originalRightAnchor == null)) { 181 if (MathUtils.equals(sceneGraphObject.getLayoutX(), originalLayoutX) == false) { 182 result.put(layoutXName, sceneGraphObject.getLayoutX()); 183 } 184 } else { 185 if (Objects.equals(AnchorPane.getLeftAnchor(sceneGraphObject), originalLeftAnchor) == false) { 186 result.put(leftAnchorName, AnchorPane.getLeftAnchor(sceneGraphObject)); 187 result.put(layoutXName, sceneGraphObject.getLayoutX()); 188 } 189 if (Objects.equals(AnchorPane.getRightAnchor(sceneGraphObject), originalRightAnchor) == false) { 190 result.put(rightAnchorName, AnchorPane.getRightAnchor(sceneGraphObject)); 191 } 192 } 193 if ((originalTopAnchor == null) && (originalBottomAnchor == null)) { 194 if (MathUtils.equals(sceneGraphObject.getLayoutY(), originalLayoutY) == false) { 195 result.put(layoutYName, sceneGraphObject.getLayoutY()); 196 } 197 } else { 198 if (Objects.equals(AnchorPane.getTopAnchor(sceneGraphObject), originalTopAnchor) == false) { 199 result.put(topAnchorName, AnchorPane.getTopAnchor(sceneGraphObject)); 200 result.put(layoutYName, sceneGraphObject.getLayoutY()); 201 } 202 if (Objects.equals(AnchorPane.getBottomAnchor(sceneGraphObject), originalBottomAnchor) == false) { 203 result.put(bottomAnchorName, AnchorPane.getBottomAnchor(sceneGraphObject)); 204 } 205 } 206 return result; 207 } 208 209 210 211 /* 212 * Public (static) 213 */ 214 215 public static double computeLeftAnchor(Bounds parentBounds, Bounds childBounds, double targetLayoutX) { 216 /* 217 * o parent origin 218 * 219 * +---------------------------------------------------+ 220 * | | 221 * | o child origin | 222 * | | 223 * | +---------------------+ | 224 * | | | | 225 * | | | | 226 * | | | | 227 * | +---------------------+ | 228 * | | 229 * | | 230 * +------------------+----+---------------------------+ 231 * . . . 232 * . . . 233 * . . . 234 * x0 . x1 235 * . 236 * targetLayoutX 237 * 238 * result = x1 - x0 239 */ 240 241 final double x0 = parentBounds.getMinX(); 242 final double x1 = parentBounds.getMinX() + targetLayoutX + childBounds.getMinX(); 243 return x1 - x0; 244 } 245 246 public static double computeRightAnchor(Bounds parentBounds, Bounds childBounds, double targetLayoutX) { 247 /* 248 * o parent origin 249 * 250 * +---------------------------------------------------+ 251 * | | 252 * | o child origin | 253 * | | 254 * | +---------------------+ | 255 * | | | | 256 * | | | | 257 * | | | | 258 * | +---------------------+ | 259 * | | 260 * | | 261 * +------------------+--------------------------------+ 262 * . . . 263 * . . . 264 * . . . 265 * . x0 x1 266 * . 267 * targetLayoutX 268 * 269 * result = x1 - x0 270 */ 271 272 final double x0 = parentBounds.getMinX() + targetLayoutX + childBounds.getMaxX(); 273 final double x1 = parentBounds.getMaxX(); 274 return x1 - x0; 275 } 276 277 public static double computeTopAnchor(Bounds parentBounds, Bounds childBounds, double targetLayoutY) { 278 final double y0 = parentBounds.getMinY(); 279 final double y1 = parentBounds.getMinY() + targetLayoutY + childBounds.getMinY(); 280 return y1 - y0; 281 } 282 283 public static double computeBottomAnchor(Bounds parentBounds, Bounds childBounds, double targetLayoutY) { 284 final double y0 = parentBounds.getMinY() + targetLayoutY + childBounds.getMaxY(); 285 final double y1 = parentBounds.getMaxY(); 286 return y1 - y0; 287 } 288 }