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:
+19
-4
@@ -753,8 +753,11 @@ void enumerateLiveGuids(ReaProject* proj, std::set<std::string>& allGuids,
|
||||
// persist.cpp writes it on the next project save alongside the bank and view state, the
|
||||
// same way an action-driven tag is persisted. Wrapping this in an Undo block would flood
|
||||
// the REAPER undo history with a new entry for every timer tick that sees new content.
|
||||
void detectNewContent() {
|
||||
if (!g_panel.session) return;
|
||||
// Returns true iff this tick tagged at least one new GUID into a mode — the signal the
|
||||
// caller uses to decide whether to run the lane-minting pass (a track can only newly
|
||||
// become multi-mode when auto-tag just placed content on it). No tag ⇒ nothing to mint.
|
||||
bool detectNewContent() {
|
||||
if (!g_panel.session) return false;
|
||||
|
||||
ReaProject* proj = EnumProjects(-1, nullptr, 0);
|
||||
|
||||
@@ -778,7 +781,7 @@ void detectNewContent() {
|
||||
enumerateLiveGuids(proj, live, itemOnManualLane);
|
||||
|
||||
const std::vector<std::string> added = g_panel.contentBaseline.observe(live);
|
||||
if (added.empty()) return; // first poll after open, or nothing new this tick
|
||||
if (added.empty()) return false; // first poll after open, or nothing new this tick
|
||||
|
||||
// Split the new GUIDs into tracks vs items so the pure decision can apply the
|
||||
// manual-lane exemption to items only. A GUID present in the item-lane map is an
|
||||
@@ -799,6 +802,7 @@ void detectNewContent() {
|
||||
autoTagNewContent(newTracks, newItems, model.activeModeId());
|
||||
for (const AutoTag& tag : tags)
|
||||
model.membership().tag(tag.guid, tag.modeId);
|
||||
return !tags.empty();
|
||||
}
|
||||
|
||||
// --- Audition preview ---------------------------------------------------------
|
||||
@@ -1245,7 +1249,18 @@ void bankPanelRefresh() {
|
||||
// tracks/items are created in the arrange view, not the panel, so detection must
|
||||
// not be gated on the dock being visible. READ-ONLY on the project; only mutates
|
||||
// the in-memory membership index (persist saves it like any action-driven tag).
|
||||
detectNewContent();
|
||||
const bool tagged = detectNewContent();
|
||||
|
||||
// Lane minting (D2 Wave 3) runs ONLY when detection just tagged new content — a
|
||||
// track can only newly become multi-mode when auto-tag placed content on it. Unlike
|
||||
// the invisible membership tag above, minting is a visible structural mutation
|
||||
// (I_FREEMODE/I_FIXEDLANE/P_LANENAME), so mintManagedLanes wraps it in its own Undo
|
||||
// block and only mints for tracks that hold >1 mode's content — a single-mode track
|
||||
// is left to D1 whole-track parking. Managed lanes only; manual lanes untouched.
|
||||
if (tagged && g_panel.session) {
|
||||
ReaProject* proj = EnumProjects(-1, nullptr, 0);
|
||||
mintManagedLanes(g_panel.session->view(), proj);
|
||||
}
|
||||
|
||||
if (!g_panel.open || !g_panel.hwnd) return;
|
||||
// Repaint only when the bank actually changed (generation bump). Cheap tick
|
||||
|
||||
Reference in New Issue
Block a user