db7c8abb6d7674bb26f579eabb58bc080ce76fdd
max
  Tue May 12 07:04:05 2020 -0700
adding a protease track to uniprot, refs #25192

diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index c4482a2..86ee78b 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -4025,56 +4025,67 @@
 	{
 	if (*styler == '#') // Legacy: just the color that follows
 	    printf(" style='color: %s;'",styler);
 	else
 	    printf(" style='%s'",styler);
 	}
     }
 printf(">%s</OPTION>\n",label);
 }
 
 static boolean filterByColumnIsList(struct cart *cart, struct trackDb *tdb,  char *setting)
 /* Is this filter setting expecting a list of items (e.g. has checkboxes) */
 {
 return (sameString(setting, FILTERBY_SINGLE_LIST) ||
         sameString(setting, FILTERBY_MULTIPLE_LIST_OR) ||
+        sameString(setting, FILTERBY_MULTIPLE_LIST_ONLY_OR) ||
+        sameString(setting, FILTERBY_MULTIPLE_LIST_ONLY_AND) ||
         sameString(setting, FILTERBY_MULTIPLE_LIST_AND));
 }
 
 static boolean filterByColumnIsMultiple(struct cart *cart, struct trackDb *tdb,  char *setting)
 /* Is this filter setting for a comma separated column. */
 {
 return (sameString(setting, FILTERBY_MULTIPLE) ||
         sameString(setting, FILTERBY_MULTIPLE_LIST_OR) ||
+        sameString(setting, FILTERBY_MULTIPLE_LIST_ONLY_OR) ||
+        sameString(setting, FILTERBY_MULTIPLE_LIST_ONLY_AND) ||
         sameString(setting, FILTERBY_MULTIPLE_LIST_AND));
 }
 
