diff --git a/src/actions.cpp b/src/actions.cpp index 94ce544..efb961f 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -34,6 +34,9 @@ #define REAPERAPI_MINIMAL #define REAPERAPI_WANT_CountSelectedTracks #define REAPERAPI_WANT_GetSelectedTrack +#define REAPERAPI_WANT_EnumProjects +#define REAPERAPI_WANT_Main_SaveProject +#define REAPERAPI_WANT_ShowConsoleMsg #include "reaper_plugin_functions.h" namespace reasampler { @@ -115,8 +118,44 @@ void reapplyActiveMode() { // state. Called after every state-changing Design View action so the view model // is not lost across save/close/reopen. Marking the project dirty is correct — // a Design View mutation is a project-level change the user should be prompted -// to save. Safe when there is no active/saved project (saveToActiveProject no-ops). +// to save. +// +// When the membership index is non-empty AND the project is unsaved, we prompt +// the user to Save-As before persisting — mirroring the flow capture uses. +// Gate: if membership is empty (no tracks tagged), skip the prompt entirely; +// saveToActiveProject will no-op for an unsaved project, which is correct. +// +// DAW-ONLY ASSUMPTION: Main_SaveProject(proj, true) opens a Save-As dialog and +// blocks until the user dismisses it. The blocking behaviour and dialog +// appearance can only be confirmed in a running REAPER (same caveat as capture). void persistViewState() { + if (!g_session->view().membership().empty()) { + // At least one track is tagged — worth persisting. Check whether the + // project is saved and, if not, prompt Save-As so saveToActiveProject + // can write ext state. Mirrors capture's readRppPath idiom exactly. + ReaProject* proj = EnumProjects(-1, nullptr, 0); + if (proj) { + auto readRppPath = [&]() -> std::string { + std::vector buf(4096, '\0'); + EnumProjects(-1, buf.data(), static_cast(buf.size())); + return std::string(buf.data()); + }; + + if (readRppPath().empty()) { + // Project is unsaved — prompt Save-As. + Main_SaveProject(proj, true); + // Re-read: still empty means the user cancelled. + if (readRppPath().empty()) { + ShowConsoleMsg( + "ReaSampler: Design View state will not persist until " + "the project is saved.\n"); + // The in-session tag state is left as-is — the mode change + // already applied and remains valid for this session. + return; + } + } + } + } g_session->saveToActiveProject(); }