Skip to main content
Version: 0.1.1

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.

  1. Clones the Context.
  2. Spawns a new thread.
  3. 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 via ctx.get_widgets()).
    • For each widget, it calls Self::apply_velocity_xy(tick, widget) to update its position if it has a Velocity and Transform component.
    • The thread sleeps for 1 millisecond. This ensures very frequent checks and smooth potential movement, as velocity is defined in "cells per second".

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:

  1. Register it with your Screen.
  2. Attach both a Transform and a Velocity component to the widget you want to animate. The Transform should have Position::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.