modules/graphics/src/main/java/javafx/scene/Parent.java

Print this page

        

*** 59,68 **** --- 59,70 ---- import com.sun.javafx.scene.input.PickResultChooser; import com.sun.javafx.sg.prism.NGGroup; import com.sun.javafx.sg.prism.NGNode; import com.sun.javafx.tk.Toolkit; import com.sun.javafx.scene.LayoutFlags; + import com.sun.javafx.scene.ParentHelper; + import java.util.Collections; import javafx.stage.Window; /** * The base class for all nodes that have children in the scene graph. * <p>
*** 95,104 **** --- 97,118 ---- * Do not populate list of removed children when its number exceeds threshold, * but mark whole parent dirty. */ private boolean removedChildrenOptimizationDisabled = false; + static { + // This is used by classes in different packages to get access to + // private and package private methods. + ParentHelper.setParentAccessor(new ParentHelper.ParentAccessor() { + + @Override + public boolean pickChildrenNode(Parent parent, PickRay pickRay, PickResultChooser result) { + return parent.pickChildrenNode(pickRay, result); + } + }); + } + /** * @treatAsPrivate implementation detail * @deprecated This is an internal API that is not intended for use and will be removed in the next version */ @Deprecated
*** 138,147 **** --- 152,165 ---- } pgChildrenSize = children.size(); startIdx = pgChildrenSize; } + if (sortedChildrenDirty) { + computeSortedChidrenAndUpdatePeer(); + sortedChildrenDirty = false; + } if (Utils.assertionEnabled()) validatePG(); } /***********************************************************************
*** 193,202 **** --- 211,279 ---- str += nn + " "; } System.out.println(str); } + /** + * The sortedChildren list is sorted by the children's priorityOrder if it is not null. + * Its size should always be equal to children.size(). + * If sortedChildren is null it implies that the rendering order of the children + * is the same as the order in the children list. + */ + final private List<Node> sortedChildren = new ArrayList(1); + private boolean sortedChildrenDirty = false; + + void markSortedChildrenDirty() { + if (!sortedChildrenDirty) { + sortedChildrenDirty = true; + impl_markDirty(DirtyBits.NODE_PRIORITY_ORDER); + } + } + + private void computeSortedChidrenAndUpdatePeer() { + boolean priorityOrderSet = false; + for (Node child : children) { + // Need to update children of peer before sorting + NGNode childPeer = child.impl_getPeer(); + double po = child.getPriorityOrder(); + childPeer.setPriorityOrder(po); + + if (!priorityOrderSet && po != 0) { + priorityOrderSet = true; + } + } + + final NGGroup peer = impl_getPeer(); + List<NGNode> peerSortedChildren = peer.getSortedChildren(); + sortedChildren.clear(); + peerSortedChildren.clear(); + + if (priorityOrderSet) { + sortedChildren.addAll(children); + + // Sort in descending order (or big-to-small order) + Collections.sort(sortedChildren, (Node a, Node b) + -> a.getPriorityOrder() < b.getPriorityOrder() ? 1 + : a.getPriorityOrder() == b.getPriorityOrder() ? 0 : -1); + + for (Node child : sortedChildren) { + NGNode childPeer = child.impl_getPeer(); + peerSortedChildren.add(childPeer); + } + } + + } + + // Call this method if children order is needed for rendering and picking. + // The returned list should be treated as read only. + private List<Node> getOrderedChildren() { + if (!sortedChildren.isEmpty()) { + return sortedChildren; + } + return children; + } + // Variable used to indicate that the change to the children ObservableList is // a simple permutation as the result of a toFront or toBack operation. // We can avoid almost all of the processing of the on replace trigger in // this case. private boolean childrenTriggerPermutation = false;
*** 257,269 **** --- 334,356 ---- if (n.isManaged()) { relayout = true; } } + // Mark sortedChildrenDirty if there is modification to children list + // because priorty order was set on one of more children + if (((removedSize > 0) || (to - from) > 0) && !sortedChildren.isEmpty()) { + sortedChildrenDirty = true; + } // update the parent and scene for each new node for (int i = from; i < to; ++i) { Node node = children.get(i); + + // Newly added node has priority order set. + if (node.getPriorityOrder() != 0) { + sortedChildrenDirty = true; + } if (node.isManaged() || (node instanceof Parent && ((Parent) node).layoutFlag != LayoutFlags.CLEAN)) { relayout = true; } node.setParent(Parent.this); node.setScenes(getScene(), getSubScene(), /* reapplyCSS*/ true);
*** 353,362 **** --- 440,453 ---- impl_markDirty(DirtyBits.PARENT_CHILDREN); // Force synchronization to include the handling of invisible node // so that removed list will get cleanup to prevent memory leak. impl_markDirty(DirtyBits.NODE_FORCE_SYNC); + + if(sortedChildrenDirty) { + impl_markDirty(DirtyBits.NODE_PRIORITY_ORDER); + } } }) { @Override protected void onProposedChange(final List<Node> newNodes, int[] toBeRemoved) {
*** 693,719 **** final Node node = children.get(i); node.computeDerivedDepthTest(); } } /** * @treatAsPrivate implementation detail * @deprecated This is an internal API that is not intended for use and will be removed in the next version */ @Deprecated @Override protected void impl_pickNodeLocal(PickRay pickRay, PickResultChooser result) { - double boundsDistance = impl_intersectsBounds(pickRay); ! if (!Double.isNaN(boundsDistance)) { ! for (int i = children.size()-1; i >= 0; i--) { ! children.get(i).impl_pickNode(pickRay, result); ! if (result.isClosed()) { ! return; ! } ! } ! if (isPickOnBounds()) { result.offer(this, boundsDistance, PickResultChooser.computePoint(pickRay, boundsDistance)); } } } --- 784,813 ---- final Node node = children.get(i); node.computeDerivedDepthTest(); } } + boolean pickChildrenNode(PickRay pickRay, PickResultChooser result) { + List<Node> orderedChildren = getOrderedChildren(); + for (int i = orderedChildren.size() - 1; i >= 0; i--) { + orderedChildren.get(i).impl_pickNode(pickRay, result); + if (result.isClosed()) { + return false; + } + } + return true; + } + /** * @treatAsPrivate implementation detail * @deprecated This is an internal API that is not intended for use and will be removed in the next version */ @Deprecated @Override protected void impl_pickNodeLocal(PickRay pickRay, PickResultChooser result) { double boundsDistance = impl_intersectsBounds(pickRay); ! if (!Double.isNaN(boundsDistance) && pickChildrenNode(pickRay, result)) { if (isPickOnBounds()) { result.offer(this, boundsDistance, PickResultChooser.computePoint(pickRay, boundsDistance)); } } }