3faf76c42e6b5c97939abd34d88cb55da515418e
braney
  Mon Jul 11 19:12:27 2011 -0700
put hub track groups up top with user tracks.
diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index ba723a1..db14d38 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -3761,85 +3761,110 @@
 /* Determine if any member tracks are visible -- currently
  * recording this in the parent's visibility setting */
 {
 tdb->visibility = tvDense;
 }
 
 boolean superTrackHasVisibleMembers(struct trackDb *tdb)
 /* Determine if any member tracks are visible -- currently
  * recording this in the parent's visibility setting */
 {
 if (!tdbIsSuper(tdb))
     return FALSE;
 return (tdb->visibility != tvHide);
 }
 
+int hubCmpAlpha(const void *va, const void *vb)
+/* Compare to sort hubs based on name */
+{
+const struct trackHub *a = *((struct trackHub **)va);
+const struct trackHub *b = *((struct trackHub **)vb);
+
+return strcmp(a->shortLabel, b->shortLabel);
+}
+
 static void groupTracks(struct trackHub *hubList, struct track **pTrackList,
 	struct group **pGroupList, int vis)
 /* Make up groups and assign tracks to groups.
  * If vis is -1, restore default groups to tracks. */
 {
 struct group *unknown = NULL;
 struct group *group, *list = NULL;
 struct hash *hash = newHash(8);
 struct track *track;
 struct trackRef *tr;
 struct grp* grps = hLoadGrps(database);
 struct grp *grp;
-float maxPriority = 0;
+float minPriority = 100000; // something really large
 
 /* build group objects from database. */
 for (grp = grps; grp != NULL; grp = grp->next)
     {
     /* deal with group reordering */
     float priority = grp->priority;
-    if (priority > maxPriority) maxPriority = priority;
+    // we want to get the minimum priority over 1 (which is custom tracks)
+    if ((priority > 1.0) && (priority < minPriority)) minPriority = priority;
     if (withPriorityOverride)
         {
         char cartVar[512];
         safef(cartVar, sizeof(cartVar), "%s.priority",grp->name);
         if (vis != -1)
             priority = (float)cartUsualDouble(cart, cartVar, grp->priority);
         if (priority == grp->priority)
             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;
     slAddHead(&list, group);
     hashAdd(hash, grp->name, group);
     }
 grpFreeList(&grps);
 
 /* build group objects from hub */
     {
+    int count = slCount(hubList);
+
+    if (count) // if we have track hubs
+	{
+	slSort(&hubList, hubCmpAlpha);	// alphabetize
+	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
+	double priorityInc = (0.9 * minPriority) / count;
+	double priority = 1.0 + priorityInc;
+
     struct trackHub *hub;
     for (hub = hubList; hub != NULL; hub = hub->next)
         {
 	AllocVar(group);
 	group->name = cloneString(hub->name);
 	group->label = cloneString(hub->shortLabel);
-	maxPriority += 1;
-	group->defaultPriority = group->priority = maxPriority;
+	    group->defaultPriority = group->priority = priority;
+	    priority += priorityInc;
 	slAddHead(&list, group);
 	hashAdd(hash, group->name, group);
 	}
     }
+    }
 
 /* Loop through tracks and fill in their groups.
  * If necessary make up an unknown group. */
 for (track = *pTrackList; track != NULL; track = track->next)
     {
     /* handle track reordering feature -- change group assigned to track */
     if (withPriorityOverride)
         {
         char *groupName = NULL;
         char cartVar[256];
 
         /* belt and suspenders -- accomodate inconsistent track/trackDb
          * creation.  Note -- with code cleanup, these default variables
          * could be retired, and the tdb versions used as defaults */
         if (!track->defaultGroupName)
@@ -5013,31 +5038,30 @@
 	   "more compact modes.</td>\n", MAX_CONTROL_COLUMNS - 2);
 
 	hPrintf("<td align='right'>");
 	hButtonWithOnClick("hgt.expandGroups", "expand all", "expand all track groups", "return setAllTrackGroupVisibility(true)");
 	hPrintf("</td></tr>");
 
 	if (!hIsGsidServer())
 	    {
 	    cg = startControlGrid(MAX_CONTROL_COLUMNS, "left");
 	    }
 	else
 	    {
 	    /* 4 cols fit GSID's display better */
 	    cg = startControlGrid(4, "left");
 	    }
-	boolean isFirstNotCtGroup = TRUE;
 	for (group = groupList; group != NULL; group = group->next)
 	    {
 	    if (group->trackList == NULL)
 		continue;
 
 	    struct trackRef *tr;
 
 	    /* check if group section should be displayed */
 	    char *otherState;
 	    char *indicator;
 	    char *indicatorImg;
 	    boolean isOpen = !isCollapsedGroup(group);
 	    collapseGroupGoodies(isOpen, TRUE, &indicatorImg,
 				    &indicator, &otherState);
 	    hPrintf("<TR>");
@@ -5045,50 +5069,49 @@
 	    if (!hIsGsidServer())
                 hPrintf("<th align=\"left\" colspan=%d class='blueToggleBar'>",MAX_CONTROL_COLUMNS);
 	    else
                 hPrintf("<th align=\"left\" colspan=%d class='blueToggleBar'>",MAX_CONTROL_COLUMNS-1);
 
             hPrintf("<table style='width:100%%;'><tr><td style='text-align:left;'>");
             hPrintf("\n<A NAME=\"%sGroup\"></A>",group->name);
             hPrintf("<IMG class='toggleButton' onclick=\"return toggleTrackGroupVisibility(this, '%s');\" id=\"%s_button\" src=\"%s\" alt=\"%s\" title='%s this group'>&nbsp;&nbsp;",
                     group->name, group->name, indicatorImg, indicator,isOpen?"Collapse":"Expand");
             hPrintf("</td><td style='text-align:center; width:90%%;'>\n<B>%s</B>", group->label);
             hPrintf("</td><td style='text-align:right;'>\n");
             hPrintf("<input type='submit' name='hgt.refresh' value='refresh' title='Update image with your changes'>\n");
             hPrintf("</td></tr></table></th>\n");
 	    controlGridEndRow(cg);
 
-	    /* First track group that is not custom track group gets ruler,
+	    /* First track group that is not the custom track group (#1)
+	     * or a track hub, gets the Base Position track
 	     * unless it's collapsed. */
-	    if (!showedRuler && isFirstNotCtGroup &&
+	    if (!showedRuler && !isHubTrack(group->name) && 
 			differentString(group->name, "user"))
 		{
 		char *url = trackUrl(RULER_TRACK_NAME, chromName);
 		showedRuler = TRUE;
 		myControlGridStartCell(cg, isOpen, group->name);
 		hPrintf("<A HREF=\"%s\">", url);
 		hPrintf(" %s<BR> ", RULER_TRACK_LABEL);
 		hPrintf("</A>");
 		hDropListClassWithStyle("ruler", rulerMenu,
 			sizeof(rulerMenu)/sizeof(char *), rulerMenu[rulerMode],
 			rulerMode == tvHide ? "hiddenText" : "normalText",
 			TV_DROPDOWN_STYLE);
 		controlGridEndCell(cg);
 		freeMem(url);
 		}
-	    if (differentString(group->name, "user"))
-		isFirstNotCtGroup = FALSE;
 
 	    /* Add supertracks to  track list, sort by priority and
 	     * determine if they have visible member tracks */
 	    groupTrackListAddSuper(cart, group);
 
 	    /* Display track controls */
 	    for (tr = group->trackList; tr != NULL; tr = tr->next)
 		{
 		struct track *track = tr->track;
 		if (tdbIsSuperTrackChild(track->tdb))
 		    /* don't display supertrack members */
 		    continue;
 		myControlGridStartCell(cg, isOpen, group->name);
 		if (track->hasUi)
 		    {