+static boolean filterByColumnAllowsMatch(struct cart *cart, struct trackDb *tdb,  char *setting)
+/* Does this filter allow the "Only Match if ..." choice */
+{
+return  !(sameString(setting, FILTERBY_MULTIPLE_LIST_ONLY_OR) ||
+          sameString(setting, FILTERBY_MULTIPLE_LIST_ONLY_AND));
+}
+
 void filterBySetCfgUiGuts(struct cart *cart, struct trackDb *tdb,
 		      filterBy_t *filterBySet, boolean onOneLine,
 		      char *filterTypeTitle, char *selectIdPrefix, char *allLabel, char *prefix)
 // Does the UI for a list of filterBy structure for either filterBy or highlightBy controls
 {
 if (filterBySet == NULL)
     return;
 
 #define FILTERBY_HELP_LINK "<A HREF=\"../goldenPath/help/multiView.html\" TARGET=ucscHelp>help</A>"
 int count = slCount(filterBySet);
 if (count == 1)
-    puts("<TABLE cellpadding=3><TR valign='top'>");
+    puts("<TABLE class='trackUiFilterTable'><TR valign='top'>");
 else
-    printf("<B>%s items by:</B> (select multiple categories and items - %s)"
-	   "<TABLE cellpadding=3><TR valign='bottom'>\n",filterTypeTitle,FILTERBY_HELP_LINK);
+    printf("<B>%s items by category:</B> "
+	   "<TABLE class='trackUiFilterTable'><TR valign='bottom'>\n",filterTypeTitle);
 
 #ifdef ADVANCED_BUTTON
 if (tdbIsBigBed(tdb))
     {
     char varName[1024];
     safef(varName, sizeof(varName), "%s.doAdvanced", tdb->track);
     puts("&nbsp;&nbsp;&nbsp;");
     printf("<a id='%s' style='text-decoration: underline; color: #121E9A' title='Show advanced options..'>%s<img src='../images/downBlue.png'/></a>" ,varName,"Advanced ");
     printf("<BR>");
     jsInlineF("$(function () { advancedSearchOnChange('%s'); });\n", varName);
     }
 #endif // ADVANCED_BUTTON
 
 
 filterBy_t *filterBy = NULL;
@@ -4084,42 +4095,52 @@
     jsIncludeFile("ui.dropdownchecklist.js",NULL);
     jsIncludeFile("ddcl.js",NULL);
     }
 
 // TODO: columnCount (Number of filterBoxes per row) should be configurable through tdb setting
 
 for (filterBy = filterBySet;  filterBy != NULL;  filterBy = filterBy->next)
     {
     puts("<TD>");
     char selectStatement[4096];
     char *setting =  getFilterType(cart, tdb, filterBy->column, FILTERBY_SINGLE_LIST);
     if (filterByColumnIsList(cart, tdb, setting))
         safef(selectStatement, sizeof selectStatement, " (select multiple items - %s)", FILTERBY_HELP_LINK);
     else
         selectStatement[0] = 0;
+
+    char *filterTitle = filterBy->title;
+    if (strchr(filterTitle, '|')!=NULL) {
+        // replace | character with the 0 byte
+        filterTitle = cloneString(filterTitle);
+        char *pipePt = strchr(filterTitle, '|');
+        *pipePt = '\0';
+    }
+
     if(count == 1)
-	printf("<B>%s by %s</B>%s",filterTypeTitle,filterBy->title,selectStatement);
+	printf("<B>%s by %s</B>%s",filterTypeTitle,filterTitle,selectStatement);
     else
-	printf("<B>%s</B>",filterBy->title);
+	printf("<B>%s</B>",filterTitle);
     puts("</TD>");
     }
 puts("</tr><tr>");
 for (filterBy = filterBySet;  filterBy != NULL;  filterBy = filterBy->next)
     {
     puts("<td>");
     char *setting =  getFilterType(cart, tdb, filterBy->column, FILTERBY_SINGLE_LIST);
-    if (filterByColumnIsMultiple(cart, tdb, setting) && filterByColumnIsList(cart, tdb, setting) && tdbIsBigBed(tdb))
+    if (filterByColumnIsMultiple(cart, tdb, setting) && filterByColumnIsList(cart, tdb, setting) && tdbIsBigBed(tdb) &&
+            filterByColumnAllowsMatch(cart, tdb, setting))
         {
         char cartSettingString[4096];
         safef(cartSettingString, sizeof cartSettingString, "%s.%s.%s", prefix,FILTER_TYPE_NAME_LOW, filterBy->column);
         printf("<div ><b>Match if  ");
         // ADVANCED BUTTON printf("<div class='advanced' style='display:none'><b>Match if  ");
         cgiMakeRadioButton(cartSettingString, FILTERBY_MULTIPLE_LIST_AND, sameString(setting, FILTERBY_MULTIPLE_LIST_AND));
         printf(" all ");
         cgiMakeRadioButton(cartSettingString, FILTERBY_MULTIPLE_LIST_OR, sameString(setting, FILTERBY_MULTIPLE_LIST_OR));
         printf(" one or more match</b></div> ");
         }
     puts("</td>");
     }
 puts("</tr><tr>");
 int ix=0;
 for (filterBy = filterBySet;  filterBy != NULL;  filterBy = filterBy->next, ix++)
@@ -4609,31 +4630,31 @@
 #define LARGE_COMPOSITE_CUTOFF 30
 
 static void printSubtrackListRadioButtons(char *parentTrack, int subCount, boolean displayAll)
 // Print radio buttons for all/select
 {
 printf("<B>List subtracks:&nbsp;");
 char javascript[JBUFSIZE];
 safef(javascript, sizeof(javascript),
       "showOrHideSelectedSubtracks(true);");
 char buffer[SMALLBUF];
 if (subCount > LARGE_COMPOSITE_CUTOFF)
     safef(buffer,SMALLBUF,"%s.displaySubtracks", parentTrack);
 else
     safecpy(buffer,SMALLBUF,"displaySubtracks");
 cgiMakeOnEventRadioButtonWithClass(buffer, "selected", !displayAll, "allOrOnly", "click", javascript);
-puts("only selected/visible &nbsp;&nbsp;");
+puts("only checked &nbsp;&nbsp;");
 safef(javascript, sizeof(javascript),
       "showOrHideSelectedSubtracks(false);");
 cgiMakeOnEventRadioButtonWithClass(buffer, "all", displayAll, "allOrOnly", "click", javascript);
 printf("all</B>");
 if (subCount > 5)
     printf("&nbsp;&nbsp;&nbsp;&nbsp;(<span class='subCBcount'></span>)");
 }
 
 static void printSubtrackTableHeader(struct trackDb *parentTdb, struct slRef *subtrackRefList,
 				struct subtrackConfigSettings *settings)
 /* Print header of subtrack table, including classes describing display appearance and behavior.
 Return number of columns */
 {
 boolean useDragAndDrop = settings->useDragAndDrop;
 sortOrder_t *sortOrder = settings->sortOrder;
@@ -5462,33 +5483,32 @@
     boxed = trackDbSettingOn(tdb,"boxedCfg");
     if (boxed)
         printf("<BR>");
     }
 if (boxed)
     {
     printf("<TABLE class='blueBox");
     char *view = tdbGetViewName(tdb);
     if (view != NULL)
         printf(" %s",view);
     printf("' style='background-color:%s;'><TR><TD>", COLOR_BG_ALTDEFAULT);
     if (title)
         printf("<CENTER><B>%s Configuration</B></CENTER>\n", title);
     }
 else if (title)
