Skip to content

AnimatedVisualPlayer

Header: winui/ui/media/AnimatedVisualPlayer.hpp. Spec: winui/ui/media/AnimatedVisualPlayer.hpp.

Plays a caller-supplied AnimatedVisualSource by advancing its progress over time and drawing each frame with the source's render_frame().

With auto_play() on (the default), a newly loaded source starts looping from 0 to 1 at once. Otherwise the app calls play(), pause(), resume(), stop() or set_progress(). A play from from to to lasts duration() * (to - from), scaled by playback_rate() while it runs. A negative rate plays backwards. The source is fitted into the player's bounds as stretch() says. When the source can't be shown (its available() is false), the fallback content takes its place. The player doesn't own the source, so it must outlive the player.

A play keeps running in real time while the player is off screen, scrolled out of view or clipped away, but nothing is drawn and the window isn't kept busy for it. Back on screen, the player shows the progress the play has reached by then, with a looped play wrapped around. A play that ends off screen still completes on time.

Example:

// A source drawing a circle that grows over one second.
struct Pulse final : ui::AnimatedVisualSource
{
    ui::Size natural_size() const override { return {48.0f, 48.0f}; }
    ui::Duration duration() const override { return ui::Duration{1000.0}; }
    void render_frame(ui::Renderer& r, const ui::Rect& b, double progress) const override
    {
        const float radius = static_cast<float>(progress) * b.width / 2.0f;
        r.fill_ellipse(b.center(), radius, radius, ui::colors::Black);
    }
};
static const Pulse pulse; // outlives every player showing it

ui::Control<ui::AnimatedVisualPlayer> player;
window.set_content(ui::VerticalStack{
    .content = {
        ui::AnimatedVisualPlayer{.source = &pulse, .auto_play = false, .width = 96.0f,
                                 .height = 96.0f, .control = player,
                                 .fallback_content = ui::Text{.text = "(no animation)"}},
        ui::Button{.text = "Play once", .on_click = [&] { player->play(0.0, 1.0, false); }},
        ui::Button{.text = "Pause", .on_click = [&] { player->pause(); }},
    },
});

ui::AnimatedVisualPlayer

A player for a caller-supplied AnimatedVisualSource (render/AnimatedVisualSource.hpp). Builds a ui::AnimatedVisualPlayerControl.

source is a non-owning pointer, so the AnimatedVisualSource must outlive the built control. Changing the source, through a binding or set_source() on the control, stops the player. fallback_content shows instead when the source can't be shown.

Example:

extern const ui::AnimatedVisualSource& logo; // the app's own subclass, alive as long as the window
ui::Control<ui::AnimatedVisualPlayer> player;

window.set_content(ui::VerticalStack{.spacing = 8, .content = {
    ui::AnimatedVisualPlayer{.source           = &logo,
                             .auto_play        = false,
                             .width            = 400.0f,
                             .height           = 400.0f,
                             .control          = player,
                             .fallback_content = ui::Text{.text = "Animation unavailable"}},
    ui::HorizontalStack{.spacing = 8, .content = {
        ui::Button{.text = "Play",  .on_click = [&] { player->play(0.0, 1.0, true); }},
        ui::Button{.text = "Pause", .on_click = [&] { player->pause(); }},
        ui::Button{.text = "Stop",  .on_click = [&] { player->stop(); }},
    }},
}});

Every field, in the order a designated initializer names them:

ui::AnimatedVisualPlayer{
    .source, .auto_play, .playback_rate, .stretch, .style, .margin, .width, .height,
    .min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
    .vertical_alignment, .visible, .tool_tip, .accessibility, .on_pointer_entered,
    .on_pointer_exited, .on_got_focus, .on_lost_focus, .on_key_down, .on_wheel, .control,
    .fallback_content
}

Fields, in declaration order (designators must follow it):

Field Type Default
source ui::Binding<const ui::AnimatedVisualSource*> The animation. Not owned, so it must outlive the built control.
auto_play ui::Binding<bool> {true} Whether the whole animation loops as soon as the source loads.
playback_rate ui::Binding<double> {1.0} Playback speed. 1 is normal speed, and a negative rate plays backwards.
stretch ui::Binding<ui::Stretch> {ui::Stretch::Uniform} How the animation fills the player's box.
on_pointer_entered ui::Action The pointer moved onto the control.
on_pointer_exited ui::Action The pointer left the control.
on_got_focus ui::Action Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this.
on_lost_focus ui::Action Keyboard focus left the control and everything inside it.
on_key_down ui::Callback<ui::Handling(const ui::KeyEvent&)> A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()).
on_wheel ui::Callback<ui::Handling(const ui::PointerEvent&)> A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()).
control ui::ControlOut<ui::AnimatedVisualPlayer> Out: the handle that receives the built control.
fallback_content ui::Spec Shown instead of the animation when the source can't be shown.

Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, accessibility every spec carries (conventions).

build

std::unique_ptr<Element> build()&&

Consumes the spec and returns the built ui::AnimatedVisualPlayerControl; the caller owns it.

ui::AnimatedVisualPlayerControl

Derives from ui::Panel.

Plays a caller-supplied AnimatedVisualSource by advancing its progress over time and drawing each frame with the source's render_frame().

