Module ui

Source
Expand description

egui UI. Dockable layout (ui/layout.rs) of panes: Library, Preview, Inspector, Effects, Transitions, Subtitles, Timeline, Curves, Planner, Auto-cut, Tracking — DaVinci-like by default, bare Windows-forms styling. Windows (Settings, Retime, Export) never block the editor.

Modules§

app
The application: owns the project, undo stack, settings, player, dockable layout and wires the panels together. Non-blocking windows (Settings, Retime, Export, Save Template, Save Profile, export/convert progress) are plain egui::Windows — the editor stays usable while they are open. Also executes MCP tool calls against the live project (one undo step per mutating call).
autocut_ui
Auto-cut pane (non-blocking; the timeline stays usable while it is open). Works on the selected audio clips (a selected video clip uses its linked audio). Controls: threshold (dBFS slider -80..0), min silence, min speech, padding (DragValues), “Keep: loud parts / quiet parts” toggle, “Ripple (close gaps)” checkbox. It shows the detected segments live (count + total kept seconds) and publishes them to overlay (timeline time ranges to KEEP, per selected clip) so the timeline can shade them; buttons: “Split only” (cuts at the boundaries, removes nothing), “Apply” (Project::auto_cut with the cuts and the quiet ranges; linked video follows), “Clear”. Peaks come from WaveformCache (None while computing → “analysing…”); detection uses engine::autocut. Undo once per Apply/Split. Returns what changed.
capture_ui
Screen recording + voiceover windows (both non-modal, both keep the editor usable).
curves
Curve (graph) editor for the FIRST selected clip: x = clip-local time over [0, duration], y = value. Left: a list of the clip’s keyframeable properties (Clip::props_mut names + “Volume”/“Pan”/“Speed” + “: ” for effect params) with a colour swatch and a checkbox to show/hide each curve (auto-scaled per property; the selected property’s scale drives the y axis labels). Right: the graph — curves drawn with the eased segments (sample Animated::at every ~2 px), keys as diamonds (accent when selected), playhead line (click on the ruler strip seeks → seeked), constant (unkeyed) properties shown as a flat dashed line. Interaction: drag a key horizontally/vertically (time clamped to the clip, vertical changes the value; undo once at drag start) — the whole selection moves with it, click a key to select it, Ctrl+click adds/removes one, dragging empty graph space rubber-bands a group (like the timeline’s clip band), Delete removes the selection and Ctrl+C / Ctrl+V copy it and paste it at the playhead keeping the relative times, double-click on empty graph area adds a key for the active property at that (t, v), right-click a key → easing menu (Ease::ALL) + Delete; Ctrl+Scroll zooms the time axis, Shift+Scroll pans, plain Scroll zooms the value axis around the pointer and “Fit” frames every key. Bezier velocity handles: a Bezier segment (or any segment whose left key is selected) shows its two handles; dragging one converts the segment to Ease::Bezier.
effects_ui
Effects panel. Top: the CATALOGUE as a thumbnail grid — one ~96x54 card per EffectKind showing the effect applied to a stock image with its name underneath, grouped by EffectKind::category() under collapsible headers, with a search box. Thumbnails arrive through set_thumbnail(kind, id, size), which the app calls after rendering them on the GPU; without a GL context a card still shows its name on a neutral tile (never blank) — an effect with EffectKind::applies_to_audio() instead gets a solid green tile with a music-note glyph, since it has no picture to render. The catalogue is filtered to what the first selected clip can use (audio clip -> audio effects only, and vice versa); with nothing selected it shows everything. Clicking a card adds the effect to every eligible selected clip, right-clicking opens its quick actions (selected clips / every clip on the track), and only a deliberate press-and-move makes it a DragPayload::Effect drag source (ui::drag_source). Below: the FIRST selected clip’s effect stack, in order: for each effect a header row (enabled checkbox, name, mask button, “Edit shader…” for a custom shader, copy/paste params, painted reorder and remove buttons) and its parameters from effect.specs(): a “From … for …” row giving the effect a window inside the clip (0 length = to the end of it, so an effect covers the whole clip until the user says otherwise), then label + DragValue (range from ParamSpec, speed ≈ (max-min)/200) — or a CHECKBOX when EffectKind::is_bool_param — + a diamond keyframe toggle at clip-local playhead time (Animated::toggle_key / set_at, highlighted when a key exists) + a button to clear them. Tint shows a colour button bound to R/G/B as well. An effect with a mask gets the inspector’s mask grid inline (shape / position / radius / feather / invert …) plus a delete button. A clip that renders from a REAL node graph (Clip::uses_graph) greys the stack out — the graph is what the renderer evaluates, so stack edits would be invisible — and offers “Unlink” to get back to the list. Every change → undo once per gesture (same edit_start rule as the inspector).
export_ui
Export window (non-blocking egui::Window “Export”): resolution (Project / 720p / 1080p / 1440p / 4K / Custom W×H, keeping the project aspect unless unlocked), scaler for up/downscaling (Nearest, Bilinear, Bicubic, Lanczos, Area, Spline → ffmpeg flags), encoder (auto + detected), quality CRF, preset, an “audio only” hint by extension, and the Fast Lossless Cut option when export::lossless_segments applies (with the keyframe-accuracy note). “Export…” opens the save dialog and returns the options; the window stays usable while an export runs (progress + cancel are shown by the app). Settings remember the last scaler/resolution. Returns Some(options) when the user confirmed an export this frame.
frame_ui
“Export Frame” window: save the frame at the playhead as an image. Options: resolution (Project / 2x / 4x / Custom W x H), upscaling mode (Scaler for the render plus the ffmpeg flag for the final resize), format (PNG / JPG / WebP with a quality slider for the lossy ones), and “Render with effects” vs “Source frame only” (the decoded frame of the top-most clip under the playhead, no compositing). Non-modal; returns the chosen options when the user confirms.
import_ui
Import report window: after engine::import::import_file, show what came through and what did not — a summary line (clips / tracks / missing media), then a scrollable table of Issues grouped by level (Ok / Warning / Skipped) with the subject and detail. Buttons: “Use this project” (replaces the current one, with the usual unsaved-changes prompt), “Copy report” (markdown) and Close. Non-modal.
inspector
Inspector panel. Nothing selected → Project panel (name, width, height, fps, duration, Save / Export / Export Frame buttons, export settings summary). One clip selected → clip name, enabled, colour label, timing (start / duration / source in), retime readout (Ctrl+R), and:
layout
Dockable editor layout (egui_tiles): panes can be rearranged by dragging their tabs, split, tabbed, hidden/shown, popped out into their own OS windows (egui immediate viewports) and saved/loaded as profiles (JSON — also written to / read from .sedit-layout files so profiles can be shared).
library
Left panel: the project browser — Premiere’s project panel, in two sub-tabs.
markers_ui
Markers pane: every marker in timeline order (project markers and clip markers together, via Project::markers_in_timeline). Rows: colour label dot (menu), time (editable DragValue, seconds), duration for ranges, name, note (multiline when the row is selected), “Go” (seek) and X (delete). Toolbar: “Add at playhead” (M), “Add on selected clip”, filter by label, and “Copy as list” (markdown, handy for the AI tools). Undo once per gesture; returns what changed.
mixer_ui
Mixer pane: the routing list (which track feeds which bus) on top, one channel strip per bus below (Main last). Everything in a strip scrolls vertically, so a long filter chain stays reachable.
nodes
Node editor: the selected clip’s effect chain as a graph you can wire up.
paste_ui
“Paste Attributes” window (Ctrl+Alt+V): a checkbox per AttrSet field, All / None buttons, a line saying what is on the clipboard (“from ‘clip.mp4’”) and how many clips will change. Non-modal, like every other window. Returns Some(set) when the user confirms; the app then calls Project::paste_attributes (one undo step).
planner
Planner pane: tabs “Plan” and “Notes”. Plan = a nested to-do tree (Project.plan): each row = checkbox (done), editable title, colour label dot (click → LABEL_COLORS menu), a collapse triangle, “+” add sub-task, delete, reorder among siblings, indent/outdent; a selected item shows its notes (multiline) and its moodboard: the asset ids in assets as rows (name, kind tag, thumbnail via ThumbCache if available, per-asset note in asset_notes, “Add to timeline”, delete); assets are added by dropping library items (DragPayload::Asset) onto the item or onto the moodboard area. Progress bar “done/total” at the top; “Add task” at the top level; “Clear completed”. Notes tab = Project.notes as a large multiline TextEdit (“describe your process, ideas, style while you edit — the style summary / AI tools read this”). Undo once per gesture. Returns what changed.
presets_ui
Presets pane: everything reusable that lives on the machine instead of in the project — saved effect chains, node graphs, adjustment layers and clip templates. All of it is in settings.json, so it survives a new project. Clicking a row applies it to the selection (templates place at the playhead); its context menu renames and deletes. “Save from selection” captures the selected clip’s node graph or effect stack, and falls back to a clip template for adjustment layers and multi-clip selections.
preview
Preview panel: the rendered frame (letterboxed, black bars), a selection outline for the selected visual clip (drag to move = edits clip.x / clip.y at the playhead time via Animated::set_at, calling undo once at drag start), and the transport bar, centred under the video: go-start, prev cut, step back, play/pause, stop, step forward, next cut, go-end (all painted glyphs, NLE order) plus timecode / duration, In/Out buttons and the in/out times, a preview-quality selector (100 / 75 / 50 / 25 %) and a Movie mode toggle. In fullscreen mode only the video is drawn (no transport, no overlay): Esc / F11 leave it (app).
retime
Retime window (Ctrl+R): speed / reverse / freeze for the selected clips (linked clips follow). egui::Window “Speed / Retime”: speed as a percent DragValue (1..10000 %, 100 = normal) + preset buttons (25 % 50 % 100 % 200 % 400 %), “Reverse” checkbox, “Freeze frame at playhead” button (Project::freeze_at(playhead, selection)) and “Unfreeze” (clear freeze), “Apply” → Project::set_speed (shows a note when the new length collides with a neighbour and nothing changed). Shows the resulting duration live. Undo once per applied change. Returns true when the project changed.
settings_ui
Settings window (egui::Window, closable). Tabs:
shader_ui
“Shader Editor” window for EffectKind::Shader: the GLSL body in a monospace editor, an Apply button, and the driver’s compile log verbatim (selectable, so it can be pasted somewhere) when the source was rejected. Non-modal — the timeline stays usable while it is open. The window only edits text: the app writes the source back onto the effect, pushes undo and asks GpuRenderer::check_shader for the log, then hands it here through error.
subtitles_ui
Subtitles panel. Toolbar: “Add at playhead” (cue [playhead, playhead+2 s) with the text “Subtitle”, selected + text field focused), “Import…” (rfd: srt/vtt → engine::subtitles::parse → replace or append after a yes/no), “Export SRT…” / “Export VTT…” (engine::subtitles::to_srt/to_vtt), “Burn in” checkbox (project.show_subtitles), and a “Style” collapsing section (font combo from fonts, size, colour, outline width/colour, background box colour, margin from bottom = project.subtitle_margin). Below: the cue list (egui::Grid / ScrollArea): start and end as editable timecode-ish DragValues in seconds (3 decimals, end ≥ start + 0.1, keep the list sorted via Project::sort_cues), a multiline text field, a play button (seek to the cue and play → seeked + play), a select checkbox and a delete one; the cue containing the playhead is highlighted; a “Split at playhead” button on the highlighted cue. A second toolbar row: “To text clips” (Project::cues_to_text_clips — editable Text clips on a “Subtitles” track), “Delete selected”, “Delete in range” (the In/Out range) and “Clear all”. “Open folder” → open_folder: the app writes the .srt sidecar and opens the folder. Undo once per gesture (same edit_start rule as the inspector); returns what changed.
timeline
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).
tools
Tool bar: a thin, movable strip that sits between the viewport and the timeline (its own dockable pane, so it can also be popped out). One row of icon buttons: Select (V) · Text (T) · Rectangle · Ellipse · Triangle · Polygon · Star · Line · Arrow · Draw (D) · Mask (rect/ellipse/polygon/path) · Zoom plus a magnet button that lights up while snapping is on (S, or Settings.snap’s own N shortcut), then, for shape tools, fill and stroke colour buttons and a stroke-width DragValue; for Draw, a play/record button, the brush colour/width, the playback speed (0.5x / 1x / 2x) and a page toggle.
tracking_ui
Tracking pane (non-blocking): follow a point or a rectangular area through a clip and keep the result as a reusable project path.
transitions_ui
Transitions panel. Catalogue: one CARD per TransitionKind (same size and frame as an effect card), previewing the transition half-way over the stock picture the effect thumbnails are rendered from — the app hands it over with set_stock, and without it a card falls back to a neutral named tile. A card selects the kind, right-clicking it applies the transition straight away (start / end of the selection, or every cut on its track), and a press-and-move drags DragPayload::Transition. Next to the grid the default duration DragValue (0.1..5 s), a colour button for FadeToColor and a direction selector for Push/Wipe. “Add at start” / “Add at end” apply it to EVERY selected clip through add_transitions, which is also what the menu, the hotkeys and MCP call — it records the choice in TransitionsState, so Ctrl+T (Action::AddLastTransition) repeats whatever was applied last, whichever path applied it. A clip with no neighbour on that side gets an EDGE transition (blend from/to nothing) instead of a cut transition, so lone clips can fade in/out too. Below: the transitions touching the first selected clip (Project::transitions_of): kind combo, position combo (Start / End / Last / Next — re-anchors the transition relative to the clip), duration, colour/direction/ease editors, remove. Returns true when the project changed (call undo once per gesture first).

