99880a42ac57bb8b8aff144a9e4401c8a408b27b max Tue Aug 18 07:06:40 2026 -0700 hgTracks: derive BLAT Results group priority from hub increment, refs #38086 The synthetic BLAT Results track group was pinned to a hardcoded priority of 1.5. Hub groups, however, are assigned priorities dynamically starting at 1.0 + priorityInc and spanning up to 1.0 + 0.9*(minPriority-1), so when the smallest real group priority is high enough (e.g. map=2.0) some hub groups can land above 1.5 and the BLAT Results group is no longer guaranteed to sit directly below Custom Tracks -- it can be sandwiched among hub groups. Derive the group's priority from the same priorityInc the hub loop uses: place it at 1.0 + priorityInc/2, i.e. between Custom Tracks (1.0) and the first hub group (1.0 + priorityInc), so it always stays directly below Custom Tracks no matter how many hubs are connected. With no hubs, keep 1.5, which sits safely between Custom Tracks and the first real group. diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c index c9ef24b90c0..442d61d3c3f 100644 --- src/hg/hgTracks/hgTracks.c +++ src/hg/hgTracks/hgTracks.c @@ -7206,32 +7206,33 @@ cartRemove(cart, cartVar); } /* create group object; add to list and hash */ AllocVar(group); group->name = cloneString(grp->name); group->label = cloneString(grp->label); group->defaultPriority = grp->priority; group->priority = priority; group->defaultIsClosed = grp->defaultIsClosed; group->errMessage = grp->errMessage; slAddHead(&list, group); hashAdd(hash, grp->name, group); } grpFreeList(&grps); -double priorityInc; +double priorityInc = 0; double priority = 1.00001; +boolean haveHubs = (grpList != NULL); // grpList is consumed by the loop below, so capture this now if (grpList) { minPriority -= 1.0; // priority is 1-based // the idea here is to get enough room between priority 1 // (which is custom tracks) and the group with the next // priority number, so that the hub nestle inbetween the // custom tracks and everything else at the top of the list // of track groups priorityInc = (0.9 * minPriority) / slCount(grpList); priority = 1.0 + priorityInc; } for(; grpList; grpList = grpList->next) { AllocVar(group); group->name = cloneString(grpList->name); @@ -7249,39 +7250,44 @@ if (!foundMap) { AllocVar(group); group->name = cloneString("map"); group->label = cloneString("Mapping and Sequencing"); group->defaultPriority = priority; group->priority = priority; group->defaultIsClosed = FALSE; slAddHead(&list, group); hashAdd(hash, "map", group); } // The "BLAT Results" group holds BLAT-search result custom tracks (group=blat, tagged // blatResult=on), keeping them out of the generic Custom Tracks group so they are easy to find and // clear as a set. It is synthesized here rather than stored in the grp table; the group header is -// skipped when it has no tracks (see the group loop that draws the controls). Priority 1.5 places -// it just after Custom Tracks (priority 1) so BLAT users find their results near the top. Gated by -// hg.conf blatResultsGroup, the same flag hgBlat/hgc read before tagging tracks with group=blat. +// skipped when it has no tracks (see the group loop that draws the controls). Gated by hg.conf +// blatResultsGroup, the same flag hgBlat/hgc read before tagging tracks with group=blat. if (cfgOptionBooleanDefault("blatResultsGroup", FALSE)) { AllocVar(group); group->name = cloneString("blat"); group->label = cloneString("BLAT Results"); - group->defaultPriority = group->priority = 1.5; + // Place the group just after Custom Tracks (priority 1) so BLAT users find their results near + // the top. When hubs are attached their groups are spread across (1.0, 1.0 + 0.9*minPriority) + // starting at 1.0 + priorityInc, so a hardcoded 1.5 could land in the middle of them; instead + // slot BLAT Results at 1.0 + priorityInc/2, i.e. between Custom Tracks and the first hub group, + // so it stays directly below Custom Tracks no matter how many hubs are connected. With no hubs + // priorityInc is unset, but 1.5 sits safely between Custom Tracks and the first real group. + group->defaultPriority = group->priority = haveHubs ? (1.0 + priorityInc/2) : 1.5; group->defaultIsClosed = FALSE; slAddHead(&list, group); hashAdd(hash, "blat", group); } // The "Visible Tracks" group is now the default top group struct group *visible = NULL; AllocVar(visible); visible->name = "visible"; visible->label = "Visible Tracks"; visible->defaultPriority = priority; visible->priority = -1; visible->defaultIsClosed = FALSE; slAddHead(&list, visible); hashAdd(hash, "visible", visible);