From 27d887671cf1f7aa2673d38d278fa129af16463f Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Wed, 22 Jul 2026 21:08:31 -0400 Subject: [PATCH] fix(view): derive parent/folder visibility on mode toggle applyMode now drives B_SHOWINTCP/B_SHOWINMIXER for every parent node from visibleTracks(tree, targetMode); parents are never parked. Adds restoreFxOffline by-index remap hazard note. --- src/view.cpp | 22 ++++++++++++++++++++++ src/view.h | 5 ++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/view.cpp b/src/view.cpp index dcf42f4..400a25b 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -10,6 +10,7 @@ #include "view.h" +#include #include #include @@ -127,6 +128,12 @@ void parkFxOffline(MediaTrack* tr) { // Restores per-FX offline from the snapshot verbatim — each slot back to its // captured value, never a blanket "online". Bounds-checked against the live FX // count in case the plugin chain changed while parked (prune-safe). +// +// HAZARD (deferred, PLAN "reconcile on delete/restructure"): the remap is by +// slot INDEX, not plugin identity. If the FX chain changed while the track was +// parked, snapshot slot k is restored onto whatever plugin now occupies slot k — +// the bounds-check guards against out-of-range, not against a reshuffled chain. +// Acceptable for D2; full identity-based reconciliation is future hardening. void restoreFxOffline(MediaTrack* tr, const std::vector& fxOffline) { int fxCount = TrackFX_GetCount(tr); for (const FxOfflineOp& op : fxOffline) { @@ -179,6 +186,21 @@ bool applyMode(ViewModeModel& model, const std::string& targetModeId, ReaProject model.clearSnapshot(guid); } + // PARENT VISIBILITY (derived, never parked): a folder is visible iff at least + // one of its descendant leaves is visible in the target mode. That derivation is + // pure (membership + active mode), so it is recomputed every toggle rather than + // snapshotted — the four leaf-park flags don't apply to parents. Drive only the + // two visibility flags; never touch B_MAINSEND/I_FXEN/FX-offline on a parent. + std::set visible = model.visibleTracks(tree, targetModeId); + for (const FolderNode& node : tree.nodes) { + if (!node.isParent) continue; + MediaTrack* tr = resolve(handleByGuid, node.guid); + if (!tr) continue; // stale GUID — prune + double show = visible.count(node.guid) ? 1.0 : 0.0; + SetMediaTrackInfo_Value(tr, "B_SHOWINTCP", show); + SetMediaTrackInfo_Value(tr, "B_SHOWINMIXER", show); + } + model.setActiveMode(targetModeId); Undo_EndBlock2(proj, "ReaSampler: apply Design View mode", -1); diff --git a/src/view.h b/src/view.h index ec66f83..1b1d248 100644 --- a/src/view.h +++ b/src/view.h @@ -40,7 +40,10 @@ namespace reasampler { // per-FX offline loop from TrackFX_GetCount, which the pure plan leaves empty). // 4. For each track to RESTORE: applies the plan's snapshot-sourced flag + per-FX // offline writes verbatim. -// 5. Sets the model's active mode to `targetModeId`. +// 5. For each PARENT (folder) node: drives B_SHOWINTCP / B_SHOWINMIXER to 1 if the +// parent is in model.visibleTracks(tree, targetModeId), else 0 — derived from +// membership, never parked/snapshotted. Only the two visibility flags. +// 6. Sets the model's active mode to `targetModeId`. // All track mutations are wrapped in Undo_BeginBlock2 / Undo_EndBlock2. // // Returns false (no mutation, active mode unchanged) if `targetModeId` is not a