Commit Graph
233 Commits
Author SHA1 Message Date
Claude 657f34d40b Layers: with several layers selected, value edits, stopwatches and viewer Scale / Rotate change them all (#355, #491)
With several layers selected, After Effects applies a property edit to the same property of
every selected layer; we changed only the layer whose row was edited (the Properties panel
showed only the first selected layer), so a stopwatch switched on one layer and later moves
of the others had nothing to keyframe (#355), and scaling or rotating a selection changed
one layer (#491).

- Engine: `prop.set`, `prop.toggleAnimation` and `prop.toggleKey` take `selected: true`:
  the change also goes to the same property (by match path, `transform/scale`,
  `effects/<effect>#n/<param>`) of every other selected, unlocked layer whose value has the
  same kind, in one undo step (a scrub keeps folding into it through its `merge` key). With
  `offset: true` (a scrub) each layer changes by the same amount from its own value; a typed
  value sets them all. Position with Separate Dimensions is handled per layer.
- The Timeline, Properties and Effect Controls panels pass `selected` (and `offset` while a
  value is dragged). The Properties panel heads "(N) Selected Objects" (zh-CN / zh-TW / ja /
  uk rows).
- Viewer: a bounding-box handle drag scales every selected layer by the same ratio about its
  own anchor point; the Rotation tool turns them all by the same angle (one undo step).

Tests: engine test (stopwatch, scrub offset, typed value, keyframe button, one undo step,
unselected layers untouched); kittests: the Properties panel with three layers selected
(header, stopwatch on all three undone in one step, a scrub moving all three by the same
amount) and a handle drag scaling two selected layers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 21:23:36 +00:00
Claude 56fd5d52b1 Dock: a panel dropped on a stacked panel becomes a tab in its frame, as in After Effects (#302)
A stack (the Default workspace's right column) held one panel per frame. Dropping a panel
onto the middle or the tab strip of a stacked panel inserted a new stacked frame below it,
and dropping on its top or bottom edge split the whole column.

A stacked frame now holds tabs (`StackEntry { panels, active, open, height }`):
- Center / tab strip drops add the panel as a tab of the anchor's frame and show it.
- Top / Bottom drops add a frame of its own above / below the anchor's frame only.
  (Left / Right still split the column: a frame can't hold a side-by-side split.)
- Clicking a frame's shown tab (or its header bar) expands / collapses it; another tab
  shows that panel. Closing a tab keeps the frame; its last tab removes it.
- Saved workspaces from before (`{"panel": …}` per frame) still load.

Tests: dock unit tests (Center / Top / Bottom on a stack, insert_tab, close, old saved
entries); a kittest dragging Effect Controls onto Properties makes a two-tab frame whose
tabs switch the shown panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 21:22:38 +00:00
Claude 8b42f970b6 Merge branch 'fix/f4': community issue fixes 2026-10-10 20:00:37 +00:00
Claude 3effa9a2ea Timeline: the view follows the CTI past its edges when scrubbing and during playback (#468)
The ruler scrub set the time under the pointer and never moved the visible span, so with
the timeline zoomed in a scrub couldn't go past the edge, and a preview ran the CTI out of
view. As in After Effects:

- zoomed in, a scrub held past either end of the ruler scrolls the timeline that way,
  faster the further past, with the CTI riding the edge (repainting while held);
- during playback, when the CTI leaves the visible span the view pages to start at it
  (not past the comp's end).

Tests: a unit test of the paging and edge speed, and a kittest that holds a scrub past the
right end (the view scrolls, the CTI stays at the edge), then past the left end, then plays
from beyond the view (it pages to the CTI). (#468's Shift+F and black-layer items need
more information and aren't part of this.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:54:17 +00:00
Claude 7b38d4d74e Dock: a click anywhere on a stacked panel's header bar expands or collapses it (#301)
In the right-hand panel stack only the tab (the name plus its padding) answered clicks, so
the rest of the header bar did nothing, a small target for short names like Audio. As in
After Effects, the rest of the strip now toggles the panel too and focuses it. A stack group
holds one panel, so the bar is unambiguous; the panel menu keeps its own click. The bar
registers the automation id `panel.header.<Panel>`.

Test: a kittest clicks near the right end of Preview's header bar (collapses), its middle
(expands) and its panel menu button (stays open).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:54:17 +00:00
Claude f440adbb5a Dock: dragging a divider past a panel's minimum no longer crashes the app (#306)
A split's first side was sized with `f32::clamp(20.min(avail), (avail - 20).max(0))`.
`f32::clamp` panics when its lower bound exceeds its upper one, which happened for any
split with 0 < avail < 40 pt. Dragging the viewer/Timeline divider up takes the area above
it down to 40 pt, so the splits nested there (the right column's vertical split and
others) got about 36 pt and the layout panicked; no guard covers egui's update, so the app
closed with no dialog.

The split size now goes through `split_first` / `clamp_ordered`, which never panic: when
the room is too small for both minimums the lower bound wins, and non-finite sizes fall
back to it. The gutter drag uses the same clamp.

Tests: a dock unit test lays out every workspace in rects too short and too narrow for its
minimums (it panicked before) and checks `split_first` on hostile sizes; a kittest drags the
divider above the Timeline 2000 pt up and 3000 pt down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:53:56 +00:00
Claude 1bea11c9f1 Roto Brush: Cmd/Ctrl-drag resizes the brush, and the tool options show its Diameter (#509)
Cause: the Roto Brush and Refine Edge diameters live in the editor state and
the roto.options command sets them, but the UI never did: the Layer panel
only painted strokes and the bottom bar only set the view mode, so the brush
size could not be changed.

Fix, as in After Effects: Cmd-drag (Ctrl-drag on Windows and Linux) in the
Layer panel resizes the active brush (Roto Brush or Refine Edge) without
painting. The circle stays at the press point, its edge follows the pointer,
and the size is shown while dragging. The tools bar shows a Diameter field
(header.roto.diameter) while a Roto Brush tool is active. Both go through
roto.options, and the next stroke uses the new radius. Diameter is in all
four interface catalogs.

Test: roto_brush_ctrl_drag_resizes_the_brush (a 20 px Cmd/Ctrl-drag makes a
40 px brush and paints nothing, the next stroke's radius is half of it, and
the Diameter field is registered).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
(cherry picked from commit b4183c28eea34ba097d7a16153b84fcf7aeea045)
2026-10-10 19:48:25 +00:00
Claude 3ba43b20c7 Effect Controls: file parameters get Choose…, Apply Color LUT asks for its LUT on apply, and text parameters get a field (#514, #473)
Cause: Apply Color LUT's only parameter, `lut`, was ParamUi::Hidden (set only
through commands), so the effect could not be used from the UI. Effect
Controls also had no widget for any ParamUi::Text parameter (only EXtractoR's
channels had one), so Cryptomatte's Selection, the OCIO effects' config file /
file / config names and Colorama's Output Cycle could not be set either.

Fix: a new ParamUi::File { filters } for paths. Effect Controls shows the
file's name (None when empty) and a Choose... button that opens the host's
file dialog with those extensions and sets the path (prop.set, so agents use
the same command). As in After Effects, applying an effect with an empty file
parameter from the UI (Effect menu, Last Effect, drops, Effects & Presets)
opens the file dialog straight away; cancelling keeps the effect without a
file. Apply Color LUT's LUT (.cube) and the OCIO Config File (.ocio) and File
(.cube/.3dl/.csp/.cc/.ccc/.cdl/.spi1d/.spi3d/.spimtx) use it. Text
parameters get a single-line field that sets the value when it loses the
focus (Esc keeps the old text). Saved projects are upgraded on open: a
Hidden or Text parameter whose spec is now a File parameter takes the File
UI and keeps its path (effects::migrate). docs/effects.md regenerated.

This covers #473's first part (the Selection field); picking mattes in the
viewer, the layer popup from the file's metadata, the GPU path and quoted
commas are separate.

Tests: effects hidden_and_text_paths_become_file_parameters (migration); ui
file_and_text_parameters_have_widgets (the LUT is asked for on apply and
inverts red to cyan, the Choose... button picks another LUT, typing into
Cryptomatte's Selection sets it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
(cherry picked from commit 403863f703999d19d3a83d9976f76bdc7577e682)
2026-10-10 19:48:25 +00:00
Claude 40e87709d5 Import: numbered stills import as stills unless the Sequence option is on; dropped folders make sequences (#431)
Cause: SequenceOptions::from_params defaulted `sequence` to true for
file.import, so any numbered still (IMG_0001.jpg) brought its whole numbered
run from its folder, and several picked or dropped stills with a common
prefix became one sequence. Dropped files never asked, and the Import
dialog's "<format> Sequence" checkbox started ticked.

Fix, matching After Effects: file.import takes picked and dropped files as
stills unless `sequence: true` (the Import dialog's Sequence checkbox, which
now starts unticked; Force Alphabetical Order implies it), while the numbered
stills inside a picked or dropped folder still import as sequences
(SequenceOptions::folders), and `sequence: false` (Alt-drag of a folder)
imports a folder's files one by one. Replace Footage, reload, proxies and
render outputs keep detecting their sequence (SequenceOptions::default and
from_params are unchanged), and mediaBrowser.import keeps bringing a numbered
still's run unless `sequence: false`. docs/footage.md and docs/agents.md
describe the new defaults.

Tests: sequence import_takes_stills_unless_asked_for_a_sequence and engine
numbered_stills_import_as_stills_by_default (one dropped still and two picked
IMG_ stills stay stills, a dropped folder makes one sequence, the checkbox
brings the run); the existing sequence tests pass `sequence: true`; ui
import_dialog_offers_the_image_sequence_option (unticked by default: a still;
ticked: the run) and a_dropped_folder_imports_as_one_sequence_with_sequence_interpretation
(two dropped frames: two stills; the folder: one sequence).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
(cherry picked from commit aa3c31db9ab3a774ee2f8ba867e1bafc1fce7aba)
2026-10-10 19:48:25 +00:00
Claude 09b3dbaad9 Merge branch 'fix/f3': community issue fixes
# Conflicts:
#	crates/ui-egui/src/widgets.rs
2026-10-10 19:48:24 +00:00
Claude 33dc3e72fa Merge branch 'fix/f2': community issue fixes 2026-10-10 19:48:18 +00:00
Claude d3e34156e5 Merge branch 'fix/f1': community issue fixes
# Conflicts:
#	crates/ui-egui/src/panels/text_panels.rs
2026-10-10 19:48:18 +00:00
Claude fbe0f7e1ce Cache bars: cached frames show at 1/3 resolution (#595)
The cache bars count the frames of `shown_series`, which rebuilds the
series from the frame key's scale in thousandths (333 -> 0.333). The key's
`opts` hashed the render options with the f64 scale, and the frames had been
rendered at 0.3333..., so the series never matched and the bars stayed empty
at Third (and any resolution that isn't a whole number of thousandths, such
as Custom 1/7).

`opts_hash` now hashes the scale rounded to the key's thousandths, which the
key carries anyway.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:32:18 +00:00
Claude e96638093c Workspaces: saved workspaces last between sessions (#320)
Window > Workspace > Save as New Workspace and Save Changes to this
Workspace kept the layout only in memory (`UiState::saved_workspaces` /
`saved_floating`): nothing wrote them, so they were gone after a restart.

They are now written to `workspaces.json` in the settings store (the config
folder on desktop, OPFS on the web) when a workspace is saved, renamed or
deleted, and read back when the app starts; a file that doesn't read is
ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:32:18 +00:00
Claude 3bde85dfdb Timeline: Ctrl/Cmd+wheel and a trackpad pinch zoom time (#428)
egui turns Ctrl/Cmd+wheel and a pinch into a zoom factor (zoom_delta)
rather than a scroll, and the Timeline only zoomed on Alt+wheel, so
both did nothing over the layers. They now zoom time around the
pointer, like Alt+wheel. (B stays Set Work Area Start as in After
Effects; Split Layer is Ctrl/Cmd+Shift+D.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:16:48 +00:00
Claude 69bf806ff5 Graph Editor: buttons that don't fit the bar move to a » menu instead of being cut off (#457)
The Graph Editor's bottom bar lays out 17 text buttons in one row
(about 1100 px) on a painter clipped to the graph area, so on a
normal-width Timeline the right-hand ones (keyframe interpolation and
easing) were cut off and unreachable. Buttons that would pass the bar's
right edge now go, in order, to a » menu at its end; picking one there
runs the same action on the next frame. Hidden buttons register as
timeline.graph.more.<id> while the menu is open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:16:48 +00:00
Claude e152dfd1d1 Essential Graphics: Scale keeps its Constrain Proportions link, on by default (#338)
A Scale property added to Essential Graphics fell into the generic Point
control: two independent fields with no link, so dragging one value
distorted the layer, unlike After Effects, whose Scale control keeps the
chain link. It now draws the link (on by default) with one field per
axis; linked, an edit scales the others in proportion (Alt edits one),
using the Timeline's constrained() (moved to widgets). The link state is
the property's own, shared with the Timeline's chain link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:16:47 +00:00
Claude 76c9abad50 Viewer: the 3D Renderer menu shows the comp's renderer and switches it (#307)
The Composition panel's bottom bar drew a hard-coded "Classic 3D"
dropdown that ignored the comp's renderer and did nothing when clicked,
so an Advanced 3D comp still read Classic 3D. It now shows the comp's
renderer (translated) and, as in After Effects, its menu switches it
through comp.settings (one undo step); the automation label is the
renderer's name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:16:36 +00:00
Claude bf5e6c6cec #581: the Discord pill fits its label and field text sits on the field's middle
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:16:03 +00:00
Claude e4916e5ca9 #513: clicking off a mask's path, even on its layer, deselects its points
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:16:03 +00:00
Claude ad7df67602 #360: the Project row menu's New Comp from Selection uses the whole selection
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 19:16:03 +00:00
Claude 7a95a0d138 Project: a single unselected folder or data-file drag still reports why; index math saturates (#634 follow-up)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 18:51:45 +00:00
Claude 954e89c661 Merge pull request #638 from FrederoxDev/feat/color-hex-input 2026-10-10 18:51:16 +00:00
Claude 1c68166b2e Merge pull request #634 from Ni-zav/fix/project-multiselect-drag-351-s20261010T1753Z-f4c2 2026-10-10 18:51:15 +00:00
Claude 5727754a54 Merge pull request #628 from MarekSpodBiedry/issue-505 2026-10-10 18:51:15 +00:00
Claude 6538fb175f Merge pull request #619 from MarekSpodBiedry/issue-546 2026-10-10 18:49:51 +00:00
Claude ea10c73294 Merge pull request #618 from MarekSpodBiedry/issue-547 2026-10-10 18:49:51 +00:00
FrederoxDevandClaude Opus 5.5 c8657bf214 UI: one After Effects-style colour picker with a hex field for every colour input
Every colour input opens one picker laid out like After Effects' Color
Picker: a square and slider for the channel chosen with H / S / B /
R / G / B, the new colour over the original, HSB and RGB fields, a hex
field (#RRGGBB, RRGGBB, #RGB) and OK / Cancel. Changes apply live;
Cancel, Escape and the original swatch restore the starting colour.

The 3D light dialog, Essential Graphics and Layer Styles passed sRGB
values to egui's color_edit_button_rgb(a), which reads them as linear,
so picked colours were stored darker (#808080 became #373737). They and
the other dialogs now use the shared sRGB colour button.

The picker and colour helpers live in color_picker.rs; widgets
re-exports them.

Tests: ui_color_hex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:26:20 +01:00
Nigel Ihza Firdausy 1922e621c2 fix(ui): drop all selected Project items into compositions (#351)
Preserve Project multi-selection when dropping onto the Timeline or Composition viewer. Keep stack order and drop position, skip non-layer project items, and add pointer-drag regression coverage.
2026-10-11 00:58:35 +07:00
MarekSpodBiedry 068db1f36b Let pan and zoom work while 3D Camera Tracker points are shown (#505) 2026-10-10 19:31:51 +02:00
MarekSpodBiedry ad0fc4da09 Locked viewer: re-convert pixels when the display profile or output simulation changes (#546) 2026-10-10 19:12:02 +02:00
MarekSpodBiedry d5f8fb54cb Viewer: passive Composition viewers apply the monitor color conversion (#547) 2026-10-10 19:11:00 +02:00
Claude 00364546eb Merge pull request #593 from kikikikier/community/type-in-font-search 2026-10-10 16:29:15 +00:00
kikikikier abd44404f8 UI: add inline font family search in Character and Properties 2026-10-10 17:14:06 +03:00
Claude 00e9e37c0a UI: the drop hint and drop errors go through the interface catalog; the Wayland notice points to the README (#447 follow-up)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 12:55:10 +00:00
Claude 63acbb1eb0 Merge pull request #447 from David-T-Campos/fix/footage-drag-drop
# Conflicts:
#	apps/effectcraft/src/main.rs
2026-10-10 12:54:44 +00:00
Claude a5feb441e9 Merge pull request #499 from tylerjenningsw/enhance/project-shift-delete 2026-10-10 12:51:16 +00:00
Claude 0ce5063d9f Viewer: Ctrl/Cmd draws a shape from its centre, as in After Effects (#443 follow-up)
Also keeps #442's newest-completed-revision lookup for the live drag, so
Frames has one way to pick the frame shown while an edit renders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
2026-10-10 12:51:15 +00:00
Claude b7b47a0e10 Merge pull request #443 from Aavirash/fix/shape-drag-preview
# Conflicts:
#	crates/ui-egui/src/frames.rs
#	crates/ui-egui/src/panels/viewer.rs
2026-10-10 12:50:43 +00:00
Claude 91d37dd449 Merge pull request #423 from cdinhoo/codex/effect-input-control-fixes 2026-10-10 12:50:18 +00:00
Claude b5c6eb7d5e Merge pull request #461 from vbasky/feature/recursive-footage-relink 2026-10-10 12:50:18 +00:00
Claude 790f57ef24 Merge pull request #442 from cdinhoo/codex/live-preview-updates
# Conflicts:
#	docs/architecture.md
2026-10-10 12:50:18 +00:00
Claude 0df89c84ec Merge pull request #579 from KattKnight/windows-test-fixes 2026-10-10 12:49:56 +00:00
Claude f6d130ac38 Merge pull request #512 from sanyamsingh001/fix/settings-info-return 2026-10-10 12:49:17 +00:00
KattandClaude Opus 5.5 a650e6c21d Tests: four failures on Windows (autosave paths, GPU viewer adapter, audio preview race)
- automation / cli autosave restart tests: the MCP instructions embed the
  auto-save state as JSON, so a Windows path's backslashes are escaped there;
  look for the JSON form of the path.
- ui_gpu: egui_kittest prefers a CPU adapter, which on Windows is WARP on
  DirectX 12, where FXC fails to compile the compositor's `pointwise` kernel
  ("compilation aborted unexpectedly"), so the viewer stayed on the CPU and
  the test failed before comparing anything. Build the harness on the adapter
  the headless compositor picked (falling back to egui_kittest's choice).
- ui_audio_scrub (#103 test): with a fixed 2 s comp, a machine with many
  render threads cached the whole preview before the first step, so the sound
  rightly started at once and no silent frame was counted (3 of 24 runs
  failed with 8 copies in parallel). Size the comp to four times the frames
  playback requests per step, so caching takes at least four steps (0 of 24).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:36:52 +05:30
Aavirash 603337a061 Viewer: a layer drag moves the picture while the button is down
Every pointer move replaces the comp's content identity, so the frame on
screen takes a new cache key at every step while its render is still in
flight; the viewer only ever showed an exact key, so the picture froze on
the last completed frame until the drag ended. While a drag or a property
scrub is running, show the newest frame of the same comp, frame, scale,
view and render options that is ready — a render behind, as After Effects
does — and go back to exact frames when it stops.
2026-10-10 12:13:55 +02:00
Aavirash 0d2264dbed Viewer: the shape tools show the tool's own shape while dragging
The drag preview was a 1 px axis-aligned rectangle for every shape tool,
which read as no preview at all against most comps. Draw the tool's own
path instead (rectangle, rounded rectangle, ellipse, polygon, star), from
the engine's own geometry, filled with the Tools bar's Fill and outlined
in its Stroke, with a caption saying where the shape lands — a mask on
the selected layer, into the selected shape layer, or a new shape layer.

The ghost and the released shape go through one normalisation, so the
drag shows exactly what it commits: Alt (Option) draws from the press
point and Shift squares the box, both live. The drag also starts at the
press point now, not where the 6 px drag threshold was crossed, so the
shape is drawn from where the button went down, as in After Effects.
2026-10-10 12:13:21 +02:00
tylerjenningsw 4359899f7a Project: a Cut is read with the modifiers held where it is in the frame (#484)
Cause: clipboard events carry no modifiers, and the Cut and Copy/Paste
mapping read i.modifiers, egui's state after all of the frame's events.
A Shift+Delete with Shift released in the same frame became Ctrl+X (no
deletion), and a Ctrl+X followed in the same frame by Ctrl up and Shift
down became Shift+Delete: the selected items and the layers using them
deleted without the prompt.

Fix: walk the frame's events in order from the modifiers held when it
began (the state the last pass ended with, recorded each pass), so each
Cut, Copy and Paste uses the modifiers at its place in the stream. When
that state isn't known (a pass was skipped), a Cut is never Shift+Delete.
Only Shift alone counts, not Ctrl/Alt+Shift.

Tests: a_cut_is_read_with_the_modifiers_where_it_is_in_the_frame queues
modifier changes and a Cut in one frame (Shift then Cut and Shift up;
Ctrl, Cut, Ctrl up, Shift down; and the mixed orders); the Windows
Shift+Delete helper now sends Shift, Cut and Shift up as one frame. They
fail on the previous mapping and pass now.
2026-10-09 19:55:48 -04:00
sanyamsingh001andCodex e4ca1e919a G2: return to Settings after dismissing GPU Information
Preserve pending preference edits through the existing OK and Cancel actions.

Co-authored-by: Codex <codex@openai.com>
2026-10-10 08:46:03 +10:00
tylerjenningsw a65d70f10e Project: Shift+Delete deletes the selected items without asking (#484)
With the Project panel focused, Delete Project Items Without Confirmation
runs project.delete on the selection: items compositions use go without
the prompt, with their layers, in one undo step. In the other panels it
does nothing, and like every shortcut it doesn't fire while typing or
with a dialog open.

On Windows the windowing layer sends Shift+Delete as Cut (the old Cut
key), which was mapped to Ctrl+X: in the Project panel, which has no
clipboard, a Cut with only Shift held is Shift+Delete now. Elsewhere it
still cuts.

Tests (ui_project_delete): Shift+Delete as a key and as Windows' Cut
deletes a comp, a solid in use, footage and a folder without the prompt
and one undo restores them; a multi-selection with a folder holding a
solid in use goes together; an empty selection deletes nothing; the next
Delete still asks after Shift+Delete or an answered prompt; it does
nothing in the Composition panel, while renaming or with a dialog open;
Shift+Backspace, Alt/Ctrl+Delete and Ctrl/Alt+Shift+Delete don't delete.
The deleting tests fail without this change.
2026-10-09 16:27:48 -04:00