f9c9519372b406cf392f199cdd23d1b032fa8e22
braney
  Tue Jun 3 12:02:11 2025 -0700
put quickLifted tracks in the right order and with the right
visibilities

diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c
index d5f10976ee6..c94873984bd 100644
--- src/hg/lib/trackHub.c
+++ src/hg/lib/trackHub.c
@@ -1606,92 +1606,94 @@
     enabled = TRUE;
 return enabled;
 }       
             
         
 static void dumpTdbAndChildren(struct cart *cart, struct dyString *dy, struct trackDb *tdb)
 /* Put a trackDb entry into a dyString, stepping up the tree for some variables. */
 {
 struct hashCookie cookie = hashFirst(tdb->settingsHash);
 struct hashEl *hel;
 dyStringPrintf(dy, "visibility %s\n", hStringFromTv(tdb->visibility));
 while ((hel = hashNext(&cookie)) != NULL)
     {   
     if (differentString(hel->name, "track") && differentString(hel->name, "visibility"))
         {
-        if (sameString(hel->name, "parent") )
-            dyStringPrintf(dy, "parent %s on\n", tdb->parent->track);
-        else if (sameString(hel->name, "html"))
+        if (sameString(hel->name, "html"))
             dyStringPrintf(dy, "%s %s\n", hel->name, trackHubSkipHubName((char *)hel->val));
         else
             dyStringPrintf(dy, "%s %s\n", hel->name, ((char *)hel->val));
         }
     }
 
 if (tdb->subtracks)
     {
     for (tdb = tdb->subtracks; tdb; tdb = tdb->next)
         {
         char *track =  trackHubSkipHubName(tdb->track);
         dyStringPrintf(dy, "\ntrack %s\nquickLifted on\n", track);
         if (!isVetted(track))
             dyStringPrintf(dy, "avoidHandler on\n");
         if (isParentVisible(cart, tdb) &&  isSubtrackVisible(cart, tdb)) // child of supertrack
             {
             char *cartVis = cartOptionalString(cart, tdb->parent->track);
             if (cartVis != NULL)
                 tdb->visibility = hTvFromString(cartVis);
-            //else if (tdbIsSuperTrack(tdb->parent))
-             //   tdb->visibility = tdb->parent->isShow;
             }
         dumpTdbAndChildren(cart, dy, tdb);
         }
     }
 }
 
 
 
 struct dyString *trackDbString(struct cart *cart, struct trackDb *tdb)
 /* Convert a trackDb entry into a dyString. */
 {
 struct dyString *dy;
 
 // add a note that the name based handler shouldn't be used on this track
 // add a note that this is a quickLifted track so the browser will accept tracks that aren't big*
 dy = dyStringNew(200);
 char *track =  trackHubSkipHubName(tdb->track);
 dyStringPrintf(dy, "track %s\nquickLifted on\n", track);
 
+if (tdbIsSuperTrack(tdb))
+    {
+    dyStringPrintf(dy, "superTrack on show\n");
+    }
+
 if (!isVetted(track))
     dyStringPrintf(dy, "avoidHandler on\n");
     
 dumpTdbAndChildren(cart, dy, tdb);
 
 return dy;
 }
 
 static boolean validateOneTdb(char *db, struct trackDb *tdb, struct trackDb **badList)
 /* Make sure the tdb is a track type we grok. */
 {
 if (!( startsWith("bigBed", tdb->type) || \
        startsWith("bigWig", tdb->type) || \
        startsWith("bigDbSnp", tdb->type) || \
        startsWith("bigGenePred", tdb->type) || \
        startsWith("gvf", tdb->type) || \
        startsWith("genePred", tdb->type) || \
        startsWith("narrowPeak", tdb->type) || \
        startsWith("bigLolly", tdb->type) || \
+       sameString("bed", tdb->type) ||
        startsWith("bed ", tdb->type)))
     {
     printf("%s %s<BR>\n",tdb->track,tdb->type);
     return FALSE;
     }
 
 // make sure we have a bigDataUrl
 if (startsWith("bigBed", tdb->type) || \
        startsWith("bigWig", tdb->type))
     {
     char *fileName = cloneString(trackDbSetting(tdb, "bigDataUrl"));
 
     if (fileName == NULL)
         {
         struct sqlConnection *conn = hAllocConnTrack(db, tdb);
@@ -1752,92 +1754,130 @@
 if (tdb->subtracks)
     {
     tdb->subtracks = validateTdbChildren(cart, db, tdb->subtracks, badList);
 
     if (tdb->subtracks == NULL)
         return FALSE;
     return TRUE;
     }
 
 return validateOneTdb(db, tdb, badList);
 }
 
 static void walkTree(FILE *f, char *db, struct cart *cart,  struct trackDb *tdb, struct dyString *visDy, struct trackDb **badList)
 /* walk tree looking for visible tracks. */
 {
+unsigned priority = 0;
+struct hash *haveSuper = newHash(0);
+char buffer[1024];
+
 for(; tdb; tdb = tdb->next)
     {
     boolean isVisible = FALSE;
 
     if (tdb->parent == NULL)  // not in super track
         {
         char *cartVis = cartOptionalString(cart, tdb->track);
         if (cartVis != NULL)
             {
             tdb->visibility = hTvFromString(cartVis);
             }
         isVisible =  tdb->visibility != tvHide;
         }
     else if (isParentVisible(cart, tdb) &&  isSubtrackVisible(cart, tdb)) // child of supertrack
+        {
+        if (hashLookup(haveSuper, tdb->parent->track) == NULL)  // output yet?
             {
             char *cartVis = cartOptionalString(cart, tdb->parent->track);
+            if (cartVis != NULL)
+                {
+                tdb->parent->visibility = hTvFromString(cartVis);
+                }
+            safef(buffer, sizeof buffer, "%d", priority++);
+            hashReplace(tdb->parent->settingsHash, "priority", cloneString(buffer));
+            struct dyString *dy = trackDbString(cart, tdb->parent);
+            fprintf(f, "%s\n", dy->string);
+
+            hashStore(haveSuper, tdb->parent->track);
+            }
+        char *cartVis = cartOptionalString(cart, tdb->track);
         if (cartVis != NULL)
             tdb->visibility = hTvFromString(cartVis);
-        else if (tdbIsSuperTrack(tdb->parent))
-            tdb->visibility = tdb->parent->isShow;
-        isVisible = TRUE;
+        isVisible =  tdb->visibility != tvHide;
         }
 
     if (isVisible && validateTdb(cart, db, tdb, badList))
         {
-        dyStringPrintf(visDy, "&%s=%s", trackHubSkipHubName(tdb->track),hStringFromTv(tdb->visibility));
-        //if (hashLookup(tdb->settingsHash, "customized") == NULL)
-            {
-            hashRemove(tdb->settingsHash, "maxHeightPixels");
-            hashRemove(tdb->settingsHash, "superTrack");
-            hashRemove(tdb->settingsHash, "subGroups");
-            hashRemove(tdb->settingsHash, "polished");
-            hashRemove(tdb->settingsHash, "noInherit");
-            hashRemove(tdb->settingsHash, "group");
-            hashRemove(tdb->settingsHash, "parent");
-            }
+        hashRemove(tdb->settingsHash, "superTrack");   // this gets inherited by subTracks(?)
 
-        //hashReplace(tdb->settingsHash, "customized", "on");
+        safef(buffer, sizeof buffer, "%d", priority++);
+        hashReplace(tdb->settingsHash, "priority", cloneString(buffer));
 
         // is this a custom track?
         char *tdbType = trackDbSetting(tdb, "tdbType");
         if (tdbType != NULL)
             {
             hashReplace(tdb->settingsHash, "type", tdbType);
             hashReplace(tdb->settingsHash, "shortLabel", trackDbSetting(tdb, "name"));
             hashReplace(tdb->settingsHash, "longLabel", trackDbSetting(tdb, "description"));
             }
 
         struct dyString *dy = trackDbString(cart, tdb);
 
         fprintf(f, "%s\n", dy->string);
         }
     }
 }
 
+static int cmpPriority(const void *va, const void *vb)
+/* Compare to sort based on priority; use shortLabel as secondary sort key. */
+{
+const struct trackDb *a = *((struct trackDb **)va);
+const struct trackDb *b = *((struct trackDb **)vb);
+float dif = 0;
+
+dif = a->groupPriority - b->groupPriority;
+if (dif == 0)
+    dif = a->priority - b->priority;
+if (dif < 0)
+   return -1;
+else if (dif == 0.0)
+    /* secondary sort on label */
+    return strcasecmp(a->shortLabel, b->shortLabel);
+else
+   return 1;
+}
+
 char *trackHubBuild(char *db, struct cart *cart, struct dyString *visDy, struct trackDb **badList)
 /* Build a track hub using trackDb and the cart. */
 {
-struct  trackDb *tdbList;
+struct  trackDb *tdbList, *tdb;
 struct grp *grpList;
 cartTrackDbInit(cart, &tdbList, &grpList, FALSE);
 
+struct hash *groupHash = newHash(0);
+struct grp *grp;
+for(grp = grpList; grp; grp = grp->next)
+    hashAdd(groupHash, grp->name, grp);
+
+for(tdb = tdbList; tdb; tdb = tdb->next)
+    {
+    grp = hashFindVal(groupHash, tdb->grp);
+    tdb->groupPriority = grp->priority;
+    }
+slSort(&tdbList, cmpPriority);
+
 char *filename = getHubName(cart, db);
 
 FILE *f = mustOpen(filename, "a");
 chmod(filename, 0666);
 
 walkTree(f, db, cart, tdbList, visDy, badList);
 fclose(f);
 
 return cloneString(filename);
 }
 
 struct grp *trackHubGetGrps()
 /* Get the groups defined by attached track hubs. */
 {
 return trackHubGrps;