Skip to main content

Timeline UI

timeline_ui.rs (~6.7k lines, the largest module) is the multi-track timeline widget. It is drawn with egui's painter and hand-written hit-testing rather than nested widgets: for a dense grid of rectangles that is far cheaper.

Contract with the app

show_timeline is called once per frame from the bottom panel. It receives the project and the history mutably, plus read-only display data, and returns what the app must handle itself.

InputPurpose
Project, HistoryEdits are applied through History::do_command, never by writing to the project directly.
TimelineStateSelection, playhead, zoom, scroll, current gesture, clipboard, export in/out. The only state the widget mutates freely.
Buffered / proxy rangesDrawn as strips under the ruler, to show what is ready to play.
Waveform cachePeaks loaded once from the on-disk cache, drawn on audio clips.
OutputHandled by the app
Media drop (drag, frame, target)Inserts media from the pool or viewer at that position.
Compound to enterPushes the current timeline onto timeline_stack; a breadcrumb leads back.
Request flags on TimelineStateSpeed, silence and paste-attributes dialogs; reveal in media pool.

From pointer to command

At most one Gesture runs at a time. During a drag only the preview moves; the project changes once, on release, through a PendingAction.

ch7-timeline-edit-flow.png

Deferring the edit to a single PendingAction keeps one code path for drags, context-menu entries and drops, and means a cancelled or no-op drag never touches the history.

Gestures

GestureStarted by
MoveDragging a clip body (Alt duplicates). Can create new tracks.
MarqueeDragging from the background: rubber-band selection.
TrimDragging a clip edge; lengthening overwrites what is underneath.
RetimeDragging the right edge with the retime bar shown (Ctrl+R): changes speed.
FadeDragging a fade handle at the top corner.
Transition / crossing lengthDragging the end of a transition marker.
Duplicate transitionAlt+drag on a transition body.
VolumeDragging the gain line of an audio clip.
SlipAny clip drag with the Slip tool: moves the media under a fixed clip.

Layout

  • Ruler: time ticks plus a marker lane (timeline_markers.rs: point and range markers, notes).
  • Two panes: video tracks above, audio tracks below, separated by a draggable divider. Each pane scrolls on its own; video tracks rest against the divider, as in other NLEs.
  • Track headers: lock, enable, mute/solo/arm buttons and add/remove track, all emitted as PendingActions.
  • Navigation: Alt+wheel zooms time, Ctrl+wheel scrolls horizontally, Shift+wheel changes track height; touchpad swipes keep kinetic momentum.

Selection rules

  • Click, Ctrl+click and Shift+click work as in a file manager. A selection is always extended to the clip's linked group, so audio and video move together.
  • A selected gap or transition replaces the clip selection: a gap is closed by ripple delete, a transition opens its own properties panel.
  • When "selection follows playhead" is on, moving the playhead selects the video clip under it.
ModuleRole
timeline_markers.rsMarker lane: draw, drag, note editor
speed_dialog.rsClip speed dialog and the Ctrl+R retime handles
silence_dialog.rsSilence removal dialog and the red preview of the cuts
paste_attributes.rsPaste attributes (Alt+V) from the clipboard to the selection
voiceover.rsRecords the microphone onto armed tracks while playing at 1x
slip_viewer.rsSplit viewer during a slip: first and last frame of the clip