-    printf("<p><B>%s &nbsp;</b>", title );
-else
-    printf("<p>");
+    printf("<B>%s &nbsp;</b>", title );
+// a <p> is not necessary here / not clear why it was there. It lead to a huge space in the wrench box
 return boxed;
 }
 
 void cfgEndBox(boolean boxed)
 // Handle end of box and title for individual track type settings
 {
 if (boxed)
     puts("</td></tr></table>");
 }
 
 void wigOption(struct cart *cart, char *name, char *title, struct trackDb *tdb)
 /* let the user choose to see the track in wiggle mode */
 {
 printf("<BR><BR><B>Display data as a density graph:</B> ");
 boolean option = cartOrTdbBoolean(cart, tdb, "doWiggle", FALSE);
@@ -6080,34 +6100,34 @@
 if (max && limitMin
 && (int)(*limitMin) != NO_VALUE &&                             *max < *limitMin)  *max = *limitMin;
 }
 
 static boolean showScoreFilter(struct cart *cart, struct trackDb *tdb, boolean *opened,
                                boolean boxed, boolean parentLevel,char *name, char *title,
                                char *label, char *scoreName)
 // Shows a score filter control with minimum value and optional range
 {
 char *setting = trackDbSetting(tdb, scoreName);
 if (setting)
     {
     if (*opened == FALSE)
         {
         boxed = cfgBeginBoxAndTitle(tdb, boxed, title);
-        puts("<TABLE>");
+        puts("<TABLE class='hgTrackUiScoreFilterTable'>");
         *opened = TRUE;
         }
-    printf("<TR><TD align='right'><B>%s:</B><TD align='left'>",label);
+    printf("<TR><TD align='right'><B>Numeric Filter: %s </B><TD align='left'>",label);
     char varName[256];
     char altLabel[256];
     char *filterName = getScoreNameAdd(tdb, scoreName, _BY_RANGE);
     boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, filterName);
     double minLimit=NO_VALUE,maxLimit=NO_VALUE;
     double minVal=minLimit,maxVal=maxLimit;
     colonPairToDoubles(setting,&minVal,&maxVal);
     getScoreFloatRangeFromCart(cart,tdb,parentLevel,scoreName,&minLimit,&maxLimit,
                                                               &minVal,  &maxVal);
     filterName = getScoreNameAdd(tdb, scoreName, filterByRange ? _MIN:"");
     safef(varName, sizeof(varName), "%s.%s", name, filterName);
     safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange ? "Minimum " : ""),
           htmlEncode(htmlTextStripTags(label)));
     cgiMakeDoubleVarWithLimits(varName,minVal, altLabel, 0,minLimit, maxLimit);
     if (filterByRange)
