-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
feat: animations for default widgets #2483
Open
lazytanuki
wants to merge
9
commits into
iced-rs:master
Choose a base branch
from
lazytanuki:animations
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 tasks
lazytanuki
force-pushed
the
animations
branch
4 times, most recently
from
July 9, 2024 20:58
c373262
to
0c15d51
Compare
lazytanuki
force-pushed
the
animations
branch
6 times, most recently
from
July 12, 2024 22:50
180d37e
to
4e69ed5
Compare
ejjonny
reviewed
Jul 13, 2024
lazytanuki
force-pushed
the
animations
branch
2 times, most recently
from
July 19, 2024 10:50
a07b781
to
f35dc79
Compare
Rebased on latest master |
Before this commit, hovering a button "deviates" the color (it darkens light ones and vice-versa) and pressing it reverts back to the original color. With animations, it makes more sense to deviate the base color one time on hover, and deviate it a second time on press, so that going back from pressed to just active just goes from light/dark to dark/light instead of dark/light to light/dark then back to dark/light.
…rollable::scroll_to` not to depend on `scrollable::State::last_notified`
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hi!
This PR is the continuation / replacement of my previous work in #1855 which needed a heavy rebase as well as improvements for some edge cases.
This PR implements internal animations for some default widgets. The goal here is to make Iced applications appear smooth when hovering / clicking things, without breaking the API.
This heavily uses the frame subscription API as well as the brand new lilt crate (thanks @ejjonny !)
output.mp4
Motivation
In many other toolkits out there, such as GTK, app developers can make GUIs without needing to handle widget animations by themselves, which makes for a better coding experience and a coherent ecosystem.
Implementation
Animations are added to the widgets
State
, which uselilt::Animated<...>
values that are then interpolated in thedraw()
function to render animated frames.Animations are triggered by specific events, such as cursor movements.
The frame subscription API is used to request redraws until the animations are completed.
Widgets that have got animations are:
buttons: hover and click style transitions
I have had to make a kind of opinionated decision here. As of now, hovering a
Button
with the mouse transitions its color to a lighter/darker version for dark/light base colors, and pressing theButton
reverts that effect back to the base color. However, this isn't very well suited to animations, as it makes the transition go from base to hover (hover), hover to base (pressed), then base to hover (release mouse button), then back from hover to base when not hovering it. On quick movements, it looks a bit odd. What other toolkits out there have been doing is a bit more linear: on a dark base color, hovering lightens it, pressing lightens it more, and so that there isn't too much back and forth between different variations.Also, buttons feature an asymmetric animation. The transition from idle to hovered is quicker than the one back to idle. That way, when moving the cursor rapidly between multiple widgets, you still get the feedback of the widgets "lighting" up when the cursor flies over them, and then you get a slower, smooth transition back to their idle state. Otherwise, having long animations would prevent the hover effects from being visible on fast cursor movements, and animations fast enough for it would feel too fast for the "back to idle" transition.
text input cursor: cursor fades in and out when idle, but remains visible while typing
togglers
checkboxes
scrollables: scrolling using the mouse wheel and clicking on the scrollbar follows an eased-out trajectory, whereas scrolling by grabbing the scrollbar remains instantaneous.
To make the code simpler and the diff shorter, I've to do a bit of refactoring there. All offsets are now stored as relative offsets, but absolute offsets are still passed in arguments when necessary, only to be converted back to relative offsets (outside
draw()
).This PR is divided in separate commits for an easier reviewing.
Caveats
Due to the stateless nature of the widgets, I've encountered some edge cases where a widget would use what I call a "tainted" state in the code. For instance, in the
tour
example, the first checkbox of a page will share the same state as the first checkbox of the page that follows (first one of its kind in the state tree map). This can lead to the new checkbox already having an ongoing animation when being rendered for the first time. I've added checks to detect and fix "tainted" states, they are pretty straightforward, but I did not find a better way to handle this.What's next
If and when this PR lands, some more widgets can receive animations. However, the most important step that I intend to implement is a global animation speed multiplier, so that users can set it according to their preferences in the COSMIC desktop, for instance. It could also include some other user settings, such as animation styles for different widgets and so on.
Thanks for reading this!