All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javafx.scene.Node Maven / Gradle / Ivy

There is a newer version: 24-ea+15
Show newest version
/*
 * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package javafx.scene;


import com.sun.javafx.geometry.BoundsUtils;
import com.sun.javafx.scene.traversal.TraversalMethod;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.binding.BooleanExpression;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.BooleanPropertyBase;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.DoublePropertyBase;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanPropertyBase;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectPropertyBase;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.property.StringPropertyBase;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.collections.ObservableSet;
import javafx.css.CssMetaData;
import javafx.css.ParsedValue;
import javafx.css.PseudoClass;
import javafx.css.StyleConverter;
import javafx.css.Styleable;
import javafx.css.StyleableBooleanProperty;
import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty;
import javafx.event.Event;
import javafx.event.EventDispatchChain;
import javafx.event.EventDispatcher;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.event.EventType;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.geometry.NodeOrientation;
import javafx.geometry.Orientation;
import javafx.geometry.Point2D;
import javafx.geometry.Point3D;
import javafx.geometry.Rectangle2D;
import javafx.scene.effect.BlendMode;
import javafx.scene.effect.Effect;
import javafx.scene.image.WritableImage;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.InputEvent;
import javafx.scene.input.InputMethodEvent;
import javafx.scene.input.InputMethodRequests;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.PickResult;
import javafx.scene.input.RotateEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.input.SwipeEvent;
import javafx.scene.input.TouchEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.input.ZoomEvent;
import javafx.scene.text.Font;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.stage.Window;
import javafx.util.Callback;
import java.security.AccessControlContext;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.sun.glass.ui.Accessible;
import com.sun.glass.ui.Application;
import com.sun.javafx.util.Logging;
import com.sun.javafx.util.TempState;
import com.sun.javafx.util.Utils;
import com.sun.javafx.beans.IDProperty;
import com.sun.javafx.beans.event.AbstractNotifyListener;
import com.sun.javafx.collections.TrackableObservableList;
import com.sun.javafx.collections.UnmodifiableListSet;
import com.sun.javafx.css.PseudoClassState;
import javafx.css.Selector;
import javafx.css.Style;
import javafx.css.converter.BooleanConverter;
import javafx.css.converter.CursorConverter;
import javafx.css.converter.EffectConverter;
import javafx.css.converter.EnumConverter;
import javafx.css.converter.SizeConverter;
import com.sun.javafx.effect.EffectDirtyBits;
import com.sun.javafx.geom.BaseBounds;
import com.sun.javafx.geom.BoxBounds;
import com.sun.javafx.geom.PickRay;
import com.sun.javafx.geom.RectBounds;
import com.sun.javafx.geom.Vec3d;
import com.sun.javafx.geom.transform.Affine3D;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.javafx.geom.transform.GeneralTransform3D;
import com.sun.javafx.geom.transform.NoninvertibleTransformException;
import com.sun.javafx.perf.PerformanceTracker;
import com.sun.javafx.scene.BoundsAccessor;
import com.sun.javafx.scene.CameraHelper;
import com.sun.javafx.scene.CssFlags;
import com.sun.javafx.scene.DirtyBits;
import com.sun.javafx.scene.EventHandlerProperties;
import com.sun.javafx.scene.LayoutFlags;
import com.sun.javafx.scene.NodeEventDispatcher;
import com.sun.javafx.scene.NodeHelper;
import com.sun.javafx.scene.SceneHelper;
import com.sun.javafx.scene.SceneUtils;
import com.sun.javafx.scene.input.PickResultChooser;
import com.sun.javafx.scene.transform.TransformHelper;
import com.sun.javafx.scene.transform.TransformUtils;
import com.sun.javafx.scene.traversal.Direction;
import com.sun.javafx.sg.prism.NGNode;
import com.sun.javafx.tk.Toolkit;
import com.sun.prism.impl.PrismSettings;
import com.sun.scenario.effect.EffectHelper;

import javafx.scene.shape.Shape3D;
import com.sun.javafx.logging.PlatformLogger;
import com.sun.javafx.logging.PlatformLogger.Level;

/**
 * Base class for scene graph nodes. A scene graph is a set of tree data structures
 * where every item has zero or one parent, and each item is either
 * a "leaf" with zero sub-items or a "branch" with zero or more sub-items.
 * 

* Each item in the scene graph is called a {@code Node}. Branch nodes are * of type {@link Parent}, whose concrete subclasses are {@link Group}, * {@link javafx.scene.layout.Region}, and {@link javafx.scene.control.Control}, * or subclasses thereof. *

* Leaf nodes are classes such as * {@link javafx.scene.shape.Rectangle}, {@link javafx.scene.text.Text}, * {@link javafx.scene.image.ImageView}, {@link javafx.scene.media.MediaView}, * or other such leaf classes which cannot have children. Only a single node within * each scene graph tree will have no parent, which is referred to as the "root" node. *

* There may be several trees in the scene graph. Some trees may be part of * a {@link Scene}, in which case they are eligible to be displayed. * Other trees might not be part of any {@link Scene}. *

* A node may occur at most once anywhere in the scene graph. Specifically, * a node must appear no more than once in all of the following: * as the root node of a {@link Scene}, * the children ObservableList of a {@link Parent}, * or as the clip of a {@link Node}. *

* The scene graph must not have cycles. A cycle would exist if a node is * an ancestor of itself in the tree, considering the {@link Group} content * ObservableList, {@link Parent} children ObservableList, and {@link Node} clip relationships * mentioned above. *

* If a program adds a child node to a Parent (including Group, Region, etc) * and that node is already a child of a different Parent or the root of a Scene, * the node is automatically (and silently) removed from its former parent. * If a program attempts to modify the scene graph in any other way that violates * the above rules, an exception is thrown, the modification attempt is ignored * and the scene graph is restored to its previous state. *

* It is possible to rearrange the structure of the scene graph, for * example, to move a subtree from one location in the scene graph to * another. In order to do this, one would normally remove the subtree from * its old location before inserting it at the new location. However, the * subtree will be automatically removed as described above if the application * doesn't explicitly remove it. *

* Node objects may be constructed and modified on any thread as long they are * not yet attached to a {@link Scene} in a {@link Window} that is * {@link Window#isShowing showing}. * An application must attach nodes to such a Scene or modify them on the JavaFX * Application Thread. * *

* The JavaFX Application Thread is created as part of the startup process for * the JavaFX runtime. See the {@link javafx.application.Application} class and * the {@link Platform#startup(Runnable)} method for more information. *

* *

* An application should not extend the Node class directly. Doing so may lead to * an UnsupportedOperationException being thrown. *

* *

String ID

*

* Each node in the scene graph can be given a unique {@link #idProperty id}. This id is * much like the "id" attribute of an HTML tag in that it is up to the designer * and developer to ensure that the {@code id} is unique within the scene graph. * A convenience function called {@link #lookup(String)} can be used to find * a node with a unique id within the scene graph, or within a subtree of the * scene graph. The id can also be used identify nodes for applying styles; see * the CSS section below. * *

Coordinate System

*

* The {@code Node} class defines a traditional computer graphics "local" * coordinate system in which the {@code x} axis increases to the right and the * {@code y} axis increases downwards. The concrete node classes for shapes * provide variables for defining the geometry and location of the shape * within this local coordinate space. For example, * {@link javafx.scene.shape.Rectangle} provides {@code x}, {@code y}, * {@code width}, {@code height} variables while * {@link javafx.scene.shape.Circle} provides {@code centerX}, {@code centerY}, * and {@code radius}. *

* At the device pixel level, integer coordinates map onto the corners and * cracks between the pixels and the centers of the pixels appear at the * midpoints between integer pixel locations. Because all coordinate values * are specified with floating point numbers, coordinates can precisely * point to these corners (when the floating point values have exact integer * values) or to any location on the pixel. For example, a coordinate of * {@code (0.5, 0.5)} would point to the center of the upper left pixel on the * {@code Stage}. Similarly, a rectangle at {@code (0, 0)} with dimensions * of {@code 10} by {@code 10} would span from the upper left corner of the * upper left pixel on the {@code Stage} to the lower right corner of the * 10th pixel on the 10th scanline. The pixel center of the last pixel * inside that rectangle would be at the coordinates {@code (9.5, 9.5)}. *

* In practice, most nodes have transformations applied to their coordinate * system as mentioned below. As a result, the information above describing * the alignment of device coordinates to the pixel grid is relative to * the transformed coordinates, not the local coordinates of the nodes. * The {@link javafx.scene.shape.Shape Shape} class describes some additional * important context-specific information about coordinate mapping and how * it can affect rendering. * *

Transformations

*

* Any {@code Node} can have transformations applied to it. These include * translation, rotation, scaling, or shearing. *

* A translation transformation is one which shifts the origin of the * node's coordinate space along either the x or y axis. For example, if you * create a {@link javafx.scene.shape.Rectangle} which is drawn at the origin * (x=0, y=0) and has a width of 100 and a height of 50, and then apply a * {@link javafx.scene.transform.Translate} with a shift of 10 along the x axis * (x=10), then the rectangle will appear drawn at (x=10, y=0) and remain * 100 points wide and 50 tall. Note that the origin was shifted, not the * {@code x} variable of the rectangle. *

* A common node transform is a translation by an integer distance, most often * used to lay out nodes on the stage. Such integer translations maintain the * device pixel mapping so that local coordinates that are integers still * map to the cracks between pixels. *

* A rotation transformation is one which rotates the coordinate space of * the node about a specified "pivot" point, causing the node to appear rotated. * For example, if you create a {@link javafx.scene.shape.Rectangle} which is * drawn at the origin (x=0, y=0) and has a width of 100 and height of 30 and * you apply a {@link javafx.scene.transform.Rotate} with a 90 degree rotation * (angle=90) and a pivot at the origin (pivotX=0, pivotY=0), then * the rectangle will be drawn as if its x and y were zero but its height was * 100 and its width -30. That is, it is as if a pin is being stuck at the top * left corner and the rectangle is rotating 90 degrees clockwise around that * pin. If the pivot point is instead placed in the center of the rectangle * (at point x=50, y=15) then the rectangle will instead appear to rotate about * its center. *

* Note that as with all transformations, the x, y, width, and height variables * of the rectangle (which remain relative to the local coordinate space) have * not changed, but rather the transformation alters the entire coordinate space * of the rectangle. *

* A scaling transformation causes a node to either appear larger or * smaller depending on the scaling factor. Scaling alters the coordinate space * of the node such that each unit of distance along the axis in local * coordinates is multiplied by the scale factor. As with rotation * transformations, scaling transformations are applied about a "pivot" point. * You can think of this as the point in the {@code Node} around which you "zoom". For * example, if you create a {@link javafx.scene.shape.Rectangle} with a * {@code strokeWidth} of 5, and a width and height of 50, and you apply a * {@link javafx.scene.transform.Scale} with scale factors (x=2.0, y=2.0) and * a pivot at the origin (pivotX=0, pivotY=0), the entire rectangle * (including the stroke) will double in size, growing to the right and * downwards from the origin. *

* A shearing transformation, sometimes called a skew, effectively * rotates one axis so that the x and y axes are no longer perpendicular. *

* Multiple transformations may be applied to a node. Custom transforms are applied using the * {@link #getTransforms transforms} list. Predefined transforms are applied using the properties specified below. * The matrices that represent the transforms are multiplied in this order: *

    *
  1. Layout ({@link #layoutXProperty layoutX}, {@link #layoutYProperty layoutY}) and translate * ({@link #translateXProperty translateX}, {@link #translateYProperty translateY}, {@link #translateZProperty translateZ})
  2. *
  3. Rotate ({@link #rotateProperty rotate})
  4. *
  5. Scale ({@link #scaleXProperty scaleX}, {@link #scaleYProperty scaleY}, {@link #scaleZProperty scaleZ})
  6. *
  7. Transforms list ({@link #getTransforms transforms}) starting from element 0
  8. *
* The transforms are applied in the reverse order of the matrix multiplication outlined above: last element of the transforms list * to 0th element, scale, rotate, and layout and translate. By applying the transforms in this order, the bounds in the local * coordinates of the node are transformed to the bounds in the parent coordinate of the node (see the * Bounding Rectangles section). * *

Bounding Rectangles

*

* Since every {@code Node} has transformations, every Node's geometric * bounding rectangle can be described differently depending on whether * transformations are accounted for or not. *

* Each {@code Node} has a read-only {@link #boundsInLocalProperty boundsInLocal} * variable which specifies the bounding rectangle of the {@code Node} in * untransformed local coordinates. {@code boundsInLocal} includes the * Node's shape geometry, including any space required for a * non-zero stroke that may fall outside the local position/size variables, * and its {@link #clipProperty clip} and {@link #effectProperty effect} variables. *

* Each {@code Node} also has a read-only {@link #boundsInParentProperty boundsInParent} variable which * specifies the bounding rectangle of the {@code Node} after all transformations * have been applied as specified in the Transformations section. * It is called "boundsInParent" because the rectangle will be relative to the * parent's coordinate system. This is the 'visual' bounds of the node. *

* Finally, the {@link #layoutBoundsProperty layoutBounds} variable defines the rectangular bounds of * the {@code Node} that should be used as the basis for layout calculations and * may differ from the visual bounds of the node. For shapes, Text, and ImageView, * layoutBounds by default includes only the shape geometry, including space required * for a non-zero {@code strokeWidth}, but does not include the effect, * clip, or any transforms. For resizable classes (Regions and Controls) * layoutBounds will always map to {@code 0,0 width x height}. * *

The image shows a node without any transformation and its {@code boundsInLocal}: *

A sine wave shape enclosed by
 * an axis-aligned rectangular bounds

* If we rotate the image by 20 degrees we get following result: *

An axis-aligned rectangular
 * bounds that encloses the shape rotated by 20 degrees

* The red rectangle represents {@code boundsInParent} in the * coordinate space of the Node's parent. The {@code boundsInLocal} stays the same * as in the first image, the green rectangle in this image represents {@code boundsInLocal} * in the coordinate space of the Node. * *

The images show a filled and stroked rectangle and their bounds. The * first rectangle {@code [x:10.0 y:10.0 width:100.0 height:100.0 strokeWidth:0]} * has the following bounds bounds: {@code [x:10.0 y:10.0 width:100.0 height:100.0]}. * * The second rectangle {@code [x:10.0 y:10.0 width:100.0 height:100.0 strokeWidth:5]} * has the following bounds: {@code [x:7.5 y:7.5 width:105 height:105]} * (the stroke is centered by default, so only half of it is outside * of the original bounds; it is also possible to create inside or outside * stroke). * * Since neither of the rectangles has any transformation applied, * {@code boundsInParent} and {@code boundsInLocal} are the same.

*

The rectangles are enclosed by their
 * respective bounds

* *

CSS

*

* The {@code Node} class contains {@code id}, {@code styleClass}, and * {@code style} variables that are used in styling this node from * CSS. The {@code id} and {@code styleClass} variables are used in * CSS style sheets to identify nodes to which styles should be * applied. The {@code style} variable contains style properties and * values that are applied directly to this node. *

* For further information about CSS and how to apply CSS styles * to nodes, see the CSS Reference * Guide. * * @since JavaFX 2.0 */ @IDProperty("id") public abstract class Node implements EventTarget, Styleable { /* * Store the singleton instance of the NodeHelper subclass corresponding * to the subclass of this instance of Node */ private NodeHelper nodeHelper = null; static { PerformanceTracker.logEvent("Node class loaded"); // This is used by classes in different packages to get access to // private and package private methods. NodeHelper.setNodeAccessor(new NodeHelper.NodeAccessor() { @Override public NodeHelper getHelper(Node node) { return node.nodeHelper; } @Override public void setHelper(Node node, NodeHelper nodeHelper) { node.nodeHelper = nodeHelper; } @Override public void doMarkDirty(Node node, DirtyBits dirtyBit) { node.doMarkDirty(dirtyBit); } @Override public void doUpdatePeer(Node node) { node.doUpdatePeer(); } @Override public BaseTransform getLeafTransform(Node node) { return node.getLeafTransform(); } @Override public Bounds doComputeLayoutBounds(Node node) { return node.doComputeLayoutBounds(); } @Override public void doTransformsChanged(Node node) { node.doTransformsChanged(); } @Override public void doPickNodeLocal(Node node, PickRay localPickRay, PickResultChooser result) { node.doPickNodeLocal(localPickRay, result); } @Override public boolean doComputeIntersects(Node node, PickRay pickRay, PickResultChooser pickResult) { return node.doComputeIntersects(pickRay, pickResult); } @Override public void doGeomChanged(Node node) { node.doGeomChanged(); } @Override public void doNotifyLayoutBoundsChanged(Node node) { node.doNotifyLayoutBoundsChanged(); } @Override public void doProcessCSS(Node node) { node.doProcessCSS(); } @Override public boolean isDirty(Node node, DirtyBits dirtyBit) { return node.isDirty(dirtyBit); } @Override public boolean isDirtyEmpty(Node node) { return node.isDirtyEmpty(); } @Override public void syncPeer(Node node) { node.syncPeer(); } @Override public void layoutBoundsChanged(Node node) { node.layoutBoundsChanged(); } @Override public

P getPeer(Node node) { return node.getPeer(); } @Override public void setShowMnemonics(Node node, boolean value) { node.setShowMnemonics(value); } @Override public boolean isShowMnemonics(Node node) { return node.isShowMnemonics(); } @Override public BooleanProperty showMnemonicsProperty(Node node) { return node.showMnemonicsProperty(); } @Override public boolean traverse(Node node, Direction direction, TraversalMethod method) { return node.traverse(direction, method); } @Override public double getPivotX(Node node) { return node.getPivotX(); } @Override public double getPivotY(Node node) { return node.getPivotY(); } @Override public double getPivotZ(Node node) { return node.getPivotZ(); } @Override public void pickNode(Node node,PickRay pickRay, PickResultChooser result) { node.pickNode(pickRay, result); } @Override public boolean intersects(Node node, PickRay pickRay, PickResultChooser pickResult) { return node.intersects(pickRay, pickResult); } @Override public double intersectsBounds(Node node, PickRay pickRay) { return node.intersectsBounds(pickRay); } @Override public void layoutNodeForPrinting(Node node) { node.doCSSLayoutSyncForSnapshot(); } @Override public boolean isDerivedDepthTest(Node node) { return node.isDerivedDepthTest(); } @Override public SubScene getSubScene(Node node) { return node.getSubScene(); } @Override public void setLabeledBy(Node node, Node labeledBy) { node.labeledBy = labeledBy; } @Override public Accessible getAccessible(Node node) { return node.getAccessible(); } @Override public void reapplyCSS(Node node) { node.reapplyCSS(); } @Override public void recalculateRelativeSizeProperties(Node node, Font fontForRelativeSizes) { node.recalculateRelativeSizeProperties(fontForRelativeSizes); } @Override public boolean isTreeVisible(Node node) { return node.isTreeVisible(); } @Override public BooleanExpression treeVisibleProperty(Node node) { return node.treeVisibleProperty(); } @Override public boolean isTreeShowing(Node node) { return node.isTreeShowing(); } @Override public List