Fix drag-out losing audio and FX-container drops losing the capture; re-home ingest under shell/actions

This commit is contained in:
2026-07-29 23:49:53 -04:00
parent a689fb75eb
commit 0800760833
16 changed files with 269 additions and 45 deletions
+7
View File
@@ -48,4 +48,11 @@ PathList assemblePathList(const std::vector<ResolvedSample>& resolved) {
return out;
}
OsHandoff decideOsHandoff(const std::vector<std::string>& paths) {
OsHandoff out;
out.startOsDrag = !paths.empty();
out.releaseInternalDrag = out.startOsDrag;
return out;
}
} // namespace reasampler::ui
+15
View File
@@ -69,4 +69,19 @@ struct PathList {
// exact-string — the shell normalizes case/slashes upstream if it wants Windows-style dedup.
PathList assemblePathList(const std::vector<ResolvedSample>& resolved);
// --- OS hand-off ordering -----------------------------------------------------
// The two side effects the shell performs when a drag crosses out of REAPER. They are ONE
// decision, not two: winding the internal drag down (release capture, clear drag state) for a
// hand-off that then cannot happen consumes the gesture — the user sees a drag that silently
// did nothing and drags again. Never release without starting.
struct OsHandoff {
bool startOsDrag = false; // hand `paths` to the OS drag initiator
bool releaseInternalDrag = false; // first wind down mouse capture + panel drag state
};
// Decides the hand-off from the assembled path list. Empty (everything stale/unresolvable)
// means the internal drag stays live rather than dying half-torn-down.
OsHandoff decideOsHandoff(const std::vector<std::string>& paths);
} // namespace reasampler::ui
+11
View File
@@ -76,6 +76,17 @@ std::vector<std::uint8_t> buildInstrumentDropPreset(const std::string& sampleId)
return buildVstPresetBytes(vstClassIdHex(), instrumentDropStateBytes(sampleId));
}
DropOutcome decideDropOutcome(const DropAttempt& attempt) {
DropOutcome out;
if (attempt.addedFxIndex < 0) return out; // add failed — nothing exists to roll back
if (!attempt.presetApplied) {
out.rollbackFxIndex = attempt.addedFxIndex;
return out;
}
out.loaded = true;
return out;
}
bool infoNamesFxHotspot(const std::string& info) {
// See the header contract for the prefix rule and the embed-strip exclusion.
auto startsWith = [&info](const char* p) { return info.rfind(p, 0) == 0; };
+21
View File
@@ -68,4 +68,25 @@ bool infoNamesFxHotspot(const std::string& info);
// assert the capture is selected. Not called by the shell.
std::vector<std::uint8_t> instrumentDropStateBytes(const std::string& sampleId);
// --- All-or-nothing rollback --------------------------------------------------
// What the shell observed while executing one drop, reduced to the two REAPER
// results the contract turns on.
struct DropAttempt {
int addedFxIndex = -1; // TrackFX_AddByName's return; < 0 = nothing was created
bool presetApplied = false; // TrackFX_SetPreset's return
};
// The verdict. `rollbackFxIndex >= 0` obliges the caller to TrackFX_Delete it before
// returning — an instance whose capture never landed must not survive the drop.
struct DropOutcome {
bool loaded = false;
int rollbackFxIndex = -1;
};
// Pure so the contract is provable without a DAW: the rollback obligation is decided
// here, not inline in the shell, and holds identically for every drop surface (FX
// button, FX chain/container, Media-Explorer import).
DropOutcome decideDropOutcome(const DropAttempt& attempt);
} // namespace reasampler::wire