feat(m11): native OS drag-out of bank samples (copy-only)

Pure drag_out (gesture boundary + path-list assembly) + Windows OLE
CF_HDROP / SWELL file-list shell; bank_panel hands off when a dragged
selection leaves the client area. COPY-ONLY mask; internal drag intact.
This commit is contained in:
2026-07-26 20:02:46 -04:00
parent 73f81ffbb7
commit 34df2563e4
7 changed files with 738 additions and 1 deletions
+48
View File
@@ -0,0 +1,48 @@
// drag_out — pure implementation. See drag_out.h. NO REAPER / SWELL / OS / vendor.
#include "drag_out.h"
#include <unordered_set>
namespace reasampler {
namespace {
// Half-open point-in-rect (matches the panel's other hit-tests: [x, x+w) x [y, y+h)).
bool insideClient(int px, int py, const PanelClientRect& c) {
return px >= c.x && px < c.x + c.width &&
py >= c.y && py < c.y + c.height;
}
} // namespace
DragGesture decideGesture(int px, int py, const PanelClientRect& client,
const DragState& state) {
if (!state.dragging || !state.hasArmedSamples) return DragGesture::None;
return insideClient(px, py, client) ? DragGesture::Internal : DragGesture::OsDrag;
}
PathList assemblePathList(const std::vector<ResolvedSample>& resolved) {
PathList out;
std::unordered_set<std::string> seen;
seen.reserve(resolved.size());
for (const ResolvedSample& s : resolved) {
if (s.absolutePath.empty()) { // shell could not resolve it
++out.skippedUnresolved;
continue;
}
if (!s.fileExists) { // stale index entry, file gone
++out.skippedMissing;
continue;
}
if (!seen.insert(s.absolutePath).second) { // already emitted this path
++out.skippedDuplicate;
continue;
}
out.paths.push_back(s.absolutePath);
}
return out;
}
} // namespace reasampler