1404 Commits

Author SHA1 Message Date
John d57a29b776 fix(ui): Save Arrangement refuses an unknown bin (#3774 follow-up) (#3900)
* fix(ui): Save Arrangement refuses an unknown bin (#3774)

The engine lays out the root bin when it does not find the one asked for, so
a Save Arrangement for a bin that does not exist (a scripted call, or a bin
deleted while the dialog was open) could overwrite a root arrangement of the
same name. The dialog now refuses a bin that does not exist when it opens and
checks it again before saving.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ui): Save Arrangement refuses a bin that is not a bin id (#3774)

A `bin` such as -1, a string or 1.5 is not an unsigned id, so it was read
as no bin and the dialog opened for the shown view. Any non-null `bin` that
is not a bin id is now refused; an omitted or null one still means the shown
view's. The test checks the arrangements list it meant to (`arrangements`),
and covers these values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 00:38:07 -05:00
Brandon Thomas ef6c7ece45 ui: media browser test re-maximizes after Shift+O opens Source (#3897)
#3749 made opening a clip in Source clear another panel's maximize, so the
test's Media Browser was left too narrow to show the Audio Info column.
Assert the new behaviour, then maximize the browser again.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:48:21 -05:00
alexanderalber 7800a0467e fix(graphics): Style buttons show and toggle the Type-tool selection (#3673)
* fix(graphics): Style buttons show and toggle the Type-tool selection

With characters selected by the Type tool, the Faux Bold, Faux Italic,
All Caps, Small Caps, Underline and Strikethrough buttons showed the
layer's value, not the selection's. A click wrote the inverse of the
layer value to the selection, so a second click could not turn a style
off again.

The buttons are now on when every selected character has the style
(its own override, else the layer's value). New
graphic_design::range_styles lists the overrides of a character range.

generated with Claude Code

* fix(graphics): Style buttons show the layer's style without a selection

Without a Type-tool selection the list of selected characters is empty,
and "every selected character has the style" was true for it. So an
unstyled layer showed Faux Bold, Faux Italic, Underline and
Strikethrough as on, and a click wrote false. The buttons now show the
layer's value when no characters are selected (found by CodeRabbit).

generated with Claude Code

* perf(project): range_styles builds only the selected range

The Style row reads the selection's styles on every redraw, once per button.
range_styles expanded every character of the text and then sliced; it now
allocates only start..end and merges the runs that overlap it, in their
order. A test compares it with the expanded text for every range, including
overlapping and out-of-range runs; the caret and past-the-end cases are
tested too.

generated with Claude Code

* test(graphics): cover Small Caps and a mixed-caps selection

The selected-characters test toggles Small Caps too, and the mixed-selection
test makes "Dr" All Caps before extending to "Drive", so both caps buttons
are off and a click makes all of it All Caps.

generated with Claude Code
2026-11-01 15:15:36 -05:00
.CooCoo af28e9acee History: each step shows the icon of the tool or command that made it (#3776)
* History: each step shows the icon of the tool or command that made it

Each undo and redo step now keeps the id of the command that made it,
through undo, redo, merged and grouped steps and the history limit.
The History panel paints that command's icon before each label: a
timeline tool's icon for the commands the tool runs, FilmCraft's own
icon for other commands that have one, and a plain square for the rest
and for edits made outside a command. Undone steps draw their icon dimmed
like their labels. The Open row has no icon. history.list is unchanged.

* History: ripple trims show the Ripple tool's icon

A ripple trim's undo step records its own id, timeline.trim.ripple,
whether it comes from a Ripple tool drag, a ripple edit point in trim
mode or a dynamic ripple trim, and the History panel shows the Ripple
tool's icon for it. Trim mode nudges, Extend Edit to Playhead and dynamic
trims record the edit point's kind (timeline.trim, timeline.roll or the
ripple id) instead of the outer trim command, so a regular trim shows the
Selection tool's icon and a roll shows the Rolling tool's icon. Trim
Previous and Next Edit to Playhead show the Selection tool's icon.

* History: icon targets on a part-scrolled row match the drawn icon

The History panel registered each row's icon target from the row rect after clipping it to the scroll area, so on a row partly scrolled out the target moved off the drawn icon, and an icon scrolled out entirely was still registered. The target is now the drawn icon's rect clipped to the scroll area, registered only while part of it shows.

* History: Apply Default Transitions to Selection shows the plain square

The trim. family gave trim.applyDefaultTransition the Rolling tool's icon, although the command adds transitions at the selected edit points and makes no rolling edit. It now shows the plain square, as the sequence transition commands do.
2026-11-01 15:15:33 -05:00
Arshiya Rahgozar ff2fa98b1f Focus the Source monitor when a clip is opened in it (#3669) (#3749)
* app: focus the Source monitor when a clip is opened in it (#3669)

Opening a clip in Source activated its tab but left focus on the Project
panel, so Space still acted on Project and did not play the clip. The
OpenSource event now also focuses Source.

Tested by opening_a_clip_in_source_focuses_it_so_space_plays_it.

Fixes #3669

* app: reopen the Source monitor before focusing it (#3669)
2026-11-01 15:15:25 -05:00
Arshiya Rahgozar 83f93b2f45 ui: say where the project was saved in the status bar (#3744)
* ui: say where the project was saved in the status bar (#3599)

File > Save, Save As and Save a Copy gave no feedback besides the Edited mark
going away. They now set the status bar to "Project saved to <path>" (or
"Copy of the project saved to <path>"); the Save As dialog path reports its
errors there too.

Tested with a headless UI test over the control channel: the status was empty
after each save before the change.

Fixes #3599

* ui: Save All also says where the project was saved (#3599)
2026-11-01 15:15:17 -05:00
infinityespi dfbd8e24fc Effect Controls: double-clicking a property's name resets it (#3735)
* Effect Controls: double-clicking a property's name resets it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VkpGcKfWyCudfSsQNiWAaG

* Effect Controls: the property-name automation ID carries the effect index and is clipped to the view

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VkpGcKfWyCudfSsQNiWAaG

* test: the name double-click is one undo step and leaves the row in place

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VkpGcKfWyCudfSsQNiWAaG

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:15:07 -05:00
John 90f388b6ba fix(ui): the Project panel's Zoom sizes List thumbnails and the Freeform canvas (#3774) (#3871)
* fix(ui): the Project panel's Zoom sizes List thumbnails and the Freeform canvas (#3774)

The footer's Zoom slider only sized Icon view's cards. In List view it now sets
the thumbnail size (the row height follows it) when Thumbnails are shown, and
is disabled when they are not, as there is nothing for it to size. In Freeform
view it scales the canvas: cards keep their stored positions and sizes, are
drawn scaled, and a drag moves a card by its distance on the unscaled canvas.
The default size draws both views as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ui): a zoomed List thumbnail keeps room for the item's name (#3774)

With large thumbnails the thumbnail covered the name and ran into the next
column. The Name column is now drawn wide enough for the thumbnail and
120 points of name; its saved width is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ui): zoomed Freeform commands use the width the cards are drawn at (#3774)

The card menu (Stack, Unstack, Clip Size), Align to Grid and Save Arrangement
sent no width, so the engine laid unplaced cards out at its 800-point default
and could save positions from different rows than the zoomed canvas shows.
They now send the same unscaled width the view lays the cards out at, and the
engine's parameter lists name the width they already read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ui): Freeform card and canvas menus act on their own bin (#3774)

A card's menu now stacks, unstacks and resizes only the selected cards of
its own bin, which its canvas width lays out; a selection that also holds
items of another bin left them laid out at this canvas's width. Save
Arrangement saves the bin of the canvas it was opened on, which can be a
floating bin window, instead of the bin the main panel shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:15:00 -05:00
John 5291456d8c fix(ui): a project file dropped on the window opens it (#3843) (#3854)
* fix(ui): a project file dropped on the window opens it (#3843)

Dropping a .fcproj on the window sent it to file.import, which does not take
project files, so nothing happened. A dropped project file now opens as
File > Open does; other files dropped with it are not imported, since one
project is open at a time.

Opening a project from the UI with unsaved changes now asks Save / Don't
Save / Cancel first, the prompt Close Project and Quit already show: for a
dropped file, File > Open, Open Recent and the Home screen's recent list.
Scripts (engine.execute) are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ui): Don't Save keeps the project when the dropped one fails to open

After Save or Don't Save, the open prompt closed the current project before
opening the chosen one, so a file that failed to load (unreadable, not a
project) left an empty project and lost the unsaved changes. Open now
replaces the project only once the chosen one has loaded; file.open leaves
the session clean, as closing it did, so the recovery journal is the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ui): Save in the open prompt saves a new project, then opens the dropped one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ui): the dropped-project test works in its own temporary directory

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:14:56 -05:00
Patrik Lermon 04476bf9cb Export: the time left counts down between batches; the status bar shows it once a second, in place (#3816)
* Export: the time left counts down between batches; the status bar shows it once a second, in place

An export finishes its frames in batches of up to 16. The estimate measured the speed to the
latest reading, so between batches the speed sagged and the time left grew, then fell when the
next batch landed: about ±13 % on a heavy 4K60 export, enough to flip between 1:04:50 and 56:11.
It now measures the speed between batch arrivals and counts down from the last one; a batch three
intervals late falls back to the speed up to now, so a stall still makes the estimate grow.

The status bar redrew its text every frame, right-aligned against the bar, in Inter's proportional
digits, so "Exporting… 46%" moved sideways with every change of the time left. The text now
changes at most once a second, its digits sit in cells of equal width, and its room only grows
while the job runs (from the start it fits 100 % and a time under an hour).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Export: no "0 s left" while the last batch is late; the status text has room for any time left from the start

The countdown between batches reached zero when the last batch took longer than the speed said,
and showed "0 s left" until it was three intervals late; it now gives way to the speed up to now as
soon as it runs out. The status bar's room was for a time under an hour, so an export's first
estimate over an hour still moved the text once; it is now for 99:59:59 from the start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Export: the queue's and the Progress panel's job text change once a second, with digits of one width

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ui-egui: tabular_label is read by screen readers as a label

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:14:46 -05:00
Arshiya Rahgozar 58f73aecf2 Timeline: the playhead glides during playback instead of jumping a frame at a time (#3806) 2026-11-01 15:14:43 -05:00
Arshiya Rahgozar 48b36b8521 Play/Stop once per Space press, not on key repeat (#3795) 2026-11-01 15:14:39 -05:00
Patrik Lermon 47370c04eb i18n(sv): translate 49 new strings (#3784)
* i18n(sv): translate 49 new strings

Brings the Swedish catalog up to date with upstream main (142fddc1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* i18n(sv): translate 55 new strings

Brings the Swedish catalog up to date with upstream main (9c6d6611).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:14:28 -05:00
Whatever Industries 5ed4952d43 Add shared custom colors and complete marker editing (#1435)
* M3: Add shared custom colors and complete marker editing

* #1435: refine native colors and range endpoint flags

Use the macOS Colors panel for custom label colors and reuse the established egui picker on other hosts. Preserve draft confirmation, exact sRGB values, native text shortcuts and project ownership. Compact the swatches and center the add control, split range glyphs across their endpoints, localize the new controls, protect newer marker edits from stale dialogs, and cover the behavior with rendered UI and hit-test regressions.

Co-authored-by: Codex <noreply@openai.com>

* #1435: preserve imported palettes and marker double-click ownership

Union saved OTIO palettes across timelines with deduplication, bounded capacity,
first-name preservation and explicit overflow warnings. Keep null authors
consistent with omitted fields, and consume marker double-clicks before the
work-area gesture so opening the editor does not alter project history.

Correct the CSV URL column and schema documentation. Add six regressions for
palette retention/capacity, author handling, and physical overlapping gestures.

Validation: full cargo xtask ci (3666 passed, 45 skipped), 42 rendered UI tests,
and strict workspace/all-target Clippy on Rust 1.99.1.

Co-authored-by: Codex <noreply@openai.com>

* #1435: retain OTIO swatch names and generator labels

Ignore orphan name entries when retaining saved palette names so input ordering
does not hide valid names after the first 64 entries. Keep names bounded by the
retained palette and preserve existing valid names.

Include generator preset labels alongside custom label colors in OTIO metadata.
Add regressions for orphan-prefixed name maps and three generator kinds with
preset/custom colors through actual export/import round trips.

Validation: both regressions failed before fixes; all 72 interchange tests and
full cargo xtask ci pass (3668 tests, 45 skipped), plus strict workspace/all-target
Clippy on Rust 1.99.1.

Co-authored-by: Codex <noreply@openai.com>

* #1435: preserve distinct OTIO generator item identity

Use exported FilmCraft item IDs for generator media identity so identical
content can retain distinct source names, labels and custom colors. Repeated
references to one source item still share a single imported media entry.

Preserve content-based fallback for missing or invalid item IDs. Cover black
video, bars and tone, and color mattes with distinct items/shared references,
plus legacy and malformed identity metadata.

Validation: distinct-generator regression failed before fix; legacy compatibility
passed. All 74 interchange tests and final full cargo xtask ci pass (3670 tests,
45 skipped); strict workspace/all-target Clippy also passes on Rust 1.99.1.

Co-authored-by: Codex <noreply@openai.com>

* #1435: align Edit Marker layout and add safe marker navigation

Give the editor a wide aligned form, larger Notes area, side action column,
and grouped palette with vertical marker types. Expand the Web Link field
with the form and keep actions accessible in small windows.

Previous/Next saves valid edits as one Undo step and stays with the original
sequence/source owner, including coincident markers. Invalid drafts stay open;
unchanged navigation and Done add no history. Keep native/shared color pickers,
Author, Notes, URL validation and immediate marker creation.

Validation: all 45 rendered sequence/marker UI tests pass, including five new
navigation/owner/validation/layout regressions. Native macOS layout, picker
Cancel and exact single-step Undo restoration verified. Full standard cargo
xtask ci passes 3675 tests (45 skipped), doctests and all remaining gates;
strict Rust 1.99.1 workspace/all-target Clippy also passes.

Co-authored-by: Codex <noreply@openai.com>

* #1435: refine Edit Marker proportions and action alignment

Narrow the dialog to 680 logical pixels and keep the core order Name,
Time/Duration, Notes, Color and marker type. Place Author after the type-specific
options as secondary metadata. Preserve our palette, custom picker and range controls.

Use consistently sized, centered rounded action buttons with a primary Done action.
Shorten Delete Marker to Delete and remove the navigation helper and unused translations.
Keep the existing navigation save/validation/Undo semantics and automation IDs.

Validation: all 45 rendered marker/sequence UI tests pass, including small-window
action accessibility. Actual macOS layout and no-op Previous/Next/Cancel verified.
Full standard cargo xtask ci passes 3675 tests (45 skipped), doctests, formatting,
Clippy, translations, layers, assets and 49 WASM crates. Strict Rust 1.99.1
workspace/all-target Clippy passes separately.

Co-authored-by: Codex <noreply@openai.com>

* #1435: tighten marker layout and validate text editing

Use a narrower aligned form with Author below Name, bounded scrolling Notes,
left-aligned colors, centered actions and an inline Web Link URL/open icon.
Remove the legacy Flash Cue choice while preserving imported marker types.

Constrain timecode typing/paste to complete numeric colon-separated fields,
validate drop-frame labels and frame bounds, and disable Done for invalid timing.
Preserve high-frame-rate timecodes and point-marker semantics when Duration is
unchecked. Route native/menu clipboard and text Undo commands to focused fields;
explicit engine commands retain project Undo and selection semantics.

Validation: standard cargo xtask ci passes 3679 tests (45 standard skips),
doctests, fmt, strict workspace/all-target Clippy, i18n, layers, 69 assets and
49 WASM crates. Also passed 48 rendered marker/sequence tests and strict Rust
1.99.1 Clippy. Actual macOS clipboard, bounded Notes, point save and exact Undo
were checked. Windows/Linux desktop interaction remains pending.

Co-authored-by: Codex <noreply@openai.com>

* M0: Wait for frame-worker recovery before asserting

Do not treat a nonempty request queue as proof of worker death in the
panic-recovery regression. Keep waiting for all injected faults and enough
post-fault completions, then drain the queue without adding more seeks.
Retain the exact fault-count, successful-recovery and empty-queue assertions
and bound the wait with a two-minute deadline.

The inherited test failed twice in independent fork CI. It did not reproduce
locally: baseline passed 20 normal and 10 delayed-report runs; the repair
passed 50 normal and 10 delayed-report runs. No product or marker UI changes.

Validation: standard cargo xtask ci passed all 4485 tests (52 standard skips),
doctests, formatting, strict workspace/all-target Clippy, i18n, layers,
69 assets and 49 WASM crates.

Assisted-by: OpenAI Codex

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <codex@openai.com>
2026-11-01 03:04:14 +01:00
aiongg 562f550221 Merge main into backlog-r1 2026-10-31 05:27:25 +00:00
aiongg dfb5fe7021 Integration: wasm32 builds: media_queue is native-only, the sequence source-audio arm gets a boxed fill and a mutable mixer 2026-10-31 05:08:42 +00:00
Dylan M. Taylor 6c2825bc95 Merge pull request #3755 from aiongg/docs-tidy
docs: tidy agent, contributor and asset docs
2026-10-31 01:06:33 -04:00
aiongg 477c983694 updates: show check results with craft-update's CheckResultDialog 2026-10-31 04:42:43 +00:00
aiongg e0298254b5 Integration: tests and dialogs meet the merged PRs (clip mismatch off in drop tests, save panel keeps caption names, Rename name optional, audio pane scroll, sequence source audio guard, workspace list, project hover label); drop the duplicate edit-marker test file 2026-10-31 04:24:16 +00:00
aiongg 239f7987de docs: fix punctuation 2026-10-31 04:17:42 +00:00
aiongg 5c18340e3f docs: tidy agent, contributor and asset docs 2026-10-31 04:17:32 +00:00
aiongg d143562a84 Integration: #2633 route stop_for_scrub through transport_running 2026-10-31 03:39:47 +00:00
aiongg 89ee11ae30 Integration: satisfy clippy (craft_ui::ComboBox in the FX choice, move_group and play_direction helpers, as_chunks in the relink test) 2026-10-31 03:39:23 +00:00
aiongg b00fd73c80 Integration: adopt egui 0.37 names in code the tracks added (Role, Id::unique, unclamped_offset) 2026-10-31 03:39:23 +00:00
aiongg d813a86484 Integration: #3389 #3391 fix the ruler menu braces and the caption padding test's style call 2026-10-31 03:39:23 +00:00
aiongg 9f7a9d6342 Merge integration track timeline 2026-10-31 03:39:23 +00:00
aiongg 199cb8df1c Merge integration track ui3 2026-10-31 03:39:22 +00:00
aiongg a9d15b9542 Merge integration track ui2 2026-10-31 03:39:22 +00:00
aiongg 5f845f41a2 Merge integration track ui1 2026-10-31 03:39:22 +00:00
aiongg 01608757f5 Merge integration track fx 2026-10-31 03:39:22 +00:00
aiongg d6b1265dc4 Merge integration track text 2026-10-31 03:38:55 +00:00
aiongg 8595147b71 Merge integration track i18n 2026-10-31 02:17:34 +00:00
aiongg bf0386bf76 Merge integration track sys 2026-10-31 02:17:26 +00:00
aiongg bf1a400b27 Merge integration track export 2026-10-31 02:17:03 +00:00
aiongg 3777d579e1 Integration: #2497 test subsequence playback in the Source monitor with and without sound 2026-10-31 02:16:32 +00:00
aiongg 7066519ccb Merge PR #2497: Enable subsequences in Source Playback 2026-10-31 02:16:08 +00:00
aiongg 0642ceee60 Merge PR #1649: scrub bars: dragging the playhead keeps the audio stream open instead of stopping it every move 2026-10-31 02:16:05 +00:00
aiongg 59ca8b9b86 Integration: #1636 use transition_top in the merged transition draw loop 2026-10-31 02:16:02 +00:00
aiongg c2ac002f8f Merge PR #3684: Render Effects In to Out renders only red segments, like the reference app (#1220) 2026-10-31 02:16:02 +00:00
aiongg e76e30ab47 Merge PR #1636: timeline: a transition on a compact track fills the track's height
# Conflicts:
#	crates/ui-egui/src/panels/timeline.rs
2026-10-31 02:16:02 +00:00
aiongg 52178b9ec7 Integration: #2666 port the monitor hunks to draw_picture and thread recent through cpu_texture_as 2026-10-31 02:16:00 +00:00
aiongg f59572ecac Integration: #3583 keep marquee_clips doc comment on marquee_clips 2026-10-31 02:15:56 +00:00
aiongg ca2bf2de25 Merge PR #3583: Timeline: the box selection stays on the clips while the view scrolls 2026-10-31 02:15:50 +00:00
aiongg 3734513c2a Merge PR #2666: #1673: the Program monitor keeps playing while a value is dragged 2026-10-31 02:15:41 +00:00
aiongg 077e8b6c54 Integration: #2438 port the lib.rs hunks to app.rs and app/frame.rs 2026-10-31 02:15:30 +00:00
aiongg 138bb1b607 Merge PR #2438: #1142: no 60 Hz polling for queued frames, no media file list every frame 2026-10-31 02:15:30 +00:00
aiongg 9d0faf7d5e Integration: #3247 keep a legacy negative speed reversed when the clip dialog reopens 2026-10-31 02:15:27 +00:00
aiongg fa7dafb3d6 Merge PR #3247: Preserve Reverse Speed when reopening the clip dialog 2026-10-31 02:15:22 +00:00
aiongg 810320933d Merge PR #2612: Clip Mismatch Warning: a first clip that doesn't match an empty sequence asks
# Conflicts:
#	crates/engine/src/commands.rs
#	crates/engine/src/settings.rs
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/i18n/zh-cn.tsv
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/panels/timeline.rs
2026-10-31 02:15:20 +00:00
aiongg 8f16aea983 Merge PR #3714: bs: Add Bosnian (bs) to the interface languages 2026-10-31 02:14:54 +00:00