#pragma once // REAPER-facing shell of Design View (D2): reads the live folder tree, runs // ViewModeModel's pure planner, and applies the resulting flag / per-FX / // lane writes. The .cpp is the sole REAPER-facing TU here (CLAUDE.md contract: // only main.cpp defines the API pointers). See src/shell/view/CLAUDE.md for // the enforced invariants (never touch master/mute, solo cached per mode and // never lost, snapshot-based restore). #include #include "core/view/view_mode_model.h" // Forward-declared to keep this header SDK-free; the .cpp includes the real SDK header. class ReaProject; namespace reasampler { // True while `proj`'s transport is playing or recording — the condition under which // applyMode refuses a real mode switch. Exposed so the panel can paint the footer's // [Arrange|Design] segments disabled BEFORE the click rather than only refusing on // it. `proj` is passed through to GetPlayStateEx as-is; the SDK documents proj=0 // meaning "current project" for GetTrack but is silent on GetPlayStateEx, so // `nullptr` meaning the current project here is inferred by analogy, not confirmed. bool transportBlocksModeSwitch(ReaProject* proj); // Does one applyMode leave an undo point behind? // // A REAPPLY that wrote nothing must not: the load-tick reapply over a project // saved fully parked re-plans a park for every inactive leaf and finds every // flag and every FX already where it wants them, so a point there would mean // opening a project costs an undo step. `Undo_EndBlock2(proj, "", 0)` is the // discard form (mintManagedLanes' no-op path uses the same idiom). // // A real switch mints regardless, fail-safe: it is an explicitly fired action // and has to stay undoable even in the degenerate case where the plan found // nothing to write. Note what applyMode CANNOT see when it decides — the // `view_state` ext-state write lands in persistViewState, after this block has // closed (src/shell/view/CLAUDE.md's Gotchas). inline bool applyMintsUndoPoint(bool realSwitch, bool wroteAnything) { return realSwitch || wroteAnything; } // True while an applyMode call is on the stack. applyMode fails closed when re-entered // (its FX writes are assumed to pump the message loop, so a timer tick or an action can // land inside one), and this lets a caller with no fallback test BEFORE it spends a // one-shot signal on a call that would be refused — see main.cpp's load glue. bool modeApplyInProgress(); // Snapshots each about-to-park track's flags into `model`, caches/clears the // outgoing mode's solo state and replays the incoming mode's, runs planToggle, // applies park/restore writes — flags AND per-FX offline, synchronously — plus // parent visibility flags, then sets the active mode. ONE switch is ONE undo // point; everything it moved rolls back in a single Ctrl-Z. Returns false (no // mutation) if `targetModeId` isn't registered, if this is a real switch // (target != active) while the transport is running, if it is re-entered // (modeApplyInProgress), or if the project does not validate. A reapply (target == // active) is never gated and never touches solo. `proj` == nullptr means the // current project, resolved ONCE and used for every call this apply makes. bool applyMode(ViewModeModel& model, const std::string& targetModeId, ReaProject* proj); // Splits any track visible in more than one mode while carrying its own media // into fixed lanes (one managed lane per involved mode), assigns items, and // records ownership in `model`. Never touches manual lanes. Runs planLaneMinting // (model + tree aware); wraps the mutation in one Undo block when non-empty. // Returns true if any lane was minted (repaint hint). `proj` == nullptr means // the current project. bool mintManagedLanes(ViewModeModel& model, ReaProject* proj); // Recovers managed-lane ownership from durable P_LANENAME on project open — // self-healing, without minting/reassigning anything and without touching // membership. A lane without the managed prefix is left untouched (manual). // `proj` == nullptr means the current project. void reconcileManagedLanes(ViewModeModel& model, ReaProject* proj); } // namespace reasampler