@@ -6356,31 +6376,31 @@
         safef(cgiVar,sizeof(cgiVar),"%s.%s.%s",tdb->track,FILTER_TYPE_NAME_LOW, filter->fieldName);
         printf(" using ");
         printf("<SELECT name='%s'> ", cgiVar);
         printf("<OPTION %s>%s</OPTION>", sameString(setting, FILTERTEXT_WILDCARD) ? "SELECTED" : "",  FILTERTEXT_WILDCARD );
         printf("<OPTION %s>%s</OPTION>", sameString(setting, FILTERTEXT_REGEXP) ? "SELECTED" : "",  FILTERTEXT_REGEXP );
         printf("</SELECT>");
         printf("</P>");
         }
     }
 
 return count;
 }
 
 void scoreCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title,
                 int maxScore, boolean boxed)
-// Put up UI for filtering bed track based on a score
+// Put up UI for filtering bed track based on a score or any other fields defined by the filter* trackDb statements
 {
 char option[256];
 boolean parentLevel = isNameAtParentLevel(tdb,name);
 boolean skipScoreFilter = FALSE;
 
 // Numeric filters are first
 boolean isBoxOpened = FALSE;
 if (numericFiltersShowAll(db, cart, tdb, &isBoxOpened, boxed, parentLevel, name, title) > 0)
     skipScoreFilter = TRUE;
 
 if (textFiltersShowAll(db, cart, tdb))
     skipScoreFilter = TRUE;
 
 if (cartOptionalString(cart, "ajax") == NULL)
     {
@@ -8478,42 +8498,43 @@
 compositeUiByFilter(db, cart, parentTdb, formName);
 
 return TRUE;
 }
 
 static boolean compositeUiAllButtons(char *db, struct cart *cart, struct trackDb *parentTdb,
                                      char *formName)
 // UI for composite tracks: all/none buttons only (as opposed to matrix or lots of buttons
 {
 if (trackDbCountDescendantLeaves(parentTdb) <= 1)
     return FALSE;
 
 if (dimensionsExist(parentTdb))
     return FALSE;
 
-#define PM_BUTTON_GLOBAL "<IMG height=18 width=18 id='%s' src='../images/%s'>"
-#define PM_BUTTON_GLOBAL_JS "matSubCBsCheck(%s);"
-char id[256];
-safef(id, sizeof id, "btn_plus_all"); 
-printf(PM_BUTTON_GLOBAL, id, "add_sm.gif");
-jsOnEventByIdF("click", id, PM_BUTTON_GLOBAL_JS, "true");
-
-safef(id, sizeof id, "btn_minus_all"); 
-printf(PM_BUTTON_GLOBAL, id, "remove_sm.gif");
-jsOnEventByIdF("click", id, PM_BUTTON_GLOBAL_JS, "false");
-
-puts("&nbsp;<B>Select all subtracks</B><BR>");
+puts("<div style='margin-bottom:3px'>Use checkboxes below to show or hide subtracks. Use drop-downs to change their visibilities.</div>");
+puts("<B>All subtracks:</B> ");
+//#define PM_BUTTON_GLOBAL "<IMG height=18 width=18 id='%s' src='../images/%s'>"
+//#define PM_BUTTON_GLOBAL_JS "matSubCBsCheck(%s);"
+//char id[256];
+//safef(id, sizeof id, "btn_plus_all"); 
+//safef(id, sizeof id, "btn_plus_all"); 
+//printf(PM_BUTTON_GLOBAL, id, "add_sm.gif");
+//printf(PM_BUTTON_GLOBAL, id, "add_sm.gif");
+printf("<span style='margin-right:6px' class='link' id='btn_plus_all'>check</span>");
+printf("<span class='link' id='btn_minus_all'>uncheck</span>");
+jsOnEventByIdF("click", "btn_plus_all", "matSubCBsCheck(%s)", "true");
+jsOnEventByIdF("click", "btn_minus_all", "matSubCBsCheck(%s)", "false");
 return TRUE;
 }
 
 static boolean compositeUiNoMatrix(char *db, struct cart *cart, struct trackDb *parentTdb,
                                    char *formName)
 // UI for composite tracks: subtrack selection.  This is the default UI
 // without matrix controls.
 {
 int i, j, k;
 char *words[SMALLBUF];
 char option[SMALLBUF];
 int wordCnt;
 char *name, *value;
 char buttonVar[1024];
 char setting[] = "subGroupN";