30c398a790536f060e754cbb67226d30406f6912
braney
  Wed Nov 30 12:00:52 2016 -0800
Always put Base Position, Short Match, and Restriction Enymes tracks
into group map.  Make group map if it doesn't exit  #16170

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index 863c293..abbae1e 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -6208,82 +6208,100 @@
 }
 
 static void groupTracks(struct track **pTrackList,
 	struct group **pGroupList, struct grp *grpList, 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 minPriority = 100000; // something really large
+boolean foundMap = FALSE;
 
 /* build group objects from database. */
 for (grp = grps; grp != NULL; grp = grp->next)
     {
+    if (sameString(grp->name, "map"))
+        foundMap = TRUE;
     /* deal with group reordering */
     float priority = grp->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);
 
 double priorityInc;
-double priority;
+double priority = 1.00001;
 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);
     group->label = cloneString(grpList->label);
     group->defaultPriority = group->priority = priority;
     priority += priorityInc;
     slAddHead(&list, group);
     hashAdd(hash, group->name, group);
     }
+//
+// If there isn't a map group, make one and set the priority so it will be right after custom tracks
+// and hub groups.
+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);
+    }
+
 
 /* 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)
@@ -8062,35 +8080,32 @@
                     "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");
             if (isHubTrack(group->name))
                 hPrintf("<input name=\"hubDisconnectButton\""
                     "onClick="
                     "\" document.disconnectHubForm.elements['hubId'].value= '%s';"
                     "document.disconnectHubForm.submit();return true;\" "
                     "type=\"button\" value=\"disconnect\">\n", &group->name[sizeof hubTrackPrefix - 1]);
             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 the custom track group (#1)
-             * or a track hub, gets the Base Position track
-             * unless it's collapsed. */
-            if (!showedRuler && !isHubTrack(group->name) &&
-		    differentString(group->name, "user") )
+            /* Base Position track goes into map group, which will always exist. */
+            if (!showedRuler && sameString(group->name, "map") )
 		{
 		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);
 		}