feat(view): D2 view shell — apply mode toggle plan to live project

Reads I_FOLDERDEPTH into a FolderTree (pure view_tree helper, unit-tested),
snapshots to-be-parked tracks before parking, runs the D1 planner, and applies
park/restore flag + per-FX-offline writes under an undo block. Master and
mute/solo untouched; acts only on tagged tracks.
This commit is contained in:
2026-07-22 20:55:50 -04:00
parent 2d040d6896
commit c068279aac
6 changed files with 448 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
#pragma once
// view — the REAPER-facing shell of the Design View feature (Phase D2). It is the
// mirror of the capture shell: the ViewModeModel (pure, D1) holds the mode/
// membership/snapshot state and emits the toggle plan; this shell reads the live
// project's folder tree, snapshots the tracks it is about to park, runs the model's
// planner, and applies the resulting flag + per-FX-offline writes to REAPER.
//
// It includes view_mode_model (pure) but NO REAPER headers — the .cpp is the one
// REAPER-facing translation unit (CLAUDE.md §contract: only main.cpp defines the
// API pointers; every other .cpp gets them extern). Callers (persist, actions)
// depend on this seam without dragging the SDK into their include sites.
//
// Hard invariants this shell enforces (CONTEXT.md §Design View, precision
// invariants) — verified in self-review, never crossed:
// * Never touches the master track's visibility (SDK forbids B_SHOWINTCP/
// B_SHOWINMIXER on master); the master is never a node in the tree.
// * Never reads or writes B_MUTE / I_SOLO on any track.
// * Acts only on tracks the model owns (tagged leaves the planner names) plus
// derived parents' visibility — never an untagged track's owned flags.
// * Snapshots every to-be-parked track's prior flags BEFORE parking, storing
// them into the model so restore is faithful and survives a save-while-parked.
#include <string>
#include "view_mode_model.h"
// REAPER's opaque project handle. Forward-declared to keep this header SDK-free;
// the .cpp includes reaper_plugin_functions.h and sees the real class.
class ReaProject;
namespace reasampler {
// Applies `targetModeId` to the live project `proj`:
// 1. Reads the arrange-ordered track list, builds the FolderTree from
// I_FOLDERDEPTH (via the pure buildFolderTree helper).
// 2. Runs model.planToggle(tree, targetModeId).
// 3. For each track about to be PARKED: snapshots its current B_SHOWINTCP /
// B_SHOWINMIXER / B_MAINSEND / I_FXEN and per-FX offline state, stores the
// snapshot into the model, THEN applies the park writes (expanding the
// 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`.
// All track mutations are wrapped in Undo_BeginBlock2 / Undo_EndBlock2.
//
// Returns false (no mutation, active mode unchanged) if `targetModeId` is not a
// registered mode. `proj` may be nullptr to mean REAPER's current project.
bool applyMode(ViewModeModel& model, const std::string& targetModeId, ReaProject* proj);
} // namespace reasampler