Refuse to park a track whose pre-park snapshot is gone, rather than re-snapshotting the already-parked chain as the user's state
This commit is contained in:
+23
-15
@@ -31,6 +31,7 @@
|
||||
#define REAPERAPI_WANT_SetMediaTrackInfo_Value
|
||||
#define REAPERAPI_WANT_GetSetMediaTrackInfo_String
|
||||
#define REAPERAPI_WANT_PreventUIRefresh
|
||||
#define REAPERAPI_WANT_ShowConsoleMsg
|
||||
#define REAPERAPI_WANT_Undo_BeginBlock2
|
||||
#define REAPERAPI_WANT_Undo_EndBlock2
|
||||
#define REAPERAPI_WANT_TrackList_AdjustWindows
|
||||
@@ -107,16 +108,6 @@ void applyTransparentLaneDisplay(MediaTrack* tr) {
|
||||
static_cast<double>(settings | kLaneSettingsHideButtons));
|
||||
}
|
||||
|
||||
const char* flagParm(Flag f) {
|
||||
switch (f) {
|
||||
case Flag::ShowInTcp: return "B_SHOWINTCP";
|
||||
case Flag::ShowInMixer: return "B_SHOWINMIXER";
|
||||
case Flag::MainSend: return "B_MAINSEND";
|
||||
case Flag::FxEnable: return "I_FXEN";
|
||||
}
|
||||
return "B_SHOWINTCP"; // unreachable; keeps the compiler quiet
|
||||
}
|
||||
|
||||
// The master track is not enumerated by GetTrack (index space excludes it),
|
||||
// so it can never enter the tree — the master-untouched invariant holds by
|
||||
// construction.
|
||||
@@ -185,7 +176,7 @@ bool writeIfChanged(MediaTrack* tr, const char* parm, double value) {
|
||||
|
||||
void applyFlags(MediaTrack* tr, const std::vector<TrackFlagOp>& flags, int& undoMask) {
|
||||
for (const TrackFlagOp& op : flags) {
|
||||
if (!writeIfChanged(tr, flagParm(op.flag), static_cast<double>(op.value))) continue;
|
||||
if (!writeIfChanged(tr, trackFlagParm(op.flag), static_cast<double>(op.value))) continue;
|
||||
// I_FXEN is the only FX-domain flag driven here, so it is the only one
|
||||
// whose undo record has to carry UNDO_STATE_FX.
|
||||
if (op.flag == Flag::FxEnable) undoMask |= UNDO_STATE_FX;
|
||||
@@ -449,6 +440,7 @@ bool applyMode(ViewModeModel& model, const std::string& targetModeId, ReaProject
|
||||
|
||||
int undoMask = kApplyUndoMask;
|
||||
bool laneModeChanged = false;
|
||||
int refusedParks = 0;
|
||||
|
||||
Undo_BeginBlock2(proj);
|
||||
{
|
||||
@@ -470,13 +462,22 @@ bool applyMode(ViewModeModel& model, const std::string& targetModeId, ReaProject
|
||||
MediaTrack* tr = resolve(trackByGuid, guid);
|
||||
if (!tr) continue; // stale GUID — prune
|
||||
|
||||
// Full contract at decidePark. Only an absent snapshot can refuse, so
|
||||
// the short-circuit cannot change the answer (ParkOnly ignores the
|
||||
// second term); a first park still pays the four reads, a reapply's
|
||||
// re-park of a still-parked track does not.
|
||||
const bool haveSnapshot = model.snapshot(guid) != nullptr;
|
||||
const ParkAction action = decidePark(
|
||||
haveSnapshot,
|
||||
!haveSnapshot &&
|
||||
parkFlagsAlreadyApplied(tp.flags, readParkFlagValues(tr, tp.flags)));
|
||||
if (action == ParkAction::Refuse) { ++refusedParks; continue; }
|
||||
|
||||
// Enqueued FIRST: a park landing on this track's own pending restore
|
||||
// cancels it, and those ops are then the only surviving record of the
|
||||
// pre-park FX state. Snapshot ONCE — a snapshot already present means
|
||||
// the track is still parked, so recapturing would overwrite the true
|
||||
// pre-park state with zeros and a later restore would hide it for good.
|
||||
// pre-park FX state.
|
||||
const std::vector<FxOfflineOp> cancelled = deferFxPark(proj, guid);
|
||||
if (model.snapshot(guid) == nullptr)
|
||||
if (action == ParkAction::SnapshotThenPark)
|
||||
model.storeSnapshot(guid, snapshotTrack(tr, cancelled));
|
||||
applyFlags(tr, tp.flags, undoMask);
|
||||
}
|
||||
@@ -539,6 +540,13 @@ bool applyMode(ViewModeModel& model, const std::string& targetModeId, ReaProject
|
||||
if (laneModeChanged) UpdateTimeline();
|
||||
|
||||
Undo_EndBlock2(proj, undoLabel.c_str(), undoMask);
|
||||
|
||||
// After the undo block and the UI hold: a refusal is a report, not a project
|
||||
// write, and it must not join what a Ctrl-Z rolls back. "!SHOW:" so an
|
||||
// unattended project-load reapply cannot force the console open
|
||||
// (reaper_plugin_functions.h:6536), same as the drain's drop report.
|
||||
const std::string refusedMsg = describeRefusedParks(refusedParks);
|
||||
if (!refusedMsg.empty()) ShowConsoleMsg(("!SHOW:" + refusedMsg).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user