Module timeline

Source
Expand description

Timeline widget (custom painted). Header column (track name, M/S buttons, height drag handle at the bottom edge), ruler (ticks, in/out markers, click/drag scrubs), track lanes (video tracks top→bottom = Vn..V1, then A1..An), clips (name, waveform for audio via WaveformCache, keyframe diamonds, disabled = dimmed, selected = accent outline), playhead (drag by ruler or line).

Interaction: click select (Ctrl toggles), drag clip body = move (linked clips follow; Project::move_clips all-or-nothing; up/down across tracks of the same kind), drag clip edges = trim (Clip::trim_start / trim_end with Project::max_clip_duration), snapping (playhead, clip edges, in/out, 0; ~8 px) when snap, right-click context menu (Split, Delete, Ripple Delete, Link/Unlink, Enable/Disable, Add Video/Audio Track, Remove Track (on headers), Mute/Solo). Ctrl+Scroll = zoom around the cursor, Shift+Scroll = horizontal pan, Alt+Scroll = height of the track under the cursor, plain scroll = vertical pan. Accepts egui dnd payloads DragPayload (Asset → Project::insert_asset_clips at the drop time/track; Path → returned in dropped_files; Effect / Transition → the clip under the pointer is outlined while dragging and reported in dropped_other, so a card lands straight on that clip). Every mutation calls c.undo(&project) with the project as it was before the gesture (once per gesture, only if it changed something) and sets edited. While playing, auto-scroll keeps the playhead visible unless the user panned away (resumes once the playhead re-enters the view or playback pauses).

Round 2: horizontal/vertical scrollbars (thumb drag + click-to-page), edge auto-scroll during drags, linked selection (click = link group, Alt+click = single, linked clips get a thin outline), audio volume line (dB mapped, draggable) + fade handles, video track V/S headers, full-width track resize handles, draggable keyframe diamonds with an easing context menu, transition bands (edge drag = duration, right-click = remove), colour labels / sequence tint, speed badges, thumbnail filmstrips (ThumbCache), auto-cut keep-range shading and Sequence open-on-double-click.

Round 3: rubber-band select on empty lane space (Shift adds; dragging any selected clip moves the whole selection as one undo step), drag past the top video / bottom audio row to drop onto a freshly created track (gutter preview, Esc cancels the gesture), keyframe diamonds in a value lane on tall clips (y = value, x = time, tooltip, one undo per gesture), project markers on the ruler and clip markers inside clips (click selects, double-click seeks, drag moves, right-click = Rename / Delete / Set label), clip colours from Project.labels, hatched Adjustment layers with an “adj” badge, and the Add Marker / Copy & Paste Attributes / Add Mask / Nest / Convert to Adjustment Layer context-menu entries.

Structs§

Drag 🔒
TimelineCtx
TimelineResponse
TimelineState

Enums§

Act 🔒
Deferred project mutation (collected while the project is borrowed for drawing).
Cap 🔒
What a header toggle paints: a picture, or a plain character.
Gesture 🔒

Constants§

DB_BOT 🔒
DB_TOP 🔒
Volume line dB range: +12 dB at the top of the clip, -60 dB at the bottom, 0 dB at 70 % height.
EDGE_W 🔒
FLAG_W 🔒
Marker flag size on the ruler / inside clips.
GUTTER_H 🔒
Insertion gutter shown when clips are dragged past the first/last row.
HANDLE_H 🔒
HBAR_H 🔒
Scrollbar strip thickness (points).
KEY_LANE_MIN 🔒
Clip height from which keyframe diamonds move into a value lane (y = value) instead of the bottom strip.
KEY_PAD 🔒
Inset of the value lane inside the clip rect (points), top and bottom.
MAX_TRACK_H 🔒
MIN_TRACK_H 🔒
RULER_H 🔒
SCROLL_MARGIN 🔒
Edge auto-scroll kicks in within this many points of the lanes edge.
SNAP_PX 🔒
SUB_LANE_H 🔒
Height of the subtitle lane pinned under the ruler (shown only when the project has cues).
TICKS 🔒
(major tick, minor tick) seconds; the first major that spans >= 80 px wins.
VBAR_W 🔒

Functions§

clip_menu 🔒
db_frac 🔒
dB → fraction of the clip height measured from the bottom. Piecewise linear: -60 dB = 0, 0 dB = 0.7, +12 dB = 1 (so unity gain sits at 70 % height and the usable attenuation range gets most of the clip).
diamond 🔒
draw_filmstrip 🔒
Filmstrip of source-time thumbnails across a video/image clip. Non-blocking: misses are queued in the ThumbCache worker and painted on a later frame.
draw_waveform 🔒
One vertical min..max line per point column over the visible part of an audio clip.
drop_on_clip 🔒
The clip under a drop at screen pos / timeline time t, with its lane rect — what an effect or a transition dragged out of its panel is aimed at (app.rs resolves the same clip from the reported time + track when the drop actually happens).
flag 🔒
Marker flag: a stem down from top with a pennant to the right.
frac_db 🔒
gain_db 🔒
has_keys 🔒
Does the clip have any keyframe at all? Cheap (no allocation), unlike Clip::key_times, so the 1000-clip case never touches the keyframe path.
hatch 🔒
Diagonal hatching (adjustment layers read as “applies to everything below”).
key_range 🔒
Value range the diamonds of prop are mapped through: the live auto-range, or the one frozen at the start of the drag so the dragged key does not push its own scale around.
label_color 🔒
label_menu 🔒
Colour submenu: the project’s own labels (name + colour), not the built-in defaults.
marker_hit 🔒
Shared marker interaction (ruler flags and clip flags): click selects, double-click seeks, drag moves, right-click = Rename / Delete / Set label.
nearest 🔒
Nearest candidate within thr of t.
paste_clips
paste_menu 🔒
Paste a copied group (relative times, the way presets::capture_template stores one) at at, with fresh clip / link / marker ids. Project::place_clips picks the first track of each kind with room (adding one when nothing is free); target then pulls the group onto the row the user last clicked, if the whole group fits there. The paste flavours, shared by every timeline context menu. The app decides whether the clipboard actually holds anything — a menu that hid itself when empty would just look broken.
prop_range 🔒
The range the rest of the UI enforces for property i (inspector sliders for the base props, ParamSpec for effect params), so a value-lane drag cannot write past what a DragValue allows. None where nothing enforces one: Position X/Y and Rotation are unbounded everywhere, and Volume is a gain behind a nonlinear dB slider. ponytail: same property order as curves.rs — move it next to prop_ref if a second caller shows up.
row_order 🔒
Display order: video tracks reversed (Vn on top, V1 just above audio), then A1..An.
row_top 🔒
Top y of track ti in display order (absolute points).
show
snap_playhead 🔒
Frame-quantise a pointer time and pull it onto the nearest snap candidate. Every tool that turns a pointer x into a time goes through here, so the razor, the marker tool, marker drags and media drops land on the same edges that moves and trims already snap to. Where the playhead lands when snapping is on: clip edges, in/out and 0, but NOT the playhead itself, which would always be the nearest candidate and pin it where it already is.
snap_target 🔒
Snap target for t: 0, playhead, in/out, edges of clips not in exclude — within thr seconds.
snap_time 🔒
tick_label 🔒
tick_step 🔒
(major, minor) tick spacing in seconds for a zoom (px/s).
toggle_button 🔒
wave_color 🔒
Wave colour of an audio clip: the plain palette green while it has no label, otherwise its own (already computed) body colour pushed to the opposite end of the brightness scale — the body is painted in that colour, so an unshifted wave would be invisible on it.