407acb3a94f347bb54698399584be6a1c085d62d
tdreszer
  Tue Feb 8 12:58:05 2011 -0800
Added support for background colors in filterBy.
diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index bc4eb1b..2d55f1f 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -3303,49 +3303,74 @@
     char *filter = cloneString(filters[ix]);
     filterBy_t *filterBy;
     AllocVar(filterBy);
     strSwapChar(filter,':',0);
     filterBy->column = filter;
     filter += strlen(filter) + 1;
     strSwapChar(filter,'=',0);
     filterBy->title = strSwapChar(filter,'_',' '); // Title does not have underscores
     filter += strlen(filter) + 1;
     if(filter[0] == '+') // values are indexes to the string titles
         {
         filter += 1;
         filterBy->useIndex = TRUE;
         }
     filterBy->valueAndLabel = (strchr(filter,'|') != NULL);
+    filterBy->colorFollows  = FALSE; // A color could be declared at the end of a filter value like "Level_2{#FF0099}"
+    char *color = strchr(filter,'{');
+    if (color != NULL)
+        filterBy->colorFollows = (*(color + 1) == '#');
     // Remove any double quotes now and rely upon commmas for delimiting
     stripString(filter, "\"");
     filterBy->slValues = slNameListFromComma(filter);
-    if (filterBy->valueAndLabel)
+    if (filterBy->valueAndLabel || filterBy->colorFollows)
         {
         struct slName *val = filterBy->slValues;
         for(;val!=NULL;val=val->next)
             {
+            // chip the color off the end of value name
+            color = strchr(val->name,'{');
+            if (color == NULL && filterBy->colorFollows)
+                {
+                warn("Using filterBy but only some values contain colors in form of value{#color} or value|label{#color}.");
+                filterBy->colorFollows = FALSE;
+                break;
+                }
+            else if (color != NULL && filterBy->colorFollows)
+                {
+                assert(*(color + 1) == '#');
+                *color++ = 0;  // The color is found inside the filters->svValues as the next string beyond value or label
+                color = strchr(val->name,'}'); // There could be a closing '}'
+                if (color != NULL)
+                    *color = 0;
+                {
+
+            // now chip the label off the end of value name
             char * lab =strchr(val->name,'|');
-            if (lab == NULL)
+            if (lab == NULL && filterBy->valueAndLabel)
                 {
                 warn("Using filterBy but only some values contain labels in form of value|label.");
                 filterBy->valueAndLabel = FALSE;
                 break;
                 }
+            if (lab != NULL && filterBy->valueAndLabel)
+                {
             *lab++ = 0;  // The label is found inside the filters->svValues as the next string
             strSwapChar(lab,'_',' '); // Title does not have underscores
             }
         }
+        }
 
     slAddTail(&filterBySet,filterBy); // Keep them in order (only a few)
 
     if(cart != NULL)
         {
         char suffix[64];
         safef(suffix, sizeof(suffix), "filterBy.%s", filterBy->column);
         boolean compositeLevel = isNameAtCompositeLevel(tdb,name);
         if(cartLookUpVariableClosestToHome(cart,tdb,compositeLevel,suffix,&(filterBy->htmlName)))
             filterBy->slChoices = cartOptionalSlNameList(cart,filterBy->htmlName);
         }
     if(filterBy->htmlName == NULL)
         {
         int len = strlen(name) + strlen(filterBy->column) + 15;
         filterBy->htmlName = needMem(len);
@@ -3492,63 +3517,68 @@
 
 filterBy_t *filterBy = NULL;
 jsIncludeFile("ui.core.js",NULL);
 jsIncludeFile("ui.dropdownchecklist.js",NULL);
 webIncludeResourceFile("ui.dropdownchecklist.css");
 
 int ix=0;
 for(filterBy = filterBySet;filterBy != NULL; filterBy = filterBy->next)
     {
     puts("<TD>");
     if(count == 1)
         printf("<B>Filter by %s</B> (select multiple items - %s)",filterBy->title,FILTERBY_HELP_LINK);
     else
         printf("<B>%s</B>",filterBy->title);
 
-    if (onOneLine && count > 1)
+    //if (onOneLine && count > 1) // NOTE: onOneLine doesn't work because filterBy with multiple selected will align above title!
         printf("<BR>\n");
-    else
-        printf(":\n");
+    //else
+    //    printf(":\n");
     // TODO: Scroll long lists
     //#define FILTER_COMPOSITE_OPEN_SIZE 16
     // TODO: columnCount (Number of filterBoxes per row) should be configurable through tdb setting
     #define FILTER_BY_FORMAT "<SELECT id='fbc%d' name='%s.filterBy.%s' multiple style='display: none;' class='filterComp filterBy'><BR>\n"
     printf(FILTER_BY_FORMAT,ix,tdb->track,filterBy->column);
     ix++;
     printf("<OPTION%s>All</OPTION>\n",(filterBy->slChoices == NULL || slNameInList(filterBy->slChoices,"All")?" SELECTED":"") );
     struct slName *slValue;
     if(filterBy->useIndex)
         {
         int ix=1;
         for(slValue=filterBy->slValues;slValue!=NULL;slValue=slValue->next,ix++)
             {
             char varName[32];
             safef(varName, sizeof(varName), "%d",ix);
             char *name = strSwapChar(cloneString(slValue->name),'_',' ');
                 printf("<OPTION%s value=%s>%s</OPTION>\n",(filterBy->slChoices != NULL && slNameInList(filterBy->slChoices,varName)?" SELECTED":""),varName,name);
             freeMem(name);
             }
         }
-    else if(filterBy->valueAndLabel)
-        {
-        for(slValue=filterBy->slValues;slValue!=NULL;slValue=slValue->next)
-            printf("<OPTION%s value=%s>%s</OPTION>\n",(filterBy->slChoices != NULL && slNameInList(filterBy->slChoices,slValue->name)?" SELECTED":""),slValue->name,slValue->name+strlen(slValue->name)+1);
-        }
     else
         {
         for(slValue=filterBy->slValues;slValue!=NULL;slValue=slValue->next)
-            printf("<OPTION%s>%s</OPTION>\n",(filterBy->slChoices != NULL && slNameInList(filterBy->slChoices,slValue->name)?" SELECTED":""),slValue->name);
+            {
+            char *label = (filterBy->valueAndLabel? slValue->name + strlen(slValue->name)+1: slValue->name);
+            printf("<OPTION");
+            if (filterBy->slChoices != NULL && slNameInList(filterBy->slChoices,slValue->name))
+                printf(" SELECTED");
+            if (filterBy->valueAndLabel)
+                printf(" value='%s'",slValue->name);
+            if (filterBy->colorFollows)
+                printf(" style='background-color: %s;'",label + strlen(label)+1);
+            printf(">%s</OPTION>\n",label);
+            }
         }
     }
     printf("</SELECT>\n");
 
     // The following is needed to make msie scroll to selected option.
     printf("<script type='text/javascript'>onload=function(){ if( $.browser.msie ) { $(\"select[name^='%s.filterBy.']\").children('option[selected]').each( function(i) { $(this).attr('selected',true); }); }}</script>\n",tdb->track);
 puts("</TR></TABLE>");
 
 return;
 }
 
 #define COLOR_BG_DEFAULT_IX     0
 #define COLOR_BG_ALTDEFAULT_IX  1
 #define DIVIDING_LINE "<TR valign=\"CENTER\" line-height=\"1\" BGCOLOR=\"%s\"><TH colspan=\"5\" align=\"CENTER\"><hr noshade color=\"%s\" width=\"100%%\"></TD></TR>\n"
 #define DIVIDER_PRINT(color) printf(DIVIDING_LINE,COLOR_BG_DEFAULT,(color))
@@ -4768,31 +4798,31 @@
         *opened = TRUE;
         }
     printf("<TR><TD align='right'><B>%s:</B><TD align='left'>",label);
     char varName[256];
     char altLabel[256];
     safef(varName, sizeof(varName), "%s%s", scoreName, _BY_RANGE);
     boolean filterByRange = trackDbSettingClosestToHomeOn(tdb, varName);
     // NOTE: could determine isFloat = (strchr(setting,'.') != NULL);  However, historical trackDb settings of pValueFilter did not always contain '.'
     if (isFloat)
         {
         double minLimit=NO_VALUE,maxLimit=NO_VALUE;
         double minVal=minLimit,maxVal=maxLimit;
         colonPairToDoubles(setting,&minVal,&maxVal);
         getScoreFloatRangeFromCart(cart,tdb,scoreName,&minLimit,&maxLimit,&minVal,&maxVal);
         safef(varName, sizeof(varName), "%s.%s%s", name, scoreName, _MIN);
-        safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange?"Minimum ":""), label);
+        safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange?"Minimum ":""), htmlEncodeText(htmlTextStripTags(label),FALSE));
         cgiMakeDoubleVarWithLimits(varName,minVal, altLabel, 0,minLimit, maxLimit);
         if(filterByRange)
             {
             printf("<TD align='left'>to<TD align='left'>");
             safef(varName, sizeof(varName), "%s.%s%s", name, scoreName, _MAX);
             safef(altLabel, sizeof(altLabel), "%s%s", (filterByRange?"Maximum ":""), label);
             cgiMakeDoubleVarWithLimits(varName,maxVal, altLabel, 0,minLimit, maxLimit);
             }
         safef(altLabel, sizeof(altLabel), "%s", (filterByRange?"": "colspan=3"));
         if(minLimit != NO_VALUE && maxLimit != NO_VALUE)
             printf("<TD align='left'%s> (%g to %g)",altLabel,minLimit, maxLimit);
         else if(minLimit != NO_VALUE)
             printf("<TD align='left'%s> (minimum %g)",altLabel,minLimit);
         else if(maxLimit != NO_VALUE)
             printf("<TD align='left'%s> (maximum %g)",altLabel,maxLimit);
