Land the package filesystem shell: streaming atomic package_io, journaled rollback carve-out, asymmetric platform pickers
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
// package_pickers.cpp — see package_pickers.h. Export is native rather than REAPER
|
||||
// API: the SDK's newer GetUserFileName(mode=0) could save, but it resolves to null
|
||||
// on older REAPER builds this extension still loads in, while GetSaveFileNameW /
|
||||
// BrowseForSaveFile are always present. main.cpp owns the REAPER API pointers; this
|
||||
// TU gets them extern.
|
||||
|
||||
#include "shell/package/package_pickers.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
#else
|
||||
#include "swell/swell.h"
|
||||
#endif
|
||||
|
||||
#define REAPERAPI_MINIMAL
|
||||
#define REAPERAPI_WANT_GetUserFileNameForRead
|
||||
#define REAPERAPI_WANT_GetMainHwnd
|
||||
#include "reaper_plugin_functions.h"
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
bool pickPackageForImport(std::string& outAbsPath) {
|
||||
outAbsPath.clear();
|
||||
if (!GetUserFileNameForRead) return false;
|
||||
char buf[4096];
|
||||
buf[0] = '\0';
|
||||
// defext spelled without the dot, matching Win32 lpstrDefExt. [verify — DAW]
|
||||
// whether REAPER's picker applies it to the shown filter.
|
||||
if (!GetUserFileNameForRead(buf, "Import bank package", "rsbank")) return false;
|
||||
outAbsPath = buf;
|
||||
return !outAbsPath.empty();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
bool pickPackageSavePath(const std::string& suggestedFileName, std::string& outAbsPath) {
|
||||
outAbsPath.clear();
|
||||
|
||||
wchar_t file[4096];
|
||||
file[0] = L'\0';
|
||||
if (!suggestedFileName.empty()) {
|
||||
const int wrote = MultiByteToWideChar(CP_UTF8, 0, suggestedFileName.c_str(),
|
||||
-1, file, 4096);
|
||||
if (wrote <= 0) file[0] = L'\0'; // unconvertible suggestion -> empty box
|
||||
}
|
||||
|
||||
OPENFILENAMEW ofn{};
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = GetMainHwnd ? GetMainHwnd() : nullptr;
|
||||
ofn.lpstrFilter =
|
||||
L"ReaSampler bank package (*.rsbank)\0*.rsbank\0All files (*.*)\0*.*\0";
|
||||
ofn.lpstrFile = file;
|
||||
ofn.nMaxFile = 4096;
|
||||
ofn.lpstrTitle = L"Export bank package";
|
||||
ofn.lpstrDefExt = L"rsbank";
|
||||
// NOCHANGEDIR: REAPER's process-wide working directory is not ours to move.
|
||||
ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR |
|
||||
OFN_HIDEREADONLY;
|
||||
if (!GetSaveFileNameW(&ofn)) return false;
|
||||
|
||||
const int need =
|
||||
WideCharToMultiByte(CP_UTF8, 0, file, -1, nullptr, 0, nullptr, nullptr);
|
||||
if (need <= 0) return false;
|
||||
std::string utf8(static_cast<std::size_t>(need), '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0, file, -1, &utf8[0], need, nullptr, nullptr);
|
||||
if (!utf8.empty() && utf8.back() == '\0') utf8.pop_back();
|
||||
outAbsPath = std::move(utf8);
|
||||
return !outAbsPath.empty();
|
||||
}
|
||||
|
||||
#else // SWELL (macOS / Linux)
|
||||
|
||||
bool pickPackageSavePath(const std::string& suggestedFileName, std::string& outAbsPath) {
|
||||
outAbsPath.clear();
|
||||
// GetOpenFileName-style pair list; the literal's implicit terminator supplies the
|
||||
// closing double-NUL. [verify — DAW] the exact filter strings SWELL accepts.
|
||||
static const char kExtList[] = "ReaSampler bank package (*.rsbank)\0*.rsbank\0";
|
||||
char fn[4096];
|
||||
fn[0] = '\0';
|
||||
if (!BrowseForSaveFile("Export bank package", nullptr,
|
||||
suggestedFileName.empty() ? nullptr
|
||||
: suggestedFileName.c_str(),
|
||||
kExtList, fn, static_cast<int>(sizeof(fn)))) {
|
||||
return false;
|
||||
}
|
||||
outAbsPath = fn;
|
||||
return !outAbsPath.empty();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace reasampler
|
||||
Reference in New Issue
Block a user