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);