d147153dbb70eb9018b248543b6f39dde939076a
tdreszer
  Fri Oct 7 16:52:46 2011 -0700
Another set of fixes propted by going through all of hg19 again and another 7 assemblies from different species and clades.
diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index f996832..cf1dad4 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -2474,40 +2474,36 @@
 // Weed out members of a subgroup without any subtracks, alters memory in place!
 {
 // First tally all subtrack counts
 int ixIn=0;
 struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks);
 struct trackDb *subtrack;
 members->subtrackCount    = needMem(members->count * sizeof(int));
 members->currentlyVisible = needMem(members->count * sizeof(int));
 members->subtrackList     = needMem(members->count * sizeof(struct slRef *));
 for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next)
     {
     subtrack = subtrackRef->val;
     char *belongsTo =NULL;
     if(subgroupFind(subtrack,members->groupTag,&belongsTo))
         {
-        for(ixIn=0;ixIn<members->count;ixIn++)
-            {
-            if(sameString(members->tags[ixIn],belongsTo))
+        if (-1 != (ixIn = stringArrayIx(belongsTo, members->tags, members->count)))
                 {
                 members->subtrackCount[ixIn]++;
                 if(cart && fourStateVisible(subtrackFourStateChecked(subtrack,cart)))
                     members->currentlyVisible[ixIn]++;
                 refAdd(&(members->subtrackList[ixIn]), subtrack);
-                break;
-                }
             }
         }
     }
 
 // Now weed out empty subgroup tags.  Can do this in place since new count <= old count
 // NOTE: Don't I wish I had made these as an slList ages ago! (tim)
 int ixOut=0;
 for(ixIn=ixOut;ixIn<members->count;ixIn++)
     {
     if(members->subtrackCount[ixIn] > 0)
         {
         if(ixOut < ixIn)
         {
             members->tags[ixOut]             = members->tags[ixIn];
             members->titles[ixOut]           = members->titles[ixIn];
@@ -2645,30 +2641,31 @@
 membersForAll->dimMax   = ixOut;
 membersForAll->abcCount = membersForAll->dimMax - dimA;
 
 return membersForAll;
 }
 
 static membersForAll_t* membersForAllSubGroupsGet(struct trackDb *parentTdb, struct cart *cart)
 /* Returns all the parents subGroups and members */
 {
 membersForAll_t *membersForAll = tdbExtrasMembersForAll(parentTdb);
 if(membersForAll != NULL)
     return membersForAll;  // Already retrieved, so don't do it again
 
 int ix;
 membersForAll = needMem(sizeof(membersForAll_t));
+if (tdbIsCompositeView(parentTdb->subtracks))  // view must have viewInMidle tdb in tree
 membersForAll->members[dimV]=subgroupMembersGet(parentTdb,"view");
 membersForAll->letters[dimV]='V';
 membersForAll->dimMax=dimA;  // This can expand, depending upon ABC dimensions
 membersForAll->dimensions = dimensionSettingsGet(parentTdb);
 if(membersForAll->dimensions != NULL)
     {
     for(ix=0;ix<membersForAll->dimensions->count;ix++)
         {
         char letter = lastChar(membersForAll->dimensions->names[ix]);
         if(letter != 'X' && letter != 'Y')
             {
             membersForAll->members[membersForAll->dimMax]=subgroupMembersGet(parentTdb, membersForAll->dimensions->subgroups[ix]);
             membersForAll->letters[membersForAll->dimMax]=letter;
             if(cart != NULL)
                 membersForAll->checkedTags[membersForAll->dimMax] = abcMembersChecked(parentTdb,cart,membersForAll->members[membersForAll->dimMax],letter);
@@ -3805,34 +3802,30 @@
 struct slRef *subtrackRef, *subtrackRefList = trackDbListGetRefsToDescendantLeaves(parentTdb->subtracks);
 
 // Look for dividers, heirarchy, dimensions, sort and dragAndDrop!
 char **lastDivide = NULL;
 dividers_t *dividers = dividersSettingGet(parentTdb);
 if (dividers)
     lastDivide = needMem(sizeof(char*)*dividers->count);
 hierarchy_t *hierarchy = hierarchySettingGet(parentTdb);
 
 membersForAll_t* membersForAll = membersForAllSubGroupsGet(parentTdb,NULL);
 int dimCount=0,di;
 for(di=0;di<membersForAll->dimMax;di++) { if (membersForAll->members[di]) dimCount++; }
 sortOrder_t* sortOrder = sortOrderGet(cart,parentTdb);
 boolean preSorted = FALSE;
 boolean useDragAndDrop = sameOk("subTracks",trackDbSetting(parentTdb, "dragAndDrop"));
-#ifdef SUBTRACK_CFG
-if (useDragAndDrop)
-    useDragAndDrop = (sortOrder == NULL); // Only support drag and drop when not sortable table
-#endif///def SUBTRACK_CFG
 char buffer[SMALLBUF];
 char *displaySubs = NULL;
 int subCount = slCount(subtrackRefList);
 #define LARGE_COMPOSITE_CUTOFF 30
 if (subCount > LARGE_COMPOSITE_CUTOFF)
     {
     safef(buffer,SMALLBUF,"%s.displaySubtracks",parentTdb->track);
     displaySubs = cartUsualString(cart, buffer,"some");              // track specific defaults to only selected
     }
 else
     {
     displaySubs = cartUsualString(cart, "displaySubtracks", "all");  // browser wide defaults to all
     }
 boolean displayAll = sameString(displaySubs, "all");
 
@@ -3996,55 +3989,60 @@
     preSorted = tdbRefSortPrioritiesFromCart(cart, &subtrackRefList); // preserves user's prev sort/drags
     printf("<TBODY class='%saltColors'>\n",(sortOrder != NULL ? "sortable " : "") );
     }
 else
     {
     slSort(&subtrackRefList, trackDbRefCmp);  // straight from trackDb.ra
     preSorted = TRUE;
     puts("<TBODY>");
     }
 
 // Finally the big "for loop" to list each subtrack as a table row.
 printf("\n<!-- ----- subtracks list ----- -->\n");
 for (subtrackRef = subtrackRefList; subtrackRef != NULL; subtrackRef = subtrackRef->next)
     {
     subtrack = subtrackRef->val;
-    int ix;
+    int ix,ix2;
 
     // Determine whether subtrack is checked, visible, configurable, has group membership, etc.
     int fourState = subtrackFourStateChecked(subtrack,cart);
     boolean checkedCB = fourStateChecked(fourState);
     boolean enabledCB = fourStateEnabled(fourState);
     boolean visibleCB = fourStateVisible(fourState);
     membership_t *membership = subgroupMembershipGet(subtrack);
-    eCfgType cType = cfgTypeFromTdb(subtrack,FALSE);
+    eCfgType cType = cfgNone;
+    if (!tdbIsMultiTrack(parentTdb))  // MultiTracks never have configurable subtracks!
+        cType = cfgTypeFromTdb(subtrack,FALSE);
     if (cType != cfgNone)
         {
     #ifdef SUBTRACK_CFG
         // Turn off configuring for certain track type or if explicitly turned off
         int cfgSubterack = configurableByPopup(subtrack,cType);
         if (cfgSubterack <= 0)
             cType = cfgNone;
-        else if (membersForAll->members[dimV])
-            {
+        else if (membersForAll->members[dimV]) // subtrack only configurable if more than one subtrack in view
+            {                                  // find "view" in subgroup membership: e.g. "signal"
             if (-1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count)))
-                {  // Don't make a configurable subtrack if there is only one in the view (assumes view is configurable)
-                if (slCount(membersForAll->members[dimV]->subtrackList[ix]) < 2)
+                {                              // find "signal" in set of all views
+                if (-1 != (ix2 = stringArrayIx(membership->membership[ix], membersForAll->members[dimV]->tags, membersForAll->members[dimV]->count)))
+                    {
+                    if (membersForAll->members[dimV]->subtrackCount[ix2] < 2)
                     cType = cfgNone;
                 }
             }
-        else if (slCount(parentTdb->subtracks) < 2 && cfgTypeFromTdb(parentTdb,FALSE) != cfgNone)
+            }
+        else if (slCount(subtrackRefList) < 2 && cfgTypeFromTdb(parentTdb,FALSE) != cfgNone)
             cType = cfgNone;  // don't bother if there is a single subtrack but the composite is configurable.
     #else///ifndef SUBTRACK_CFG
         if (trackDbSettingClosestToHomeOn(subtrack, "configurable") == FALSE)
             cType = cfgNone;
     #endif///ndef SUBTRACK_CFG
         }
 
     if (sortOrder == NULL && !useDragAndDrop)
         {
         if ( divisionIfNeeded(lastDivide,dividers,membership) )
             colorIx = (colorIx == COLOR_BG_DEFAULT_IX ? COLOR_BG_ALTDEFAULT_IX : COLOR_BG_DEFAULT_IX);
         }
 
     // Start the TR which must have an id that is directly related to the checkBox id
     char *id = checkBoxIdMakeForTrack(subtrack,membersForAll->members,membersForAll->dimMax,membership); // view is known tag
@@ -4071,46 +4069,50 @@
     // And finally the checkBox is made!
     safef(buffer, sizeof(buffer), "%s_sel", subtrack->track);
 #ifdef SUBTRACK_CFG
     if (!enabledCB)
         {
         dyStringAppend(dyHtml, " disabled");
         cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml),"onclick='matSubCbClick(this);' style='cursor:pointer' title='view is hidden'");
         }
     else
 #endif///def SUBTRACK_CFG
         cgiMakeCheckBoxFourWay(buffer,checkedCB,enabledCB,id,dyStringContents(dyHtml),"onclick='matSubCbClick(this);' style='cursor:pointer'");
     if (useDragAndDrop)
         printf("&nbsp;");
 
 #ifdef SUBTRACK_CFG
+    if (!tdbIsMultiTrack(parentTdb))  // MultiTracks never have independent vis
+        {
     enum trackVisibility vis = tdbVisLimitedByAncestors(cart,subtrack,FALSE,FALSE);
     char *view = NULL;
-    if (membersForAll->members[dimV] && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count)))
+        if (membersForAll->members[dimV]
+        && -1 != (ix = stringArrayIx(membersForAll->members[dimV]->groupTag, membership->subgroups, membership->count)))
         view = membership->membership[ix];
         char classList[256];
         if (view != NULL)
             safef(classList,sizeof(classList),"clickable fauxInput%s subVisDD %s",(visibleCB ? "":" disabled"),view); // view should be last!
         else
             safef(classList,sizeof(classList),"clickable fauxInput%s subVisDD",(visibleCB ? "":" disabled"));
         #define SUBTRACK_CFG_VIS "<div id= '%s_faux' class='%s' style='width:65px;' onclick='return subCfg.replaceWithVis(this,\"%s\",true);'>%s</div>\n"
         printf(SUBTRACK_CFG_VIS,subtrack->track,classList,subtrack->track,hStringFromTv(vis));
     if (cType != cfgNone)  // make a wrench
         {
         #define SUBTRACK_CFG_WRENCH "<span class='clickable%s' onclick='return subCfg.cfgToggle(this,\"%s\");' title='Configure this subtrack'><img src='../images/wrench.png'></span>\n"
         printf(SUBTRACK_CFG_WRENCH,(visibleCB ? "":" disabled"),subtrack->track);
         }
+        }
 #endif///def SUBTRACK_CFG
 
     // A hidden field to keep track of subtrack order if it could change
     if (sortOrder != NULL || useDragAndDrop)
         {
         safef(buffer, sizeof(buffer), "%s.priority", subtrack->track);
         float priority = (float)cartUsualDouble(cart, buffer, subtrack->priority);
         printf("<INPUT TYPE=HIDDEN NAME='%s' class='trPos' VALUE=\"%.0f\">", buffer, priority); // keeing track of priority
         }
 
     // A color patch which helps distinguish subtracks in some types of composites
     if (doColorPatch)
         {
         printf("<TD BGCOLOR='#%02X%02X%02X'>&nbsp;&nbsp;&nbsp;&nbsp;</TD>",
                 subtrack->colorR, subtrack->colorG, subtrack->colorB);
@@ -4968,32 +4970,34 @@
     if (filterByRange)
         {
         puts("<B>Filter score range:  min:</B>");
         snprintf(option, sizeof(option), "%s.%s", name,SCORE_FILTER _MIN);
         cgiMakeIntVarWithLimits(option, minVal, "Minimum score",0, minLimit,maxLimit);
         puts("<B>max:</B>");
         snprintf(option, sizeof(option), "%s.%s", name,SCORE_FILTER _MAX);
         cgiMakeIntVarWithLimits(option, maxVal, "Maximum score",0,minLimit,maxLimit);
         printf("(%d to %d)\n",minLimit,maxLimit);
         }
     else
         {
         printf("<b>Show only items with score at or above:</b> ");
         snprintf(option, sizeof(option), "%s.%s", name,SCORE_FILTER);
         cgiMakeIntVarWithLimits(option, minVal, "Minimum score",0, minLimit,maxLimit);
-        printf("&nbsp;&nbsp;(range: %d to %d)", minLimit, maxLimit);
+        printf("&nbsp;&nbsp;(range: %d to %d)\n", minLimit, maxLimit);
         }
+    if (glvlScoreMin)
+        printf("<BR>");
     }
 
 if (glvlScoreMin)
     scoreGrayLevelCfgUi(cart, tdb, name, maxScore);
 
 /* filter top-scoring N items in track */
 char *scoreCtString = trackDbSettingClosestToHome(tdb, "filterTopScorers");
 if (scoreCtString != NULL)
     {
     /* show only top-scoring items. This option only displayed if trackDb
      * setting exists.  Format:  filterTopScorers <on|off> <count> <table> */
     char *words[2];
     char *scoreFilterCt = NULL;
     chopLine(cloneString(scoreCtString), words);
     safef(option, sizeof(option), "%s.filterTopScorersOn", name);
@@ -5454,40 +5458,38 @@
 
 if(trackDbSettingClosestToHomeOn(tdb, "nmdFilter"))
     {
     boolean nmdDefault = FALSE;
     safef(varName, sizeof(varName), "hgt.%s.nmdFilter", name);
     nmdDefault = cartUsualBoolean(cart,varName, FALSE);  // TODO: var name (hgt prefix) needs changing before ClosesToHome can be used
     printf("<p><b>Filter out NMD targets.</b>");
     cgiMakeCheckBox(varName, nmdDefault);
     }
 
 if(!sameString(tdb->track, "tigrGeneIndex")
 && !sameString(tdb->track, "ensGeneNonCoding")
 && !sameString(tdb->track, "encodeGencodeRaceFrags"))
     baseColorDropLists(cart, tdb, name);
 
-if (cartOptionalString(cart, "ajax") == NULL)
-    {
     filterBy_t *filterBySet = filterBySetGet(tdb,cart,name);
     if(filterBySet != NULL)
         {
         printf("<BR>");
         filterBySetCfgUi(cart,tdb,filterBySet,FALSE);
         filterBySetFree(&filterBySet);
         }
-    }
+
 cfgEndBox(boxed);
 }
 
 static boolean isSpeciesOn(struct cart *cart, struct trackDb *tdb, char *species, char *option, int optionSize, boolean defaultState)
 /* check the cart to see if species is turned off or on (default is defaultState) */
 {
 boolean ret = defaultState;
 safef(option, optionSize, "%s.%s", tdb->track, species);
 
 /* see if this is a simple multiz (not composite track) */
 char *s = cartOptionalString(cart, option);
 if (s != NULL)
     ret =  (sameString(s, "on") || atoi(s) > 0);
 else
     {
@@ -6036,118 +6038,103 @@
     printf("<BR>\n");
     }
 cgiMakeRadioButton(cartVarName, BAM_COLOR_MODE_OFF, sameString(selected, BAM_COLOR_MODE_OFF));
 printf("No additional coloring");
 
 //TODO: include / exclude flags
 
 if (!boxed && fileExists(hHelpFile("hgBamTrackHelp")))
     printf("<P><A HREF=\"../goldenPath/help/hgBamTrackHelp.html\" TARGET=_BLANK>BAM "
 	   "configuration help</A></P>");
 
 cfgEndBox(boxed);
 }
 #endif//def USE_BAM
 
-struct trackDb *rFindViewInList(struct trackDb *tdbList, char *view)
-/* Return the trackDb on the list (or on any children of the list) that has matching view tag. */
+struct trackDb *rFindView(struct trackDb *forest, char *view)
+// Return the trackDb on the list that matches the view tag. Prefers ancestors before decendents
 {
 struct trackDb *tdb;
-for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
+for (tdb = forest; tdb != NULL; tdb = tdb->next)
     {
     char *viewSetting = trackDbSetting(tdb, "view");
     if (sameOk(viewSetting, view))
         return tdb;
     }
-for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
+for (tdb = forest; tdb != NULL; tdb = tdb->next)
     {
-    struct trackDb *viewTdb = rFindViewInList(tdb->subtracks, view);
+    struct trackDb *viewTdb = rFindView(tdb->subtracks, view);
     if (viewTdb != NULL)
         return viewTdb;
     }
 return NULL;
 }
 
 static boolean compositeViewCfgExpandedByDefault(struct trackDb *parentTdb,char *view,
 	char **retVisibility)
 /* returns true if the view cfg is expanded by default.  Optionally allocates string of view
  * setting (eg 'dense') */
 {
 boolean expanded = FALSE;
 if ( retVisibility != NULL )
     *retVisibility = cloneString(hStringFromTv(parentTdb->visibility));
-struct trackDb *viewTdb = rFindViewInList(parentTdb->subtracks, view);
+struct trackDb *viewTdb = rFindView(parentTdb->subtracks, view);
 if (viewTdb == NULL)
     return FALSE;
 if (retVisibility != NULL)
     *retVisibility = cloneString(hStringFromTv(viewTdb->visibility));
 if (trackDbSetting(viewTdb, "viewUi"))
     expanded = TRUE;
 return expanded;
 }
 
 enum trackVisibility visCompositeViewDefault(struct trackDb *parentTdb,char *view)
 /* returns the default track visibility of particular view within a composite track */
 {
 char *visibility = NULL;
 compositeViewCfgExpandedByDefault(parentTdb,view,&visibility);
 enum trackVisibility vis = hTvFromString(visibility);
 freeMem(visibility);
 return vis;
 }
 
-struct trackDb *rFindView(struct trackDb *forest, char *viewName)
-/* Find a descendent with given view. */
-{
-struct trackDb *tdb;
-for (tdb = forest; tdb != NULL; tdb = tdb->next)
-    {
-    char *viewSetting = trackDbSetting(tdb, "view");
-    if (sameOk(viewSetting, viewName))
-        return tdb;
-    struct trackDb *view = rFindView(tdb->subtracks, viewName);
-    if (view)
-        return view;
-    }
-return NULL;
-}
-
 static boolean hCompositeDisplayViewDropDowns(char *db, struct cart *cart, struct trackDb *parentTdb)
 /* UI for composite view drop down selections. */
 {
 int ix;
 char varName[SMALLBUF];
 char classes[SMALLBUF];
 char javascript[JBUFSIZE];
 #define CFG_LINK  "<B><A HREF=\"#a_cfg_%s\" onclick=\"return (showConfigControls('%s') == false);\" title=\"%s Configuration\">%s</A><INPUT TYPE=HIDDEN NAME='%s.%s.showCfg' value='%s'></B>"
 #define MAKE_CFG_LINK(name,title,tbl,open) printf(CFG_LINK, (name),(name),(title),(title),(tbl),(name),((open)?"on":"off"))
 
 membersForAll_t *membersForAll = membersForAllSubGroupsGet(parentTdb, cart); // membersForAll is generated once per track, then cached
 members_t *membersOfView = membersForAll->members[dimV];
 if(membersOfView == NULL)
     return FALSE;
 
 char configurable[membersOfView->count];
 memset(configurable,cfgNone,sizeof(configurable));
 int firstOpened = -1;
 boolean makeCfgRows = FALSE;
 struct trackDb **matchedViewTracks = needMem(sizeof(struct trackDb *)*membersOfView->count);
 
 for (ix = 0; ix < membersOfView->count; ix++)
     {
     char *viewName = membersOfView->tags[ix];
-    if (membersOfView->subtrackList != NULL && membersOfView->subtrackList[ix] != NULL)
+    if (membersOfView->subtrackList     != NULL
+    &&  membersOfView->subtrackList[ix] != NULL)
         {
         struct trackDb *subtrack = membersOfView->subtrackList[ix]->val;
         matchedViewTracks[ix] = subtrack->parent;
         configurable[ix] = (char)cfgTypeFromTdb(subtrack, TRUE);
         if(configurable[ix] != cfgNone)
             {
             if(firstOpened == -1)
                 {
                 safef(varName, sizeof(varName), "%s.%s.showCfg", parentTdb->track, viewName);
                 if(cartUsualBoolean(cart,varName,FALSE))
                     firstOpened = ix;
                 }
             makeCfgRows = TRUE;
             }
         }