With auto_play() on (the default), a newly loaded source starts looping from 0 to 1 at once. Otherwise the app calls play(), pause(), resume(), stop() or set_progress(). A play from from to to lasts duration() * (to - from), scaled by playback_rate() while it runs. A negative rate plays backwards. The source is fitted into the player's bounds as stretch() says. When the source can't be shown (its available() is false), the fallback content takes its place. The player doesn't own the source, so it must outlive the player.

A play keeps running in real time while the player is off screen, scrolled out of view or clipped away, but nothing is drawn and the window isn't kept busy for it. Back on screen, the player shows the progress the play has reached by then, with a looped play wrapped around. A play that ends off screen still completes on time.

Example:

// A source drawing a circle that grows over one second.
struct Pulse final : ui::AnimatedVisualSource
{
    ui::Size natural_size() const override { return {48.0f, 48.0f}; }
    ui::Duration duration() const override { return ui::Duration{1000.0}; }
    void render_frame(ui::Renderer& r, const ui::Rect& b, double progress) const override
    {
        const float radius = static_cast<float>(progress) * b.width / 2.0f;
        r.fill_ellipse(b.center(), radius, radius, ui::colors::Black);
    }
};
static const Pulse pulse; // outlives every player showing it

ui::Control<ui::AnimatedVisualPlayer> player;
window.set_content(ui::VerticalStack{
    .content = {
        ui::AnimatedVisualPlayer{.source = &pulse, .auto_play = false, .width = 96.0f,
                                 .height = 96.0f, .control = player,
                                 .fallback_content = ui::Text{.text = "(no animation)"}},
        ui::Button{.text = "Play once", .on_click = [&] { player->play(0.0, 1.0, false); }},
        ui::Button{.text = "Pause", .on_click = [&] { player->pause(); }},
    },
});

AnimatedVisualPlayerControl

AnimatedVisualPlayerControl() = default

A player with no source: auto-play on, rate 1, Uniform stretch.

source

const AnimatedVisualSource* source() const

The source being played, or null.

set_source

void set_source(const AnimatedVisualSource* source)

Sets the source to play. The player doesn't own it, so the source must outlive the player. Replacing the source stops whatever was playing, and auto-play then starts on the new one. nullptr unloads it. Shows or hides the fallback content as the source's available() says.

is_animated_visual_loaded

bool is_animated_visual_loaded() const

A source is set, available and has a size.

set_fallback_content

Element* set_fallback_content(std::unique_ptr<Element> content)

Sets what shows instead when the source can't be shown. Takes ownership, returns a non-owning observer and replaces any earlier fallback.

fallback_content

Element* fallback_content() const

The fallback content (whether or not it is showing), or null if none was set.

is_fallen_back

bool is_fallen_back() const

Whether the fallback content is what is showing.

auto_play

bool auto_play() const

Whether a loaded source starts looping 0..1 on its own. Default true.

set_auto_play

void set_auto_play(bool auto_play)

Turns auto-play on or off. Turning it on while a source is loaded and nothing plays starts the looping play at once.

playback_rate

double playback_rate() const

How fast plays run, 1 by default. A negative rate plays backwards.

set_playback_rate

void set_playback_rate(double rate)

Sets the playback rate. A running play speeds up, slows down or reverses at once.

stretch

Stretch stretch() const

How the source's natural size fits the player's bounds. Uniform by default.

set_stretch

void set_stretch(Stretch stretch)

Sets the stretch. Updates layout and redraws.

is_playing

bool is_playing() const

Whether a play has started and not completed. A paused play counts as playing.

is_paused

bool is_paused() const

Whether the current play is paused.

progress

double progress() const

The current position in the animation, from 0 to 1.

duration

Duration duration() const

0 until a source is loaded, then the source's duration().

play

void play(double from_progress, double to_progress, bool looped)

Completes any play in progress, rewinding it, then plays from from_progress to to_progress, repeating forever when looped is true. Without a loaded source the play waits and doesn't start, and setting a source cancels it.

pause

void pause()

Pauses the current play where it is. Does nothing when nothing is playing.

resume

void resume()

Continues a paused play. Does nothing when nothing is playing.

stop

void stop()

Completes the current play and rewinds progress() to 0. Does nothing when nothing is playing.

set_progress

void set_progress(double progress)

Completes any play and jumps to progress, clamped to [0,1].

on_screen_changed

void on_screen_changed(bool on_screen) override

When the player comes back on screen, draws the progress the play reached while away.

automation_role

AutomationRole automation_role() const override

Exposed to UI Automation as an image.

measure_override

Size measure_override(Size available, const MeasureContext& context) const override

Fits the source's natural size into available as stretch() says, or measures the fallback.

arrange_override

void arrange_override(const Rect& final_rect, const ArrangeContext& context) override

Arranges the fallback content when it is showing.

render_override

void render_override(Renderer& renderer, const RenderContext& context) const override

Draws the source's frame at progress(), clipped for UniformToFill, or draws the fallback.

tick_override

void tick_override(Duration delta) override

Advances the current play by delta * playback_rate(), and completes or loops it at its ends. Off screen it draws nothing and keeps the window idle, and a play that ends there still completes on time.

Tests

  • tests/test_animated_visual_player.cpp