e506d31b6278bb1251d8b260f75c67fa38c99a27 jcasper Thu Jul 23 10:20:01 2026 -0700 Making it possible for multiWig containers to be children of composites, refs #36320 diff --git src/hg/lib/trackDbCustom.c src/hg/lib/trackDbCustom.c index 77927d3a81d..a365a217bc9 100644 --- src/hg/lib/trackDbCustom.c +++ src/hg/lib/trackDbCustom.c @@ -1041,35 +1041,30 @@ /* Do subtrack hierarchy - filling in parent and subtracks fields. */ for (tdb = superlessList; tdb != NULL; tdb = next) { next = tdb->next; char *subtrackSetting = trackDbLocalSetting(tdb, "parent"); if (subtrackSetting != NULL && !tdbIsSuperTrackChild(tdb)) // superChildren cannot be in both subtracks list AND tdbList { char *parentName = cloneFirstWord(subtrackSetting); if (sameString(parentName, tdb->track)) errAbort("Track %s lists itself as its own parent", tdb->track); struct trackDb *parent = hashFindVal(trackHash, parentName); if (parent != NULL) { - if (trackDbLocalSetting(tdb, "container")) - { - errAbort("Composite track '%s' cannot have child track '%s'," - " which is a container multiWig.", parentName, tdb->track); - } slAddHead(&parent->subtracks, tdb); // composite/multiWig children are ONLY subtracks tdb->parent = parent; } else { errAbort("Parent track %s of child %s doesn't exist", parentName, tdb->track); } freez(&parentName); } else { slAddHead(&forest, tdb); } } @@ -1209,30 +1204,55 @@ rGetRefsToDescendantLeaves(pList, tdb->subtracks); else refAdd(pList, tdb); } } struct slRef *trackDbListGetRefsToDescendantLeaves(struct trackDb *tdbList) /* Return reference list all leaves in forest. Do slFreeList when done. */ { struct slRef *refList = NULL; rGetRefsToDescendantLeaves(&refList, tdbList); slReverse(&refList); return refList; } +static void rGetRefsToDescendantLeavesOrContainers(struct slRef **pList, struct trackDb *tdbList) +/* Like rGetRefsToDescendantLeaves, but stop at (and include) container (multiWig) nodes + * instead of descending into them. Still recurses through views and other non-container + * intermediate nodes. */ +{ +struct trackDb *tdb; +for (tdb = tdbList; tdb != NULL; tdb = tdb->next) + { + if (tdb->subtracks != NULL && trackDbLocalSetting(tdb, "container") == NULL) + rGetRefsToDescendantLeavesOrContainers(pList, tdb->subtracks); + else + refAdd(pList, tdb); // a leaf, or a container node we stop at + } +} + +struct slRef *trackDbListGetRefsToDescendantLeavesOrContainers(struct trackDb *tdbList) +/* Return reference list of all leaves in forest, plus any container (multiWig) nodes, + * not descending into containers. Do slFreeList when done. */ +{ +struct slRef *refList = NULL; +rGetRefsToDescendantLeavesOrContainers(&refList, tdbList); +slReverse(&refList); +return refList; +} + int trackDbCountDescendantLeaves(struct trackDb *tdb) /* Count the number of leaves in children list and their children. */ { struct slRef *leafRefs = trackDbListGetRefsToDescendantLeaves(tdb->subtracks); int result = slCount(leafRefs); slFreeList(&leafRefs); return result; } int trackDbRefCmp(const void *va, const void *vb) /* Do trackDbCmp on list of references as opposed to actual trackDbs. */ { const struct slRef *aRef = *((struct slRef **)va); const struct slRef *bRef = *((struct slRef **)vb); struct trackDb *a = aRef->val, *b = bRef->val;