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.drag.source;
  33 
  34 import com.oracle.javafx.scenebuilder.kit.util.MathUtils;
  35 import javafx.geometry.Bounds;
  36 import javafx.geometry.Rectangle2D;
  37 import javafx.scene.Group;
  38 import javafx.scene.Node;
  39 import javafx.scene.SnapshotParameters;
  40 import javafx.scene.image.ImageView;
  41 import javafx.scene.layout.Region;
  42 import javafx.scene.transform.NonInvertibleTransformException;
  43 import javafx.scene.transform.Transform;
  44 
  45 /**
  46  * A shadow is the following construct:
  47  *
  48  *    Group
  49  *         ImageView        snapshot of a 'scene graph node'
  50  *         Region           glass area with css styling
  51  *
  52  * Layout bounds of the group must be equal to layout bounds
  53  * of the scene graph node. We ensure this by setting layoutX/Y
  54  * on the image view and the region (1).
  55  */
  56 class DragSourceShadow extends Group {
  57 
  58     private final ImageView imageView = new ImageView();
  59     private final Region glass = new Region();
  60     private static final String NID_DRAG_SHADOW = "dragShadow"; //NOI18N
  61 
  62 
  63     public DragSourceShadow() {
  64         this.setId(NID_DRAG_SHADOW);
  65         this.getChildren().add(imageView);
  66         this.getChildren().add(glass);
  67 
  68         this.getStyleClass().add("drag-shadow"); //NOI18N
  69         this.glass.getStyleClass().add("drag-shadow-glass"); //NOI18N
  70     }
  71 
  72     public void setupForNode(Node node) {
  73         assert node != null;
  74         assert node.getScene() != null;
  75 
  76         // Snapshot node
  77         // Note : we setup snapshot view port with layout bounds.
  78         final SnapshotParameters sp = new SnapshotParameters();
  79         final Transform l2p = node.getLocalToParentTransform();
  80         try {
  81             sp.setTransform(l2p.createInverse());
  82         } catch(NonInvertibleTransformException x) {
  83             throw new RuntimeException(x);
  84         }
  85         final Bounds vp = node.getLayoutBounds();
  86         if ((vp.getWidth() >= 0) && (vp.getHeight() >= 0)) {
  87             sp.setViewport(new Rectangle2D(vp.getMinX(), vp.getMinY(),
  88                     vp.getWidth(), vp.getHeight()));
  89         }
  90         imageView.setImage(node.snapshot(sp, null));
  91 
  92         // Setup layoutX/layoutY on the image view and the region (1)
  93         final Bounds inputBounds = vp;
  94         imageView.setLayoutX(inputBounds.getMinX());
  95         imageView.setLayoutY(inputBounds.getMinY());
  96         glass.setLayoutX(inputBounds.getMinX());
  97         glass.setLayoutY(inputBounds.getMinY());
  98         glass.setPrefWidth(inputBounds.getWidth());
  99         glass.setPrefHeight(inputBounds.getHeight());
 100 
 101         final Bounds outputBounds = this.getLayoutBounds();
 102         assert MathUtils.equals(inputBounds.getMinX(), outputBounds.getMinX())
 103                 : "inputBounds=" + inputBounds + ", outputBounds=" + outputBounds; //NOI18N
 104         assert MathUtils.equals(inputBounds.getMinY(), outputBounds.getMinY())
 105                 : "inputBounds=" + inputBounds + ", outputBounds=" + outputBounds; //NOI18N
 106         assert MathUtils.equals(inputBounds.getWidth(), outputBounds.getWidth(), 5.0)
 107                 : "inputBounds=" + inputBounds + ", outputBounds=" + outputBounds; //NOI18N
 108         assert MathUtils.equals(inputBounds.getHeight(), outputBounds.getHeight(), 5.0)
 109                 : "inputBounds=" + inputBounds + ", outputBounds=" + outputBounds; //NOI18N
 110     }
 111 }