ux: drop last-reference confirm from sample remove; silent remove via undo (R-B)

This commit is contained in:
2026-07-26 17:27:05 -04:00
parent 6199a4868d
commit ff4eb26eab
5 changed files with 30 additions and 86 deletions
+7 -31
View File
@@ -1365,38 +1365,14 @@ void transferSamples(const std::vector<std::string>& sampleIds,
// Remove `sampleIds` from `srcBankId` (index-only, this-bank scope). Non-destructive to
// the file: a last-reference remove leaves the file on disk, orphaned until Phase R
// prune — remove NEVER deletes bytes (the manifest is untouched). Confirm-on-last-
// reference guardrail: a single confirm summarizing the N whose files this would orphan
// (computed on the PRE-mutation reference graph), fired only when at least one would
// orphan. Ids passed by value — no BankIndex& cached across the loop's mutations.
// prune — remove NEVER deletes bytes (the manifest is untouched). Removes are silent
// (no confirm dialog); recoverability is provided by the batched REAPER undo (R-B) —
// one Ctrl-Z restores the index entry. Ids passed by value — no BankIndex& cached
// across the loop's mutations.
void removeSamples(const std::vector<std::string>& sampleIds,
const std::string& srcBankId) {
if (!book() || sampleIds.empty()) return;
const Bank* src = book()->bank(srcBankId);
if (!src) return;
// Count files this remove would orphan — computed BEFORE mutating, so a same-hash
// sibling in another bank counts as a surviving reference.
int orphanCount = 0;
for (const std::string& sid : sampleIds) {
const Sample* s = src->index.query(sid);
if (!s) continue; // already gone; not a last-reference orphan
if (!book()->hashReferencedElsewhere(s->contentHash, srcBankId)) ++orphanCount;
}
if (orphanCount > 0) {
const std::string msg =
std::to_string(orphanCount) +
(orphanCount == 1 ? " selected sample is" : " selected samples are") +
" in no other bank.\n\nRemoving " +
(orphanCount == 1 ? "it" : "them") +
" drops the index entry only -- the file stays on disk until you prune "
"(it is never deleted by remove).\n\nRemove anyway?";
// 4 == MB_YESNO. 6=Yes (SDK); anything else cancels.
const int r = ShowMessageBox(msg.c_str(),
"ReaSampler: remove last-reference sample(s)", 4);
if (r != 6) return;
}
if (!book()->bank(srcBankId)) return;
int removed = 0;
for (const std::string& sid : sampleIds)
@@ -1771,8 +1747,8 @@ bool handleKey(int vk) {
stopAudition();
return true;
case VK_DELETE: {
// Remove the focused-region selection (B5). Same confirm-on-last-reference
// path the context-menu "Remove" uses; a no-op when nothing is selected.
// Remove the focused-region selection (B5). Silent; a no-op when nothing
// is selected.
const std::vector<std::string> sel = focusedSelectionIds();
if (sel.empty()) return false; // nothing selected — let the key fall through
removeSamples(sel, bankIdForRegion(g_panel.focusedRegion));