Crate cosmic_time
source ·Expand description
An animation toolkit for Iced
This Project was build for Cosmic DE. Though this will work for any project that depends on Iced.
The goal of this project is to provide a simple API to build and show complex animations efficiently in applications built with Iced-rs/Iced.
Project Goals:
- Full compatibility with Iced and The Elm Architecture.
- Ease of use.
- No math required for any animation.
- No heap allocations in render loop.
- Provide additional animatable widgets.
- Custom widget support (create your own!).
Overview
To wire cosmic-time into Iced there are five steps to do.
- Create a
Timeline
This is the type that controls the animations.
struct Counter {
timeline: Timeline
}
// ~ SNIP
impl Application for Counter {
// ~ SNIP
fn new(_flags: ()) -> (Self, Command<Message>) {
(Self { timeline: Timeline::new()}, Command::none())
}
}
- Add at least one animation to your timeline. This can be done in your
Application’s
new()
orupdate()
, or both!
static CONTAINER: Lazy<id::Container> = Lazy::new(id::Container::unique);
let animation = chain![
CONTAINER,
container(Duration::ZERO).width(10),
container(Duration::from_secs(10)).width(100)
];
self.timeline.set_chain(animation).start();
There are some different things here!
static CONTAINER: Lazyid::Container = Lazy::new(id::Container::unique);
Cosmic Time refers to each animation with an Id. We export our own, but they are Identical to the widget Id’s Iced uses for widget operations. Each animatable widget needs an Id. And each Id can only refer to one animation.
let animation = chain![
Cosmic Time refers to animations as Chain
s because of how we build then.
Each Keyframe is linked together like a chain. The Cosmic Time API doesn’t
say “change your width from 10 to 100”. We define each state we want the
widget to have .width(10)
at Duration::ZERO
then .width(100)
at
Duration::from_secs(10)
. Where the Duration
is the time after the previous
keyframe. This is why we call the animations chains. We cannot get to the
next state without animating though all previous Keyframes.
self.timeline.set_chain(animation).start();
Then we need to add the animation to the Timeline
. We call this .set_chain
,
because there can only be one chain per Id.
If we set_chain
with a different animation with the same Id, the first one is
replaced. This a actually a feature not a bug!
As well you can set multiple animations at once:
self.timeline.set_chain(animation1).set_chain(animation2).start()
.start()
This one function call is important enough that we should look at it specifically.
Cosmic Time is atomic, given the animation state held in the Timeline
at any
given time the global animations will be the exact same. The value used to
calculate any animation’s interpolation is global. And we use .start()
to
sync them together.
Say you have two 5 seconds animations running at the same time. They should end
at the same time right? That all depends on when the widget thinks it’s animation
should start. .start()
tells all pending animations to start at the moment that
.start()
is called. This guarantees they stay in sync.
IMPORTANT! Be sure to only call .start()
once per call to update()
.
The below is incorrect!
self.timeline.set_chain(animation1).start();
self.timeline.set_chain(animation2).start();
That code will compile, but will result in the animations not being in sync.
- Add the Cosmic time Subscription
fn subscription(&self) -> Subscription<Message> {
self.timeline.as_subscription::<Event>().map(Message::Tick)
}
- Map the subscription to update the timeline’s state:
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Tick(now) => self.timeline.now(now),
}
}
If you skip this step your animations will not progress!
- Show the widget in your
view()
!
anim!(CONTIANER, &self.timeline, contents)
All done! There is a bit of wiring to get Cosmic Time working, but after that it’s only a few lines to create rather complex animations! See the Pong example to see how a full game of pong can be implemented in only a few lines!
Re-exports
Modules
- A slightly different import to clean up makeing animation Ids.
- A slightly different import to clean up makeing lazy keyframes.
- The main timeline for your animations!
- Additional Widgets that Cosmic Time uses for more advanced animations.
Macros
- The macro used to clean up animation’s view code.
- The macro used to cleanly and efficently build an animation chain. Works for ann Id’s that implement
into_chain
andinto_chain_with_children
Structs
- A
Duration
type to represent a span of time, typically used for system timeouts. - A measurement of a monotonically nondecreasing clock. Opaque and useful only with
Duration
.
Enums
- Used to set a back animation easing.
- Used to set a bounce animation easing.
- Used to set an circular animation easing.
- Used to set a cubic animation easing.
- A container type for all types of animations easings.
- Used to set an elastic animation easing.
- Used to set an exponential animation easing.
- Used to set a linear animation easing. The default for most animations.
- A container type so that the API user can specify Either Time controlled animations, or speed controlled animations.
- Used to set a quadratic animation easing.
- Used to set a quartic animation easing.
- Used to set a quintic animation easing.
- Used to set a sinusoildal animation easing.
- Speed Controlled Animation use this type. Rather than specifying the time (
Duration
) between links in the animation chain, this type auto-calculates the time for you. Very useful with lazy keyframes. Designed to have an API very similar to std::time::Duration
Traits
- A trait that all ease’s need to implement to be used.
Functions
- Create a button keyframe. Needs to be added into a chain. See
crate::chain!
macro. - Create a column keyframe. Needs to be added into a chain. See
crate::chain!
macro. - Create a container keyframe. Needs to be added into a chain. See
crate::chain!
macro. - A simple animation percentage flip calculation function.
- A simple linear interpolation calculation function. p = percent_complete in decimal form
- Create a row keyframe. Needs to be added into a chain. See
crate::chain!
macro. - Create a space keyframe. Needs to be added into a chain. See
crate::chain!
macro. - Create a style_button keyframe. Needs to be added into a chain. See
crate::chain!
macro. - Create a style_container keyframe. Needs to be added into a chain. See
crate::chain!
macro.