feat(prune): R3 guarded deletion — confirm-to-delete + panel button

Extend BANK_PRUNE_FOLDER from report-only to dry-run→confirm-with-manifest→
delete exactly the pure-core orphan set (fresh recompute, stale entries skipped).
Windows routes to Recycle Bin (SHFileOperation+FOF_ALLOWUNDO), else unlink.
New pure prune_button module + footer button dispatching the action id. No
ext-state write, no undo point (deletion is not REAPER-undoable).
This commit is contained in:
2026-07-26 18:47:02 -04:00
parent 105a4421a8
commit 7b53ba16f6
12 changed files with 695 additions and 28 deletions
+39
View File
@@ -0,0 +1,39 @@
#include "prune_button.h"
// prune_button implementation — right-anchored button placement in the footer strip,
// with a left-collision suppression rule. Trivially auditable arithmetic; the safety
// property (a suppressed/empty button never claims a click) is a pure predicate tested
// outside the DAW.
namespace reasampler {
ButtonRect computePruneButton(const FooterRect& footer, const PruneButtonSpec& spec) {
if (footer.width <= 0 || footer.height <= 0) return ButtonRect{}; // degenerate footer
if (spec.buttonWidth <= 0) return ButtonRect{}; // nothing to place
// Right-anchored: right edge inset from the footer's right; width fixed.
const int right = footer.x + footer.width - spec.rightInset;
const int left = right - spec.buttonWidth;
// Suppress if the button would encroach past the reserved left inset (tail label room)
// or spill off the left of the footer entirely.
if (left < footer.x + spec.minLeftInset) return ButtonRect{};
// Vertically centred by the inset; clamp so a thin footer never yields a negative height.
int top = footer.y + spec.verticalInset;
int height = footer.height - 2 * spec.verticalInset;
if (height <= 0) {
top = footer.y;
height = footer.height;
}
return ButtonRect{left, top, spec.buttonWidth, height};
}
bool hitTestPruneButton(int px, int py, const ButtonRect& button) {
if (button.empty()) return false; // suppressed button claims nothing
return px >= button.x && px < button.x + button.width &&
py >= button.y && py < button.y + button.height;
}
} // namespace reasampler