@@ -5283,32 +5313,32 @@
             else
                 extraWhere = dyAddFilterAsDouble(cart,tdb,extraWhere,filter->name,NULL,field,and);
             }
         slNameFree(&filter);
         }
     }
 return extraWhere;
 }
 #endif///def ALL_SCORE_FILTERS_LOGIC
 
 void encodePeakCfgUi(struct cart *cart, struct trackDb *tdb, char *name, char *title, boolean boxed)
 /* Put up UI for filtering wgEnocde peaks based on score, Pval and Qval */
 {
 boolean compositeLevel = isNameAtCompositeLevel(tdb,name);
 boolean opened = FALSE;
-showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum Q-Value (-log 10)",QVALUE_FILTER,TRUE);
-showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum P-Value (-log 10)",PVALUE_FILTER,TRUE);
+showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum Q-Value (<code>-log<sub>10</sub></code>)",QVALUE_FILTER,TRUE);
+showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum P-Value (<code>-log<sub>10</sub></code>)",PVALUE_FILTER,TRUE);
 showScoreFilter(cart,tdb,&opened,boxed,compositeLevel,name,title,"Minimum Signal value",     SIGNAL_FILTER,TRUE);
 
 char *setting = trackDbSettingClosestToHomeOrDefault(tdb, SCORE_FILTER,NULL);//"0:1000");
 if(setting)
     {
     if(!opened)
         {
         boxed = cfgBeginBoxAndTitle(tdb, boxed, title);
         puts("<TABLE>");
         opened = TRUE;
         }
     char varName[256];
     int minLimit=0,maxLimit=1000,minVal=0,maxVal=NO_VALUE;
     colonPairToInts(setting,&minVal,&maxVal);
     getScoreIntRangeFromCart(cart,tdb,SCORE_FILTER,&minLimit,&maxLimit,&minVal,&maxVal);