fix(view): redraw arrange when inserted item lands on already-split lane

An item inserted onto an already-split folder in Design mode sat on the
correct lane but stayed invisible until a manual toggle: mintManagedLanes
returned on the idempotent no-op path before its UpdateArrange call. Force
the redraw there so the item appears immediately.
This commit is contained in:
2026-07-25 17:16:58 -04:00
parent a786915451
commit 47721a40c4
2 changed files with 63 additions and 4 deletions
+45
View File
@@ -1459,6 +1459,50 @@ static void testLaneMintingFolderOwnItemsSpanBothModes() {
CHECK(hasAssign(plan, "{d}", "{F}", kDesignModeId));
}
// -- Fix (pd2): item inserted onto an ALREADY-split folder still yields a non-empty plan --
//
// Regression guard for the "inserted item invisible until a manual toggle" bug. When a new
// item lands (via insert/capture) on a folder that is ALREADY lane-split and derived-visible
// in >1 mode, and REAPER placed it on the active mode's currently-playing lane, the shell's
// assignItemToLane sees I_FIXEDLANE unchanged and writes nothing — applyMintPlan reports
// changed==false. The shell must STILL treat this tick as "content landed on a managed track"
// and refresh the arrange (so the item draws immediately, no toggle). The pure signal the
// shell keys on is: planLaneMinting returns a NON-EMPTY plan carrying an assign for the new
// item. This test locks that signal; if planLaneMinting ever went empty here, the shell would
// have nothing to refresh on and the bug would return.
static void testLaneMintingNewItemOnAlreadySplitFolderYieldsPlan() {
ViewModeModel vm;
vm.membership().tag("{LD}", kDesignModeId); // Design leaf ⇒ folder derived-visible Design
// {LA} untagged ⇒ Arrange ⇒ folder ALSO derived-visible in Arrange (dual-visible).
vm.membership().tag("{own}", kDesignModeId); // the pre-existing own Design item
vm.membership().tag("{new}", kDesignModeId); // the JUST-INSERTED item (auto-tagged Design)
FolderTree tree;
tree.nodes.push_back(FolderNode{"{F}", "", /*isParent=*/true});
tree.nodes.push_back(FolderNode{"{LD}", "{F}", false});
tree.nodes.push_back(FolderNode{"{LA}", "{F}", false});
// The folder is already split for Design (its lane exists + is owned). This mirrors the
// live "already auto-split" track the bug reproduces on.
CHECK(vm.lanes().setManaged("{F}", laneNameForMode(kDesignModeId), kDesignModeId));
// {F} now carries its original own item PLUS the freshly-inserted one, both Design.
std::vector<LaneTrack> tracks{
LaneTrack{"{F}", {
LaneItem{"{own}", kDesignModeId, false},
LaneItem{"{new}", kDesignModeId, false},
}},
};
const LaneMintPlan plan = planLaneMinting(vm, tree, tracks);
// The plan is NON-EMPTY (folder is dual-visible ⇒ splits) and carries an assign for the
// new item onto the Design lane. In the shell this is the exact branch that must force a
// redraw even when the assign is an idempotent no-op (item already on the playing lane).
CHECK(!plan.empty());
CHECK(hasAssign(plan, "{new}", "{F}", kDesignModeId));
CHECK(hasAssign(plan, "{own}", "{F}", kDesignModeId));
}
// SHOW-BOTH escape hatch: a show-both track carrying its own items is visible in every
// mode ON PURPOSE and must NOT be force-split — its content stays cross-mode-visible.
// Even with own items that would otherwise span modes, the decision skips it entirely.
@@ -1631,6 +1675,7 @@ int main() {
testLaneMintingFolderDerivedVisibleSplitsOwnMedia();
testLaneMintingLazySingleLaneStillConfines();
testLaneMintingFolderOwnItemsSpanBothModes();
testLaneMintingNewItemOnAlreadySplitFolderYieldsPlan();
testLaneMintingShowBothNotForceSplit();
testLaneMintingSingleModeLeafVisibleOnceNoSplit();
testLaneMintingEmptyFolderNotSplit();