In Node, there is layout attached to the Layout X and Layout Y properties that attempts to prevent another layout pass when the properties changed belong to the Node currently being laid out.
This detection uses `Parent::isCurrentLayoutChild`, however, in almost all cases this check fails (returns `false`) because the current layout child is not automatically updated by all common layout containers. The only code that updates this value is the Parent class itself, but it only does this at the parent's parent level. In other words, if you have this tree:
Root -> Intermediate -> Leaf
Then Root's current layout child will be "Intermediate ", but Intermediate's layout child is not set (it will be null). Node's check will do:
leaf.getParent().isCurrentLayoutChild(leaf)
This almost always returns false. The only time it doesn't return false if it one does NOT override `layoutChildren` from Parent, as Parent does track the current layout child correctly... however, this method is almost always overridden, and even if you called `super.layoutChildren` it wouldn't work as the current layout child must be set correctly *just* before it is modified.
Solution
========
What Node really wants to know is:
Is this layout X/Y change triggered by code from its parent's layoutChildren? If so, then the change is expected, and we don't need to schedule another layout pass.
As JavaFX is single thread, the question boils down to: is the parent layoutChildren call somewhere in the call stack?
This can be easily tracked by having a flag in Parent that is set just before the layoutChildren call, and cleared immediately after it. Anything that ran during that time that modified the layout X/Y of a direct child of such a container can be considered "expected layout behavior".
So I propose to add a new flag `inLayoutChildren` which `Node` can query instead of using `isCurrentLayoutChild`. As `Node` is the only user of the previous mechanism, and it is not public API, the previous system can be removed.
This detection uses `Parent::isCurrentLayoutChild`, however, in almost all cases this check fails (returns `false`) because the current layout child is not automatically updated by all common layout containers. The only code that updates this value is the Parent class itself, but it only does this at the parent's parent level. In other words, if you have this tree:
Root -> Intermediate -> Leaf
Then Root's current layout child will be "Intermediate ", but Intermediate's layout child is not set (it will be null). Node's check will do:
leaf.getParent().isCurrentLayoutChild(leaf)
This almost always returns false. The only time it doesn't return false if it one does NOT override `layoutChildren` from Parent, as Parent does track the current layout child correctly... however, this method is almost always overridden, and even if you called `super.layoutChildren` it wouldn't work as the current layout child must be set correctly *just* before it is modified.
Solution
========
What Node really wants to know is:
Is this layout X/Y change triggered by code from its parent's layoutChildren? If so, then the change is expected, and we don't need to schedule another layout pass.
As JavaFX is single thread, the question boils down to: is the parent layoutChildren call somewhere in the call stack?
This can be easily tracked by having a flag in Parent that is set just before the layoutChildren call, and cleared immediately after it. Anything that ran during that time that modified the layout X/Y of a direct child of such a container can be considered "expected layout behavior".
So I propose to add a new flag `inLayoutChildren` which `Node` can query instead of using `isCurrentLayoutChild`. As `Node` is the only user of the previous mechanism, and it is not public API, the previous system can be removed.
- links to
-
Review(master)
openjdk/jfx/1945