// See view_reconcile.h. Compiled into the reaper_reasampler module; includes // reaper_plugin_functions.h without REAPERAPI_IMPLEMENT (main.cpp owns that). // The decision is pure (header, test_view_reconcile.cpp); this file owns the memo's // lifetime and the writes. #include "shell/view/view_reconcile.h" #include #include #include "shell/view/view_park.h" // trackFlagParm / writeIfChanged #include "shell/view/view_tracks.h" #define REAPERAPI_MINIMAL #define REAPERAPI_WANT_EnumProjects #define REAPERAPI_WANT_TrackList_AdjustWindows #define REAPERAPI_WANT_Undo_BeginBlock2 #define REAPERAPI_WANT_Undo_EndBlock2 #define REAPERAPI_WANT_UpdateArrange #define REAPERAPI_WANT_ValidatePtr2 #include "reaper_plugin_functions.h" namespace reasampler { namespace { // What the last apply left driven, per project. Keyed by ReaProject*, COMPARE-ONLY // and never dereferenced (the same discipline the panel's own project memos take): a // closed project's pointer must never be followed, only found unequal or used as a // map key. A project absent here gets no repair — the tool has no account of driving // anything there, so it has no opinion. Never pruned on project close: churn is a // handful of entries per session, cheap enough that a close hook would cost more than // it saves. One slot used to serve every project; a tab-switch mid-session silently // discarded whichever project's memo wasn't "current" — see planReconcilePerProject. std::map g_applied; } // namespace void noteAppliedState(ReaProject* proj, const ViewModeModel& model) { ReaProject* const project = proj ? proj : EnumProjects(-1, nullptr, 0); g_applied[project] = view::appliedState(model); } void reconcileAppliedFlags(ViewModeModel& model, ReaProject* proj) { ReaProject* const project = proj ? proj : EnumProjects(-1, nullptr, 0); if (!ValidatePtr2(nullptr, project, "ReaProject*")) return; const view::AppliedState reloaded = view::appliedState(model); const ProjectReconcileResult result = planReconcilePerProject(g_applied, project, reloaded); // Adopted whether or not anything is written: from here the memo describes the // project as it now stands, so a second reload cannot replay a repair that has // already happened over values the user has since changed. g_applied[project] = result.newEntry; if (result.ops.empty()) return; TrackHandles handleByGuid; readFolderEntries(project, handleByGuid); const TrackByGuid trackByGuid = indexHandles(handleByGuid); bool wrote = false; Undo_BeginBlock2(project); { UiRefreshHold uiHold; for (const TrackFlagOp& op : result.ops) { MediaTrack* tr = resolve(trackByGuid, op.guid); if (!tr) continue; // stale/deleted GUID — prune if (writeIfChanged(tr, trackFlagParm(op.flag), static_cast(op.value))) wrote = true; } } Undo_EndBlock2(project, "", 0); // discard form — see the header if (wrote) { TrackList_AdjustWindows(false); // tracks reappearing owe the full relayout UpdateArrange(); } } } // namespace reasampler