Structs§

Gesture 🔒
Accumulates widget responses over one frame: start → push undo once, changed → write back. Shared by every panel so the gesture rule lives in one place.

Enums§

DragPayload
Drag-and-drop payload from the library / recent / planner panels to the timeline (egui dnd API).

Constants§

DRAG_SLOP 🔒
How far the pointer must travel while held before a click turns into a drag.
ENCODER_PRESETS
x264-style speed presets offered by the settings and export windows.

Functions§

combo
ComboBox over (value, label) pairs writing into a String setting. Returns true if the value changed.
drag_intent 🔒
“The user really means to drag this”: the primary button is down and the pointer has moved past DRAG_SLOP. egui also promotes a stationary long press to a drag (is_decidedly_dragging), and its Sense::drag widgets start dragging on the press of ANY button — which is how a right-click used to pluck a card out of a panel instead of opening its menu.
drag_source 🔒
An item that is clickable and right-clickable first and a drag-and-drop source second: the payload is only handed to egui once drag_intent holds, and the body is lifted under the cursor from that moment (the one thing Ui::dnd_drag_source is good for). Use this instead of dnd_drag_source, which senses drag only — grab cursor on hover, and a drag on any press.
duration_text
Short duration text “1:23.4”.
edit_start 🔒
True on the first frame of an edit gesture (drag start, or a non-drag change such as typing/clicking).
encoder_options
Encoder names worth offering: the h264 / hevc / vp9 / av1 families (software + nvenc/qsv/amf).
key_buttons 🔒
Diamond keyframe toggle at the clip-local playhead + a “keys” clear button once it is animated.
label_color
Colour of a clip/asset/recent label index (0 or out of range = “no label” dim).
label_name
Name of a label index (“None” for 0 / out of range).
mask_grid 🔒
Mask parameter grid, shared by the Inspector (the clip mask) and the Effects panel (a per-effect mask): shape, enabled, invert, position/size/rotation, feather, expand, opacity — each keyframable.
once 🔒
Push undo at most once per frame.
seed_mask_points 🔒
A Polygon/Path mask is drawn from points; with fewer than 3 vertices the rasteriser reports “outside everywhere” and the masked clip disappears with no way back. Seed the vertices from the mask’s own rect so every shape switch leaves something visible and editable.
timecode
HH:MM:SS:FF timecode.