Skip to content

UIComponent: Deprecate animationFrame #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 4, 2025

Conversation

Johni0702
Copy link
Contributor

See the kdocs on ElementaVersion.V8 for details and motivation.

Aside from the changes behind the ElementaVersion flag, this commit also changes the behavior of constraints evaluated on components which do not have a window (because we therefore cannot determine the ElementaVersion) to never cache its value.
This is necessary because if we were to cache its value in that situation, we wouldn't be able to get it registered in the Window's cachedConstraints list, and so it'd never be invalidated again on V8+. The chance of someone relying on the constraint caching behaivor in such a specific scenario are sufficiently tiny that it seems safe to make this change.

Depends on #155 and #156.

The old API is difficult to work with because it will continue to render
floating components even if they've been removed from the component
tree. Additionally it can CME if components are removed from the
floating list during rendering, further complicating the workarounds
required.

This new API fixes the issue by tracking when components are
removed/added from/to the tree and updating its internal floating list
accordingly.
It also allows setting the floating state at any time, even before the
component has a parent, another thing the old API did not support.

The order in which floating components appear also differs in the new
API. While the old API showed floating components in the order in which
they were set to be floating, this often isn't all too useful when the
order in which components are added/removed to/from the tree is not
particularily well defined. As such, the new API choses to instead order
floating components in exactly the same way as they appear in the
component tree (pre-order tree traversal, i.e. first parent, then
children). This results in consistent ordering and is generally the
order you want for nested floating components to behave in a useful way.

This has been implemented as a new, completely separate API instead of
an ElementaVersion primarily to easy migration (the new API can be used
even with Windows still on older ElementaVersions; both APIs can be used
at the same time) but also because there isn't anything reasonable the
old-API methods in `Window` could do in the new version, they really
should have been internal to begin with.
Intended to be used in almost all places where `animationFrame` was used
before (only major exception being animated constraints, which will
receive a different replacement).

Unlike `animationFrame`, which runs at a fixed rate of (by default) 244
times per second, the [UpdateFunc] API is variable rate, meaning it'll
be called exactly once per frame with the time that passed since the
last frame.
This allows it to match the true framerate exactly, animations won't
slow down under high load, and it won't waste tons of CPU time on
traversing the entire tree potentially mutliple times each frame.

The UpdateFunc API notably also allows modifying the component hierarchy
and accessing layout information directly from within a UpdateFunc call,
both of which are quite tricky to do correctly from `animationFrame`.
Previously these would both just traverse the entire tree and evaluate
the constraints of all components.
In Essential, only components which can be dragged care about drag
events, so most components don't, and since we primarily use the
`hoveredState` from unstable Elementa, virtually no components need the
mouseEnter/Leave listeners (which is what mouseMove is for).

This commit thusly optimizes the two methods to only traverse the narrow
subtree which has components that might be interested.
For simplicity, this is a best-effort optimization (e.g. it may still
visit components which have had such listeners at some point but no
longer do now); it should however be completely correct in that it will
behave idential to how it behaved prior to this commit, just consume
less CPU where easily possible.

Only exception are the `lastDraggedMouseX/Y` properties which are
impossible to accurately emulate without traversing every component.
They should really have been private and only in Window to begin with...
This commit compromises by accepting that their behaivor may be
different now if set manually or if dragMouse is called manually, but
still preserves the rough meaning if it's merely read from in e.g.
`mouseRelease`. The exact behavior of these properties was sufficiently
unexpected that hopefully no one will have tried to rely on their exact
behavior to begin with.

Note that the Flags class and tracking introduced in this commit also
support `Effect`s, despite neither of the two methods being available in
`Effect`s. This is because we'll also use the same mechanism with
`animationFrame` in the future.
See the kdocs on `ElementaVersion.V8` for details and motivation.

Aside from the changes behind the ElementaVersion flag, this commit also
changes the behavior of constraints evaluated on components which do not
have a window (because we therefore cannot determine the
ElementaVersion) to never cache its value.
This is necessary because if we were to cache its value in that
situation, we wouldn't be able to get it registered in the Window's
`cachedConstraints` list, and so it'd never be invalidated again on V8+.
The chance of someone relying on the constraint caching behaivor in such
a specific scenario are sufficiently tiny that it seems safe to make
this change.
Copy link
Contributor

@RedEpicness RedEpicness left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also not that familiar with the system, but looks good

Base automatically changed from feature/optimize-mouse-move-drag-tree-traversal to master March 4, 2025 06:56
@Johni0702 Johni0702 merged commit 064af7e into master Mar 4, 2025
1 check passed
@Johni0702 Johni0702 deleted the feature/deprecate-animationFrame branch March 4, 2025 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants