Files
pebble/src/fw/applib/legacy2/ui/animation_legacy2.h
Josh Soref e63c8c0b83 spelling: initializes
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2025-01-29 00:03:24 -05:00

287 lines
14 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "util/list.h"
#include "drivers/rtc.h"
#include "applib/ui/animation.h"
//! @file animation.h
//! @addtogroup UI
//! @{
//! @addtogroup AnimationLegacy2
//! \brief Abstract framework to create arbitrary animations
//!
//! The AnimationLegacy2 framework provides your Pebble app with an base layer to create arbitrary
//! animations. The simplest way to work with animations is to use the layer frame
//! \ref PropertyAnimationLegacy2, which enables you to move a Layer around on the screen.
//! Using animation_legacy2_set_implementation(), you can implement a custom animation.
//!
//! @{
///////////////////
// Base AnimationLegacy2
//
struct AnimationLegacy2;
struct AnimationLegacy2Implementation;
struct AnimationLegacy2Handlers;
//! Creates a new AnimationLegacy2 on the heap and initializes it with the default values.
//!
//! * Duration: 250ms,
//! * Curve: \ref AnimationCurveEaseInOut (ease-in-out),
//! * Delay: 0ms,
//! * Handlers: `{NULL, NULL}` (none),
//! * Context: `NULL` (none),
//! * Implementation: `NULL` (no implementation),
//! * Scheduled: no
//! @return A pointer to the animation. `NULL` if the animation could not
//! be created
struct AnimationLegacy2 *animation_legacy2_create(void);
//! Destroys an AnimationLegacy2 previously created by animation_legacy2_create.
void animation_legacy2_destroy(struct AnimationLegacy2 *animation);
//! @internal
//! resets animation to default values (see animation_create)
void animation_legacy2_init(struct AnimationLegacy2 *animation);
//! Sets the time in milliseconds that an animation takes from start to finish.
//! @param animation The animation for which to set the duration.
//! @param duration_ms The duration in milliseconds of the animation. This excludes
//! any optional delay as set using \ref animation_legacy2_set_delay().
void animation_legacy2_set_duration(struct AnimationLegacy2 *animation, uint32_t duration_ms);
//! Sets an optional delay for the animation.
//! @param animation The animation for which to set the delay.
//! @param delay_ms The delay in milliseconds that the animation system should
//! wait from the moment the animation is scheduled to starting the animation.
void animation_legacy2_set_delay(struct AnimationLegacy2 *animation, uint32_t delay_ms);
//! Sets the animation curve for the animation.
//! @param animation The animation for which to set the curve.
//! @param curve The type of curve.
//! @see AnimationCurve
void animation_legacy2_set_curve(struct AnimationLegacy2 *animation, AnimationCurve curve);
//! Sets a custom animation curve function.
//! @param animation The animation for which to set the curve.
//! @param curve_function The custom animation curve function.
//! @see AnimationCurveFunction
void animation_legacy2_set_custom_curve(struct AnimationLegacy2 *animation,
AnimationCurveFunction curve_function);
//! Gets the custom animation curve function.
//! @param animation The animation for which to get the curve.
//! @return The custom animation curve function for the given animation. NULL if not set.
//! @see AnimationCurveFunction
AnimationCurveFunction animation_legacy2_get_custom_curve(struct AnimationLegacy2 *animation);
//! The function pointer type of the handler that will be called when an animation is started,
//! just before updating the first frame of the animation.
//! @param animation The animation that was started.
//! @param context The pointer to custom, application specific data, as set using
//! \ref animation_legacy2_set_handlers()
//! @note This is called after any optional delay as set by \ref animation_legacy2_set_delay()
//! has expired.
//! @see animation_legacy2_set_handlers
typedef void (*AnimationLegacy2StartedHandler)(struct AnimationLegacy2 *animation, void *context);
//! The function pointer type of the handler that will be called when the animation is stopped.
//! @param animation The animation that was stopped.
//! @param finished True if the animation was stopped because it was finished normally,
//! or False if the animation was stopped prematurely, because it was unscheduled before finishing.
//! @param context The pointer to custom, application specific data, as set using
//! \ref animation_legacy2_set_handlers()
//! @see animation_legacy2_set_handlers
typedef void (*AnimationLegacy2StoppedHandler)(struct AnimationLegacy2 *animation, bool finished,
void *context);
//! The handlers that will get called when an animation starts and stops.
//! See documentation with the function pointer types for more information.
//! @see animation_legacy2_set_handlers
typedef struct AnimationLegacy2Handlers {
//! The handler that will be called when an animation is started.
AnimationLegacy2StartedHandler started;
//! The handler that will be called when an animation is stopped.
AnimationLegacy2StoppedHandler stopped;
} AnimationLegacy2Handlers;
//! Sets the callbacks for the animation.
//! Often an application needs to run code at the start or at the end of an animation.
//! Using this function is possible to register callback functions with an animation,
//! that will get called at the start and end of the animation.
//! @param animation The animation for which to set up the callbacks.
//! @param callbacks The callbacks.
//! @param context A pointer to application specific data, that will be passed as an argument by
//! the animation subsystem when a callback is called.
void animation_legacy2_set_handlers(struct AnimationLegacy2 *animation,
AnimationLegacy2Handlers callbacks, void *context);
//! Gets the application-specific callback context of the animation.
//! This `void` pointer is passed as an argument when the animation system calls AnimationHandlers
//! callbacks. The context pointer can be set to point to any application specific data using
//! \ref animation_legacy2_set_handlers().
//! @param animation The animation.
//! @see animation_legacy2_set_handlers
void *animation_legacy2_get_context(struct AnimationLegacy2 *animation);
//! Schedules the animation. Call this once after configuring an animation to get it to
//! start running.
//!
//! If the animation's implementation has a `.setup` callback it will get called before
//! this function returns.
//!
//! @note If the animation was already scheduled,
//! it will first unschedule it and then re-schedule it again.
//! Note that in that case, the animation's `.stopped` handler, the implementation's
//! `.teardown` and `.setup` will get called, due to the unscheduling and scheduling.
//! @param animation The animation to schedule.
//! @see \ref animation_legacy2_unschedule()
void animation_legacy2_schedule(struct AnimationLegacy2 *animation);
//! Unschedules the animation, which in effect stops the animation.
//! @param animation The animation to unschedule.
//! @note If the animation was not yet finished, unscheduling it will
//! cause its `.stopped` handler to get called, with the "finished" argument set to false.
//! @see \ref animation_legacy2_schedule()
void animation_legacy2_unschedule(struct AnimationLegacy2 *animation);
//! Unschedules all animations of the application.
//! @see animation_legacy2_unschedule
void animation_legacy2_unschedule_all(void);
//! @return True if the animation was scheduled, or false if it was not.
//! @note An animation will be scheduled when it is running and not finished yet.
//! An animation that has finished is automatically unscheduled.
//! @param animation The animation for which to get its scheduled state.
//! @see animation_legacy2_schedule
//! @see animation_legacy2_unschedule
bool animation_legacy2_is_scheduled(struct AnimationLegacy2 *animation);
//! The data structure of an animation.
typedef struct AnimationLegacy2 {
ListNode list_node;
const struct AnimationLegacy2Implementation *implementation;
AnimationLegacy2Handlers handlers;
void *context;
//! Absolute time when the animation got scheduled, in ms since system start.
uint32_t abs_start_time_ms;
uint32_t delay_ms;
uint32_t duration_ms;
AnimationCurve curve:3;
bool is_completed:1;
//! Pointer to a custom curve. Unfortunately, due to backward-compatibility
//! constraints, it must fit into 28 bits.
//! It is only valid when curve == AnimationCurveCustomFunction.
//! The mapping from 28-bit field to pointer is unpublished. Call
//! animation_legacy2_set_custom_curve() to ensure your app continues to run
//! after future Pebble updates.
uintptr_t custom_curve_function:28;
} AnimationLegacy2;
///////////////////////////////////////
// Implementing custom animation types
//! Pointer to function that (optionally) prepares the animation for running.
//! This callback is called when the animation is added to the scheduler.
//! @param animation The animation that needs to be set up.
//! @see animation_legacy2_schedule
//! @see AnimationTeardownImplementation
typedef void (*AnimationLegacy2SetupImplementation)(struct AnimationLegacy2 *animation);
//! Pointer to function that updates the animation according to the given normalized distance.
//! This callback will be called repeatedly by the animation scheduler whenever the animation needs
//! to be updated.
//! @param animation The animation that needs to update; gets passed in by the animation framework.
//! @param distance_normalized The current normalized distance; gets passed in by the animation
//! framework for each animation frame.
//! This is a value between \ref ANIMATION_NORMALIZED_MIN and \ref ANIMATION_NORMALIZED_MAX.
//! At the start of the animation, the value will be \ref ANIMATION_NORMALIZED_MIN.
//! At the end of the animation, the value will be \ref ANIMATION_NORMALIZED_MAX.
//! For each frame during the animation, the value will be the distance along the
//! animation path, mapped between \ref ANIMATION_NORMALIZED_MIN and
//! \ref ANIMATION_NORMALIZED_MAX based on the animation duration and the
//! \ref AnimationCurve set.
//! For example, say an animation was scheduled at t = 1.0s, has a delay of 1.0s,
//! a duration of 2.0s and a curve of AnimationCurveLinear.
//! Then the .update callback will get called on t = 2.0s with
//! distance_normalized = \ref ANIMATION_NORMALIZED_MIN. For each frame
//! thereafter until t = 4.0s, the update callback will get called where
//! distance_normalized is
//! (\ref ANIMATION_NORMALIZED_MIN + (((\ref ANIMATION_NORMALIZED_MAX -
//! \ref ANIMATION_NORMALIZED_MIN) * t) / duration)).
//! Other animation curves will result in a non-linear relation between
//! distance_normalized and time.
//! @internal
//! @see animation_legacy2_timing.h
typedef void (*AnimationLegacy2UpdateImplementation)(struct AnimationLegacy2 *animation,
const uint32_t distance_normalized);
//! Pointer to function that (optionally) cleans up the animation.
//! This callback is called when the animation is removed from the scheduler.
//! In case the `.setup` implementation
//! allocated any memory, this is a good place to release that memory again.
//! @param animation The animation that needs to be teared down.
//! @see animation_legacy2_unschedule
//! @see AnimationSetupImplementation
typedef void (*AnimationLegacy2TeardownImplementation)(struct AnimationLegacy2 *animation);
//! The 3 callbacks that implement a custom animation.
//! Only the `.update` callback is mandatory, `.setup` and `.teardown` are optional.
//! See the documentation with the function pointer typedefs for more information.
//!
//! @note The `.setup` callback is called immediately after scheduling the animation,
//! regardless if there is a delay set for that animation using \ref animation_legacy2_set_delay().
//!
//! The diagram below illustrates the order in which callbacks can be expected to get called
//! over the life cycle of an animation. It also illustrates where the implementation of
//! different animation callbacks are intended to be “living”.
//! ![](animations.png)
//!
//! @see AnimationLegacy2SetupImplementation
//! @see AnimationLegacy2UpdateImplementation
//! @see AnimationLegacy2TeardownImplementation
typedef struct AnimationLegacy2Implementation {
//! Called by the animation system when an animation is scheduled, to prepare it for running.
//! This callback is optional and can be left `NULL` when not needed.
AnimationLegacy2SetupImplementation setup;
//! Called by the animation system when the animation needs to calculate the next animation frame.
//! This callback is mandatory and should not be left `NULL`.
AnimationLegacy2UpdateImplementation update;
//! Called by the animation system when an animation is unscheduled, to clean up after it has run.
//! This callback is optional and can be left `NULL` when not needed.
AnimationLegacy2TeardownImplementation teardown;
} AnimationLegacy2Implementation;
//! Sets the implementation of the custom animation.
//! When implementing custom animations, use this function to specify what functions need to be called to
//! for the setup, frame update and teardown of the animation.
//! @param animation The animation for which to set the implementation.
//! @param implementation The structure with function pointers to the implementation of the setup, update and teardown functions.
//! @see AnimationImplementation
void animation_legacy2_set_implementation(struct AnimationLegacy2 *animation,
const AnimationLegacy2Implementation *implementation);
//! @} // group AnimationLegacy2
//! @} // group UI