de6d2d4e5d0106a57d1ada79e9e36005676c260e
chmalee
  Fri Sep 25 12:39:18 2026 -0700
Add trackDb defined filters, coloring, and mouseovers for vcf tracks, using INFO fields or sub INFO fields, like vep.Consequence, refs #37617, #37618

diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 54b082a5564..9f01230ed9b 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -6926,31 +6926,34 @@
         tdbFilter->name = cloneString(filter->name);
         tdbFilter->setting = trackDbSetting(tdb, filter->name);
         tdbFilter->fieldName = extractFieldNameNew(filter->name, lowName);
         tdbFilter->priority = lookupFilterPriority(tdb, tdbFilter->fieldName, isHighlight);
         setAsNewFilterType(tdb, tdbFilter->name, tdbFilter->fieldName);
         }
     }
 filterSettings = trackDbSettingsWildMatch(tdb, capWild);
 
 if (filterSettings)
     {
     struct trackDbFilter *tdbFilter;
     struct slName *filter = NULL;
     while ((filter = slPopHead(&filterSettings)) != NULL)
         {
-        if (differentString(filter->name,NO_SCORE_FILTER))
+        // vcfDoFilter and vcfDoInfoFilter are VCF UI toggles, not filters on a field
+        if (differentString(filter->name,NO_SCORE_FILTER)
+            && differentString(filter->name, VCF_DO_FILTER_UI)
+            && differentString(filter->name, VCF_DO_INFOFILTER_UI))
             {
             AllocVar(tdbFilter);
             slAddHead(&trackDbFilterList, tdbFilter);
             tdbFilter->name = cloneString(filter->name);
             tdbFilter->setting = trackDbSetting(tdb, filter->name);
             tdbFilter->fieldName = extractFieldNameOld(filter->name, capName);
             tdbFilter->priority = lookupFilterPriority(tdb, tdbFilter->fieldName, isHighlight);
             char *name;
             if ((name = isNewFilterType(tdb, tdbFilter->fieldName) ) != NULL)
                 errAbort("error specifying a field's filters in both old (%s) and new format (%s).", tdbFilter->name, name);
             }
         }
     }
 
 slSort(&trackDbFilterList, trackDbFilterPriCmp);
@@ -7020,58 +7023,59 @@
  * Try to guess what the user means. */
 {
 if (sameString("score", field))
     return 4;
 if (sameString("signal", field))
     return 6;
 if (sameString("signalValue", field))
     return 6;
 if (sameString("pValue", field))
     return 7;
 if (sameString("qValue", field))
     return 8;
 return -1;
 }
 
-static int numericFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb, boolean *opened,
+int numericFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb, boolean *opened,
                                  boolean boxed, boolean parentLevel,char *name, char *title,
                                  boolean isHighlight)
 // Shows all *Filter style filters.  Note that these are in random order and have no graceful title
 {
 int count = 0;
 struct trackDbFilter *trackDbFilters = NULL;
 if (isHighlight)
     trackDbFilters = tdbGetTrackNumHighlights(tdb);
 else
     trackDbFilters = tdbGetTrackNumFilters(tdb);
 if (trackDbFilters)
     {
     puts("<BR>");
     struct trackDbFilter *filter = NULL;
     struct sqlConnection *conn = NULL;
     if (!isHubTrack(db) && !isGenArk(db))
         conn = hAllocConnTrack(db, tdb);
     struct asObject *as = asForTdb(conn, tdb);
     hFreeConn(&conn);
+    boolean isVcf = startsWith("vcf", tdb->type);
 
     while ((filter = slPopHead(&trackDbFilters)) != NULL)
         {
         char *field = filter->fieldName;
         char *scoreName = cloneString(filter->name);
         char *trackDbLabel = getLabelSetting(cart, tdb, field);
 
-        if (as != NULL)
+        if (as != NULL && !isVcf)
             {
             struct asColumn *asCol = asColumnFind(as, field);
             if (asCol != NULL)
                 { // Found label so replace field; strip "|..." suffix used for detail page
                 field = asCol->comment;
                 char *pipe = strchr(field, '|');
                 if (pipe != NULL)
                     field = cloneStringZ(field, pipe - field);
                 }
             else if (defaultFieldLocation(field) < 0)
                 errAbort("Building filter on field %s which is not in AS file.", field);
             }
         char labelBuf[1024];
         char *label = labelBuf;
         char *filterName = getScoreNameAdd(tdb, scoreName, _BY_RANGE);
@@ -7146,51 +7150,69 @@
         if (differentString(oneFilter->fieldName,"score")) // scoreFilter is implicit
             {                                              // but could be blocked
             one = TRUE;
             break;
             }
         }
     if (one)
         return TRUE;
     }
 if (!blocked)  // scoreFilter is implicit unless NO_SCORE_FILTER
     return TRUE;
 
 return FALSE;
 }
 
+char *getHighlightType(struct cart *cart, struct trackDb *tdb, char *field, char *def)
+/* Figure out how the trackDb is specifying the HIGHLIGHT_TYPE variable and return its setting */
+{
+char settingString[4096];
+safef(settingString, sizeof settingString, "%s.%s", HIGHLIGHT_TYPE_NAME_LOW, field);
+char *setting = cartOrTdbString(cart, tdb, settingString, NULL);
+if (setting == NULL)
+    {
+    safef(settingString, sizeof settingString, "%s.%s", field, HIGHLIGHT_TYPE_NAME_CAP);
+    setting = cartOrTdbString(cart, tdb, settingString, NULL);
+    }
+if (setting == NULL)
+    {
+    safef(settingString, sizeof settingString, "%s%s", field, HIGHLIGHT_TYPE_NAME_CAP);
+    setting = cartOrTdbString(cart, tdb, settingString, def);
+    }
+return setting;
+}
 
 char *getFilterType(struct cart *cart, struct trackDb *tdb, char *field, char *def)
 // figure out how the trackDb is specifying the FILTER_TYPE variable and return its setting
 {
 char settingString[4096];
 safef(settingString, sizeof settingString, "%s.%s", FILTER_TYPE_NAME_LOW, field);
 char *setting = cartOrTdbString(cart, tdb, settingString, NULL);
 if (setting == NULL)
     {
     safef(settingString, sizeof settingString, "%s.%s", field, FILTER_TYPE_NAME_CAP);
     setting = cartOrTdbString(cart, tdb, settingString, NULL);
     }
 if (setting == NULL)
     {
     safef(settingString, sizeof settingString, "%s%s", field, FILTER_TYPE_NAME_CAP);
     setting = cartOrTdbString(cart, tdb, settingString, def);
     }
 return setting;
 }
 
-static int textFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb, boolean isHighlight)
+int textFiltersShowAll(char *db, struct cart *cart, struct trackDb *tdb, boolean isHighlight)
 /* Show all the text filters for this track. */
 {
 int count = 0;
 struct trackDbFilter *trackDbFilters = NULL;
 if (isHighlight)
     trackDbFilters = tdbGetTrackTextHighlights(tdb);
 else
     trackDbFilters = tdbGetTrackTextFilters(tdb);
 if (trackDbFilters)
     {
     puts("<BR>");
     struct trackDbFilter *filter = NULL;
     struct sqlConnection *conn = NULL;
     if (!isHubTrack(db) && !isGenArk(db))
         conn = hAllocConnTrack(db, tdb);