-
-
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
base: master
Are you sure you want to change the base?
Conversation
c373262
to
0c15d51
Compare
180d37e
to
4e69ed5
Compare
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`
Hey there! Thanks for taking a shot at this. For anyone that wants to help taking widget animations to the finish line—and specially now that #2757 is landing—there are a couple of things we must do:
|
I would be interested in helping with widget animations.
@hecrj How would you like the user to customize the internal animation (i.e. easing and duration)? I imagine you already have something in mind. |
@Brady-Simon I think the Widget animations should be implemented for those internal state changes that cannot be easily animated from application code (e.g. hover transitions, toggle transitions, focus transitions, etc.). I would just hardcode some sane defaults for duration and easings for now. We can think about customization later. |
Thanks @hecrj for tackling this! I'll have a look at it and try to reimplement my animations on top of this in separate PR's. I'll try to implement the toggle widget first to see if the implementation design aligns with your vision, then I shall start working on the other ones. |
@lazytanuki I've opened an initial PR for animating the radio widget. Do you have any other widgets beside |
Hi ! I still need to have a closer look at the new API but yeah ideally I'd like to rebase my implementations (mainly buttons, scrollables, toggles) as some had caveats that can be a hassle to tackle. I shall get into this tonight |
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!