66f5ca1a4f
Timeline widget with:
- Header: play/pause + reset + duration drag + loop checkbox
- Ruler: 0.5s ticks, scrub via click+drag
- Tracks: horizontal rows with diamond-shaped draggable keyframes
- Playhead: vertical primary_light line + ruler triangle marker
State and types:
- Keyframe { time, value, ease }
- Track { name, vector<Keyframe> }
- TimelineState { tracks, current_time, duration, playing, loop }
Pure functions:
- track_value_at(track, t): interp between keys, ease applied via the
destination keyframe (Maya/AfterEffects convention)
- timeline_update(state, dt): advance current_time, wrap or saturate
Render with fn_tokens for visual coherence with the rest of the design
system. Keys are sorted by time on every changed frame to keep order
consistent during drag.
68 lines
2.1 KiB
C++
68 lines
2.1 KiB
C++
#pragma once
|
|
|
|
// timeline — widget tipo DAW: tracks horizontales con keyframes interpolados,
|
|
// scrub y play/pause. Sirve para animar valores escalares (uniforms shader,
|
|
// parametros UI, etc) a lo largo del tiempo.
|
|
//
|
|
// Estado puro (TimelineState) + funciones puras de interpolacion
|
|
// (track_value_at) + render impuro (timeline_widget).
|
|
//
|
|
// Uso:
|
|
// static fn::TimelineState tl;
|
|
// tl.tracks.push_back({"hue", {{0,0}, {2,1}, {4,0}}});
|
|
// tl.duration = 4.0f;
|
|
//
|
|
// fn::timeline_update(tl, dt);
|
|
// float h = fn::track_value_at(tl.tracks[0], tl.current_time);
|
|
// fn::timeline_widget("##tl", tl);
|
|
|
|
#include "core/tween_curves.h"
|
|
|
|
#include <imgui.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace fn {
|
|
|
|
struct Keyframe {
|
|
float time;
|
|
float value;
|
|
tween::Ease ease = tween::Ease::Linear;
|
|
};
|
|
|
|
struct Track {
|
|
std::string name;
|
|
std::vector<Keyframe> keys;
|
|
};
|
|
|
|
struct TimelineState {
|
|
std::vector<Track> tracks;
|
|
float current_time = 0.0f;
|
|
float duration = 5.0f;
|
|
bool playing = false;
|
|
bool loop = true;
|
|
};
|
|
|
|
// --- Pure -------------------------------------------------------------------
|
|
|
|
// Interpola el valor de `track` en el tiempo `t`. Asume keys ordenadas por
|
|
// time. Si `t` cae antes del primer keyframe devuelve el value del primero;
|
|
// si cae despues del ultimo, devuelve el value del ultimo. Entre keyframes
|
|
// usa el ease de la SEGUNDA key (la "curva entrante" hasta esa key).
|
|
float track_value_at(const Track& track, float t);
|
|
|
|
// --- Update -----------------------------------------------------------------
|
|
|
|
// Avanza current_time si playing. Si loop=true hace wrap; si no, satura en
|
|
// duration y pone playing=false al llegar.
|
|
void timeline_update(TimelineState& s, float dt);
|
|
|
|
// --- Render -----------------------------------------------------------------
|
|
|
|
// Widget completo: cabecera con play/pause + tiempo, ruler con scrub, y un
|
|
// panel por track con keyframes draggable. Devuelve true si el usuario hizo
|
|
// algun cambio (drag de keyframe, scrub, play/pause).
|
|
bool timeline_widget(const char* id, TimelineState& s, ImVec2 size = ImVec2(-1, 200));
|
|
|
|
} // namespace fn
|