Phase 27: strengthen undo transactions and improve editor workflow
This commit is contained in:
parent
901a536f10
commit
c4daef7c42
21 changed files with 460 additions and 27 deletions
115
docs/EDITING.md
Normal file
115
docs/EDITING.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# Editing commands and undo (Phase 27 audit)
|
||||
|
||||
The control thread owns project edits and history. Audio plans are immutable
|
||||
snapshots; widgets never pass editable project pointers into the callback.
|
||||
Graph commands and batch note commands use the existing public C command APIs.
|
||||
The GUI groups a completed gesture or accepted dialog as one history step.
|
||||
|
||||
## Operation audit
|
||||
|
||||
| Operation | History / grouping | Engine and external effects |
|
||||
| --- | --- | --- |
|
||||
| Track create/delete/name/order; clip create/delete/move/trim/name | One accepted command/drag | Stops playback before mutation; track removal cascades clips/notes/lanes, never files |
|
||||
| MIDI clip creation and default source routing | One command, including automatic route | Core candidate graph is validated before model adoption |
|
||||
| Audio duplicate/split/gain/fades | One command including copied metadata/notes | Source WAV is shared; split does not rewrite samples |
|
||||
| Note add/delete/drag/resize, filtered quantize/transpose/properties/repeat | One gesture/batch, including fresh note IDs | Stops playback; validates all matched notes/capacity before applying |
|
||||
| Graph add/remove/connect/disconnect/insert gain | One graph command | Candidate and history storage prepared before engine submission; active graph remains immutable |
|
||||
| Mixer gain/pan/mute/solo, bus create/route, automation points | One released slider/command/point | Stops playback; bus deletion reroutes members without deleting their media |
|
||||
| Plugin add/replace/control/reset/automation/insert | One accepted command/dialog including wiring | Candidate compiles before installation; old module instances retire on control thread |
|
||||
| MIDI controller bindings | One channel-map command | Rebuilds immutable MIDI plan; no callback mutation |
|
||||
| Import/relink audio | One accepted edit, including newly needed track/routes | Import candidate prepared before adoption; source media never copied/deleted by undo |
|
||||
| Recording start/stop | Start has no document history step; completed take adds one | Undo removes take reference, never finalized WAV; failed add retains saved take for manual import |
|
||||
| Save / Save As | No history step; retains existing history | Writes document; undo does not restore earlier on-disk file versions |
|
||||
| New / Open | Fresh baseline after unsaved-change handling | Parse/prepare failure retains old document/history; engine may already be stopped/reset after preparation failure |
|
||||
| Transport, panic, external connections/reconnect | Not document history | Undo does not reverse playback, live voices, device connections or capture side effects |
|
||||
| Selection, tabs, snap/grid, zoom/scroll, node layout, meters/reset peaks | Session UI state, no history | No music or media changes |
|
||||
|
||||
No arbitrary cross-command grouping or automation recording mode is introduced.
|
||||
An accepted no-op model edit can still consume a step. History holds 32 edits
|
||||
plus a baseline; new accepted edits discard redo, and eviction drops the oldest
|
||||
baseline. Monotonic ID high-water marks survive undo and branches. History is
|
||||
session-only; restart/New/Open discards it.
|
||||
|
||||
## History ownership and failure boundary
|
||||
|
||||
`xtc_history_reserve` allocates one empty fixed-capacity project/graph snapshot
|
||||
before an edit mutates the document or a candidate is submitted to the engine.
|
||||
Failure aborts the command without changing history or dropping redo. The call
|
||||
is idempotent: storage left by a rejected command is reused. It neither records
|
||||
an edit nor moves the cursor. GUI arrangement/note/mixer guards reserve before
|
||||
stopping playback; candidate graph/plugin/map/take paths reserve before
|
||||
publication. File/media work and compilation can still fail before adoption.
|
||||
|
||||
The next `xtc_history_record` copies model arrays and the bounded 64-node/4096-
|
||||
edge graph into reserved storage without allocating. Successful record takes
|
||||
ownership of that storage, remembers IDs, then releases old redo/evicted states.
|
||||
The snapshot contains metadata/graph configuration only, never sample buffers,
|
||||
DSP instances, module handles or GUI pointers. An unused reservation is freed
|
||||
with history. This adds at most one pending metadata snapshot to the 33 retained
|
||||
states. C clients that call record without reserving retain the original
|
||||
clone-and-report-allocation-failure behavior; they must handle that result.
|
||||
All history work is serialized on the control thread, never the audio callback.
|
||||
|
||||
Undo/redo checks out an owned candidate without moving the cursor, stops/resets
|
||||
transport and prepares its assets/plans, then accepts the adjacent history step
|
||||
only after installation succeeds. Failed checkout/preparation retains the
|
||||
cursor/document, so retry is possible. Preparation failure may leave transport
|
||||
stopped at zero; it does not resume playback automatically. Snapshot restoration
|
||||
marks the document dirty conservatively, even if it matches a saved file.
|
||||
|
||||
## Selection, focus and menus
|
||||
|
||||
Ctrl+Z undoes; Ctrl+Shift+Z and Ctrl+Y redo. The main Edit menu disables unavailable
|
||||
steps and disables history while recording. Piano roll also has Edit/Undo/Redo
|
||||
shortcuts. Undo preserves currently selected track/clip, mixer strip, graph node
|
||||
and piano-roll clip/note when their stable IDs still exist (notes must remain
|
||||
visible under the current filter). Clip selection follows its restored track. A removed selection
|
||||
clears, with track fallback for a removed clip. A visible piano roll stays open
|
||||
when its clip survives; missing clips hide it. Historical selections/layouts are
|
||||
not saved in snapshots; undo does not resurrect a selection already cleared by
|
||||
a deletion. Open/New retain their reset behavior.
|
||||
|
||||
Editor-local shortcuts act on focused editors. Text inputs retain Space and
|
||||
text undo/editing keys; numeric mixer inputs do not invoke fader shortcuts.
|
||||
Timeline Ctrl+D duplicates, F2 renames, Alt+Up/Down reorders tracks, S splits
|
||||
audio at the cursor, A opens audio properties and Delete removes the selection.
|
||||
Graph Left/Right chooses a node, L arranges by flow, I inserts unity gain in the
|
||||
selected wire, Delete removes the selected node/wire and Escape cancels gestures.
|
||||
Piano-roll commands are listed in its Notes menu. Escape cancels gestures;
|
||||
ordinary deletion is reversible and does not add a confirmation dialog.
|
||||
|
||||
Graph right-click now selects the node/wire under the pointer before showing
|
||||
Inspect/Arrange/Insert/Delete; empty space clears a stale selection. Piano-roll
|
||||
right-click selects the clicked note and offers Properties/Quantize/Repeat/Delete.
|
||||
It no longer immediately deletes the note. Timeline context menus retain their
|
||||
selection and duplicate/rename/delete/audio commands. Dismissing a context menu
|
||||
does not edit the document. Context menus and widgets remain C++/FLTK UI code.
|
||||
|
||||
Open/import/plugin load/replacement paint a busy cursor and operation status
|
||||
before synchronous work, flushing drawing without dispatching new input or
|
||||
reentering commands. This is feedback, not background loading or cancellable
|
||||
progress. Failure messages distinguish capacity, memory, target/value, format/
|
||||
optional-support and audio errors. Unsaved New/Open/Quit and Save As overwrite
|
||||
keep their existing confirmations; undoable deletes and external-media reference
|
||||
edits do not request extra approval. No operation here deletes source media.
|
||||
|
||||
## Evidence and manual procedure
|
||||
|
||||
`make all test gui test-gui-plugins test-reliability analyze test-workflow
|
||||
test-gui-jack` covers core commands, grouped gestures/batches, backend rollback,
|
||||
selection retention, take undo/redo and real software JACK state restoration.
|
||||
The GUI fixture injects history-reservation failure before graph/map/import
|
||||
publication and verifies unchanged document, submission count and redo. The
|
||||
allocation-interposed reliability suite fails each reservation allocation, then
|
||||
fails all allocations while capturing a reserved edit; redo branching and
|
||||
snapshot restoration still succeed. ASan/UBSan cover the same ownership paths.
|
||||
|
||||
For native manual inspection: right-click different graph nodes/wires and empty
|
||||
space, dismiss the menu, and confirm only selection changes. Right-click a note,
|
||||
dismiss, then explicitly Delete and undo; confirm the note returns. Type spaces
|
||||
and use text undo in a name/input dialog, and edit numeric mixer fields without
|
||||
triggering fader keys. Record a short take, stop, undo once and confirm its WAV
|
||||
still exists; redo restores the reference. Watch operation feedback on a large
|
||||
import/Open. These manual popup/focus/large-file and physical-device listening
|
||||
checks remain pending; automation does not claim broad accessibility or human
|
||||
usability qualification. Existing native-plugin failure limits still apply.
|
||||
|
|
@ -19,7 +19,8 @@
|
|||
Automated LADSPA controls use run(1) and can be expensive.
|
||||
- GUI loading/compilation is synchronous on the control thread. Timeline grid/
|
||||
zoom/selection and graph positions are session UI state. Undo retains 32 edits
|
||||
plus baseline; allocation failures are reported, not silently hidden. Media is
|
||||
plus baseline and at most one reserved metadata snapshot; GUI edits reserve
|
||||
history before mutation/publication. Media is
|
||||
never removed by undo/delete. Broad screen-reader/accessibility testing is pending.
|
||||
- Format v10 reads v1–v9 and uses relative local media references. External absolute
|
||||
media/module paths need manual repair after relocation. Saving does not bundle
|
||||
|
|
@ -59,3 +60,8 @@ PERFORMANCE.md, PLUGIN_HOSTING.md and RECOVERY.md for tested contracts/evidence.
|
|||
for live sine volume/pan/sustain. Live mappings do not drive arranged lanes,
|
||||
faders or plugins. No automation capture, touch/latch/write modes or loop
|
||||
transport. Backward jumps are deterministic for lanes, not opaque plugin tails.
|
||||
|
||||
- Editing feedback remains synchronous; busy cursors are not background loading
|
||||
or cancellable progress. Surviving selections are retained across undo but
|
||||
historical selection/layout is not stored. Native context-menu/focus manual
|
||||
qualification and broad accessibility testing remain pending. See EDITING.md.
|
||||
|
|
|
|||
|
|
@ -104,7 +104,8 @@ plus a baseline, cloning metadata and graph, never audio samples. Common graph,
|
|||
track, clip, note, mixer, import/relink and automation edits are included. One
|
||||
accepted gesture is one step; selection, scrolling and graph-node placement are
|
||||
GUI state and are not undoable. New/Open resets history; Save retains it.
|
||||
Undo/redo stops and resets transport and resets editor selections/layout. The
|
||||
Undo/redo stops and resets transport; Phase 27 preserves surviving selections
|
||||
by stable ID (layout remains session state). The
|
||||
candidate is installed before moving the history cursor: validation, asset-plan
|
||||
or backend failure retains the current document and history position. Missing
|
||||
assets retain the existing silent/reporting behavior. A new edit after Undo
|
||||
|
|
@ -112,8 +113,9 @@ removes the redo branch; the oldest state is evicted at capacity. Allocation
|
|||
ID high-water marks survive Undo/branching so abandoned IDs are not reused. History is
|
||||
session-only and Undo marks the document dirty even if it matches a saved state.
|
||||
External WAV files are never deleted or restored by Undo; recording itself cannot
|
||||
be undone while active. An allocation failure retaining a new history snapshot
|
||||
reports an error; the accepted edit remains in the document.
|
||||
be undone while active. Phase 27 reserves snapshot storage before GUI commands mutate/publish, so an
|
||||
allocation failure rejects the command before adoption; reserved capture itself
|
||||
does not allocate. C clients using unreserved history record must handle errors.
|
||||
|
||||
With mixer focus, M/S toggles mute/solo, Left/Right changes gain by 0.05,
|
||||
Shift+Left/Right changes pan, and Up/Down selects a track. Native sliders also
|
||||
|
|
|
|||
|
|
@ -720,10 +720,37 @@ Make common editing actions quick, discoverable, and safe to reverse.
|
|||
- Keep presentation logic out of the core C engine.
|
||||
|
||||
### Acceptance criteria
|
||||
- Documented editing operations have predictable undo/redo behavior.
|
||||
- Undo and redo restore the project model and relevant engine state consistently.
|
||||
- Failed operations do not leave partial changes behind.
|
||||
- Common tasks can be completed using documented keyboard and mouse interactions.
|
||||
- [x] Documented editing operations have predictable undo/redo behavior.
|
||||
- [x] Undo and redo restore the project model and relevant engine state consistently.
|
||||
- [x] Failed operations do not leave partial changes behind.
|
||||
- [x] Common tasks can be completed using documented keyboard and mouse interactions.
|
||||
|
||||
Implemented: operation-by-operation audit in EDITING.md; reserved history storage
|
||||
before GUI command mutation/candidate publication, followed by allocation-free
|
||||
snapshot capture; recording start creates no empty history entry and each
|
||||
completed take is one undoable reference edit; unavailable main-menu history
|
||||
steps disabled; surviving editor selections and open piano-roll context retained
|
||||
on undo; piano-roll history shortcuts/context menu and pointer-targeted graph
|
||||
context menus; input focus guards and synchronous busy feedback. Existing C
|
||||
graph/batch note commands and snapshot history remain the model boundary; FLTK
|
||||
presentation stays in C++. No project format change (v10 retained).
|
||||
|
||||
Validation: warning-enabled core/GUI builds and full tests; interposed allocation
|
||||
failure for each history reservation and capture with all allocations disabled;
|
||||
GUI history-reservation failure retains document, engine submission count and
|
||||
redo; completed-take undo grouping retains WAV; selection/context-target tests;
|
||||
existing grouped gestures/batches, candidate/backend rollback and save/reopen;
|
||||
workflow/software JACK GUI integration, reliability/callback guards, Clang static
|
||||
analysis, core/GUI ASan+UBSan, optional-dependency-free build, installation and
|
||||
package relocation. GUI sanitizer runs retain the existing fontconfig-only leak
|
||||
suppression. EDITING.md supplies a reproducible native manual procedure for
|
||||
popup dismissal, text focus, large synchronous operations and recorded takes.
|
||||
|
||||
Native manual popup/focus/large-file usability checks, broad accessibility and
|
||||
physical-device listening/endurance remain pending. History remains bounded and
|
||||
session-only; selection/layout history, arbitrary command grouping, background
|
||||
loading and destructive source-media editing are not supplied. Preparation
|
||||
failure can stop/reset transport while retaining the old document/history.
|
||||
|
||||
## Phase 28 — Project Format, Compatibility, and Portability
|
||||
|
||||
|
|
|
|||
|
|
@ -145,3 +145,10 @@ replaced. Audio → MIDI controller mapping lists all channel bindings; enter
|
|||
must be distinct, 120/123 reserved). Maps are undoable and saved. Controllers
|
||||
modify live sine voices; arranged track/bus/plugin automation takes precedence
|
||||
over its static controls and is unaffected by those MIDI bindings. See CONTROL.md.
|
||||
|
||||
Phase 27: unavailable main-menu undo/redo actions are disabled, including while
|
||||
recording. Piano roll has Edit/Undo/Redo shortcuts and a right-click note menu;
|
||||
right-click no longer immediately deletes notes. Graph right-click targets the
|
||||
node/wire under the pointer. Undo preserves surviving selections. Completed
|
||||
takes add one undo step; undo removes references and keeps WAV files. See
|
||||
EDITING.md for grouped commands, failure handling and keyboard/focus behavior.
|
||||
|
|
|
|||
|
|
@ -131,3 +131,15 @@ its region never deletes the WAV; recording failures retain their recovery path.
|
|||
There is no destructive media-delete operation. New/Open reset history after
|
||||
unsaved-change handling. The capacity limit and allocation-error reporting in
|
||||
MIXER.md still apply. Tests: `make test-editing test-gui-plugins test-workflow`.
|
||||
|
||||
## Phase 27 editing audit
|
||||
|
||||
See [EDITING.md](EDITING.md) for the operation-by-operation undo matrix, command
|
||||
ownership, allocation-failure boundary, external-media behavior and manual
|
||||
context-menu/focus procedure. History now reserves storage before edits and
|
||||
publication, preserving redo when commands fail. Recording start has no empty
|
||||
undo entry; a completed take is one step and undo never deletes its WAV.
|
||||
Undo preserves surviving selections and an open piano roll; the piano window
|
||||
also offers Edit/Undo/Redo. Graph context menus select under the pointer and
|
||||
piano-roll right-click now opens a menu instead of immediately deleting a note.
|
||||
Load/import/plugin work paints busy feedback while remaining synchronous.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue