import: a .rsbank lands as a new bank, whole or not at all

Four collisions answered explicitly: ids reminted, names never overwritten,
content deduped before the write, bank name auto-suffixed. Degraded ledger
refuses before the picker.
This commit is contained in:
2026-08-02 13:21:48 -04:00
parent 33ea95078d
commit a927dad2f4
26 changed files with 1689 additions and 24 deletions
+21 -3
View File
@@ -15,6 +15,7 @@
#include "shell/panel/draw_kit.h"
#include "shell/actions/ingest.h"
#include "shell/actions/package_import_action.h"
#ifdef _WIN32
#include <windowsx.h> // GET_X_LPARAM / GET_Y_LPARAM (SWELL supplies them on mac/linux)
@@ -40,12 +41,24 @@ PanelState g_panel;
namespace {
bool isPackagePath(const std::string& path) {
static const std::string kExt = ".rsbank";
if (path.size() <= kExt.size()) return false;
std::string tail = path.substr(path.size() - kExt.size());
for (char& c : tail)
if (c >= 'A' && c <= 'Z') c = static_cast<char>(c - 'A' + 'a');
return tail == kExt;
}
// DragQueryFile(hDrop, 0xFFFFFFFF, ...) returns the file count; each path is then
// queried by index (length first, excludes NUL, then a sized buffer). DragFinish
// always frees the shell-allocated drop buffer. Multi-file drop imports all into
// the active bank (bank-fill only — no assignment to any live instance).
// always frees the shell-allocated drop buffer. A .rsbank is a whole bank, not audio,
// so it routes to the import verb (one new bank each); everything else keeps the
// existing ingest route — multi-file drop imports all into the active bank (bank-fill
// only, no assignment to any live instance).
void handleDropFiles(HDROP hDrop) {
std::vector<std::string> paths;
std::vector<std::string> packages;
const UINT count = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0);
paths.reserve(count);
for (UINT i = 0; i < count; ++i) {
@@ -54,9 +67,14 @@ void handleDropFiles(HDROP hDrop) {
std::vector<char> buf(static_cast<std::size_t>(len) + 1, '\0');
DragQueryFile(hDrop, i, buf.data(), static_cast<UINT>(buf.size()));
std::string p(buf.data());
if (!p.empty()) paths.push_back(std::move(p));
if (p.empty()) continue;
if (isPackagePath(p)) packages.push_back(std::move(p));
else paths.push_back(std::move(p));
}
DragFinish(hDrop);
if (g_panel.session)
for (const std::string& pkg : packages)
doImportBankPackageFile(*g_panel.session, pkg);
if (!paths.empty()) ingestDroppedFiles(paths);
}