feat(view): mint managed lanes to separate cross-mode content per stance (D2 W3-A)

Pure planLaneMinting decides which tracks hold >1 mode's content and which managed
lane each item lands on; view.cpp applies it (I_FREEMODE/I_NUMFIXEDLANES/P_LANENAME/
I_FIXEDLANE) under one undo block, driven off the auto-tag detection tick. Manual lanes
and their items are never touched. Load-time reconcile rebuilds ownership from durable
lane names before reapplying active-mode visibility.
This commit is contained in:
2026-07-23 20:08:38 -04:00
parent fed70c0a80
commit b182146f9a
11 changed files with 673 additions and 4 deletions
+37
View File
@@ -52,4 +52,41 @@ namespace reasampler {
// registered mode. `proj` may be nullptr to mean REAPER's current project.
bool applyMode(ViewModeModel& model, const std::string& targetModeId, ReaProject* proj);
// Mints managed fixed lanes for any track in `proj` that now holds content of MORE
// THAN ONE mode, and assigns each item to its mode's managed lane (Phase D2 Wave 3).
// 1. Enumerates every track + its items; resolves each item's mode from the model's
// membership (untagged ⇒ Arrange) and reads whether it currently sits on a MANUAL
// lane (exempt).
// 2. Runs the pure planLaneMinting decision. A track with content of only one mode
// is left whole-track-parked (D1) — NOT lane-split.
// 3. For each track that must split: enables fixed-lane mode (I_FREEMODE=2), ensures
// enough fixed lanes (I_NUMFIXEDLANES), stamps each managed lane's durable name
// (P_LANENAME:n), records the lane MANAGED-for-its-mode in the model's ownership
// index, and assigns each managed-eligible item to its mode's lane (I_FIXEDLANE).
// Manual lanes and the items on them are NEVER minted-over or reassigned.
// 4. Reapplies the active mode's lane visibility so the just-minted lanes take their
// correct play/show state immediately (the active mode's lane plays; others hide).
// The whole structural mutation is wrapped in ONE Undo_BeginBlock2/EndBlock2 — but only
// when the plan is non-empty (no undo point for a tick that mints nothing).
//
// Returns true if any lane was minted this call (⇒ the caller may want a repaint).
// `proj` may be nullptr to mean REAPER's current project. READ of the membership index
// only; the sole model mutation is recording new managed-lane ownership.
bool mintManagedLanes(ViewModeModel& model, ReaProject* proj);
// Reconciles the model's lane-ownership index against the live project's lanes on
// project open (Phase D2 Wave 3). REAPER's durable P_LANENAME is the source of truth for
// lane identity across sessions (design point #2): a lane whose name carries the managed
// prefix is tool-managed and owned by the mode encoded in that name. This walks every
// track's lanes and records each managed-named lane MANAGED-for-its-mode in the index —
// self-healing a saved project's classification WITHOUT re-minting (it never creates a
// lane, changes I_FREEMODE/I_NUMFIXEDLANES, or reassigns an item) and WITHOUT mass-
// tagging (it never touches membership). A lane without the managed prefix is left
// untouched (manual by default). Reload's active-mode lane visibility is then reapplied
// by the caller's applyMode, mirroring D1's reapply-on-open.
//
// `proj` may be nullptr to mean REAPER's current project. The only model mutation is
// recording managed ownership recovered from durable lane names.
void reconcileManagedLanes(ViewModeModel& model, ReaProject* proj);
} // namespace reasampler