osui::extensions::velocity
The velocity
module provides the VelocityExtension
and Velocity
component, enabling simple animation by automatically moving widgets with a constant velocity.
Velocity
(Component)
component!(Velocity(pub i32, pub i32));
A tuple struct component that holds two i32
values, representing the horizontal (x
) and vertical (y
) velocity of a widget. The values represent "cells per second" for movement.
Fields:
0
:i32
- Horizontal velocity (cells per second). Positive moves right, negative moves left.1
:i32
- Vertical velocity (cells per second). Positive moves down, negative moves up.
Example:
use osui::prelude::*;
rsx! {
@Velocity(10, 0); // Move 10 cells right per second
@Transform::new().x(0).y(0);
Div { "Moving Right" }
}
VelocityExtension
This extension is responsible for applying the specified Velocity
to widgets that also have a Transform
component, causing them to move across the screen.
pub struct VelocityExtension;
Associated Methods
VelocityExtension::apply_velocity(ticks: u16, velocity: i32, x: &mut u16)
An internal helper function that updates a single coordinate (x
or y
) based on the elapsed ticks
and velocity
. It ensures that movement occurs at the specified velocity
(cells per second) by checking if enough time has passed since the last movement.
VelocityExtension::apply_velocity_xy(ticks: u16, widget: &Arc<Widget>)
An internal helper that applies Velocity
to both x
and y
coordinates of a widget's Transform
component. It retrieves the Velocity
and Transform
components, calculates new positions using apply_velocity
, and then updates the Transform
component on the widget.
Extension
Trait Implementation
init(&mut self, ctx: &super::Context)
Called when the extension is initialized.
- Clones the
Context
. - Spawns a new thread.
- In this thread, it enters an infinite loop:
- Initializes a
tick
counter (0 to 1000, then resets). This acts as a granular time counter. - Iterates over all widgets managed by the
Screen
(obtained viactx.get_widgets()
). - For each widget, it calls
Self::apply_velocity_xy(tick, widget)
to update its position if it has aVelocity
andTransform
component. - The thread sleeps for 1 millisecond. This ensures very frequent checks and smooth potential movement, as
velocity
is defined in "cells per second".
- Initializes a
Why a separate thread?
Similar to InputExtension
and TickExtension
, a separate thread is used because time-based operations like thread::sleep
are blocking. This prevents the velocity calculations from blocking the main rendering loop and ensures smooth animations. The 1ms sleep provides a high refresh rate for velocity updates.
Usage
To use VelocityExtension
, you need to:
- Register it with your
Screen
. - Attach both a
Transform
and aVelocity
component to the widget you want to animate. TheTransform
should havePosition::Const
for the coordinates you want to animate.
Example:
use osui::prelude::*;
fn main() -> std::io::Result<()> {
let screen = Screen::new();
screen.extension(InputExtension); // Required for general terminal operations
screen.extension(RelativeFocusExtension::new()); // Optional, but good practice
screen.extension(VelocityExtension); // Register the VelocityExtension
rsx! {
// A Div that moves right at 10 cells/second
@Velocity(10, 0);
@Transform::new().x(0).y(0).dimensions(10, 1); // Must have Const position to be moved
@Style { background: Background::Solid(0xFF0000) };
Div { "Moving Text" }
// A Div that moves down at 5 cells/second, starting below the first
@Velocity(0, 5);
@Transform::new().x(0).y(2).dimensions(10, 1);
@Style { background: Background::Solid(0x0000FF) };
Div { "Moving Down" }
}
.draw(&screen);
screen.run()
}
VelocityExtension
provides a simple, component-based way to add continuous motion to your OSUI elements. For more complex animations, you might combine it with TickExtension
and custom logic within a widget's event
method or a more advanced animation extension.