753c0bb7aacde00fa0e2c07bcb3c67e2f3bb8e4b
tdreszer
  Thu Nov 10 13:57:11 2011 -0800
Get DNA color feature: added support for composites and limited to currently visible tracks.  This is for redmine 685.
diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index 0f7797f..116d5ba 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -4205,30 +4205,52 @@
     {
     struct trackDb *tdb;
     AllocVar(tdb);
     tdb->track = cloneString(USER_PSL_TRACK_NAME);
     tdb->table = cloneString(USER_PSL_TRACK_NAME);
     tdb->shortLabel = cloneString(USER_PSL_TRACK_LABEL);
     tdb->type = cloneString("psl");
     tdb->longLabel = cloneString(USER_PSL_TRACK_LONGLABEL);
     tdb->visibility = tvFull;
     tdb->priority = 11.0;
     trackDbPolish(tdb);
     return(tdb);
     }
 }
 
+#define AND_SUBTRACKS_TOO
+#ifdef AND_SUBTRACKS_TOO
+struct trackDb *rFindUnderstandableTrack(char *db, struct trackDb *tdb)
+// If any leaf is usable in getting DNA then that leaf's tdb is returned.
+{
+if (tdb->subtracks != NULL)
+    return rFindUnderstandableTrack(db,tdb->subtracks);
+
+if (fbUnderstandTrack(db, tdb->table) && !dnaIgnoreTrack(tdb->table))
+    return tdb;
+else
+    return NULL;
+}
+
+boolean forestHasUnderstandableTrack(char *db, struct trackDb *tdb)
+// TRUE if any leaf is usable in getting DNA.
+{
+return (rFindUnderstandableTrack(db, tdb) != NULL);
+}
+#endif///def AND_SUBTRACKS_TOO
+
+
 void doGetDnaExtended1()
 /* Do extended case/color get DNA options. */
 {
 struct trackDb *tdbList = hTrackDb(database), *tdb;
 struct trackDb *ctdbList = tdbForCustomTracks();
 struct trackDb *utdbList = tdbForUserPsl();
 boolean isRc     = cartUsualBoolean(cart, "hgc.dna.rc", FALSE);
 boolean revComp  = cartUsualBoolean(cart, "hgSeq.revComp", FALSE);
 boolean maskRep  = cartUsualBoolean(cart, "hgSeq.maskRepeats", FALSE);
 int padding5     = cartUsualInt(cart, "hgSeq.padding5", 0);
 int padding3     = cartUsualInt(cart, "hgSeq.padding3", 0);
 char *casing     = cartUsualString(cart, "hgSeq.casing", "");
 char *repMasking = cartUsualString(cart, "hgSeq.repMasking", "");
 boolean caseUpper= FALSE;
 char *pos = NULL;
@@ -4305,31 +4327,36 @@
 printf(" Default case: ");
 cgiMakeRadioButton("case", "upper", caseUpper);
 printf(" Upper ");
 cgiMakeRadioButton("case", "lower", !caseUpper);
 printf(" Lower ");
 cgiMakeButton("Submit", "submit");
 printf("<BR>\n");
 printf("<TABLE BORDER=1>\n");
 printf("<TR><TD>Track<BR>Name</TD><TD>Toggle<BR>Case</TD><TD>Under-<BR>line</TD><TD>Bold</TD><TD>Italic</TD><TD>Red</TD><TD>Green</TD><TD>Blue</TD></TR>\n");
 for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
     {
     char *table = tdb->table;
     char *track = tdb->track;
     if (sameString(USER_PSL_TRACK_NAME, table) ||
 	(lookupCt(track) != NULL) ||
+#ifdef AND_SUBTRACKS_TOO
+        (   tdbVisLimitedByAncestors(cart,tdb,TRUE,TRUE) != tvHide
+         && forestHasUnderstandableTrack(database, tdb)))
+#else///ifndef AND_SUBTRACKS_TOO
 	(fbUnderstandTrack(database, table) && !dnaIgnoreTrack(table)))
+#endif///ndef AND_SUBTRACKS_TOO
 	{
         char *visString = cartUsualString(cart, track, hStringFromTv(tdb->visibility));
          if (differentString(visString, "hide") && tdb->parent)
             {
             char *parentVisString = cartUsualString(cart, tdb->parentName,
                                         hStringFromTv(tdb->parent->visibility));
             if (sameString("hide", parentVisString))
                 visString = "hide";
             }
 	char buf[128];
 	if (sameString(visString, "hide"))
 	    {
 	    char varName[256];
 	    sprintf(varName, "%s_case", track);
 	    cartSetBoolean(cart, varName, FALSE);
@@ -4864,31 +4891,36 @@
 seq = hDnaFromSeq(database, seqName, winStart, winEnd, dnaLower);
 if (isRc)
     reverseComplement(seq->dna, seq->size);
 if (defaultUpper)
     touppers(seq->dna);
 
 AllocArray(colors, winSize);
 for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
     {
     char *track = tdb->track;
     char *table = tdb->table;
     struct featureBits *fbList = NULL, *fb;
     struct customTrack *ct = lookupCt(track);
     if (sameString(USER_PSL_TRACK_NAME, table) ||
 	(ct != NULL) ||
+#ifdef AND_SUBTRACKS_TOO
+        (   tdbVisLimitedByAncestors(cart,tdb,TRUE,TRUE) != tvHide
+         && forestHasUnderstandableTrack(database, tdb)))
+#else///ifndef AND_SUBTRACKS_TOO
 	(fbUnderstandTrack(database, table) && !dnaIgnoreTrack(table)))
+#endif///ndef AND_SUBTRACKS_TOO
         {
 	char buf[256];
 	int r,g,b;
 	/* to save a LOT of time, don't fetch track features unless some
 	 * coloring/formatting has been specified for them. */
 	boolean hasSettings = FALSE;
 	safef(buf, sizeof(buf), "%s_u", track);
 	hasSettings |= cgiBoolean(buf);
 	safef(buf, sizeof(buf), "%s_b", track);
 	hasSettings |= cgiBoolean(buf);
 	safef(buf, sizeof(buf), "%s_i", track);
 	hasSettings |= cgiBoolean(buf);
 	safef(buf, sizeof(buf), "%s_case", track);
 	hasSettings |= cgiBoolean(buf);
 	safef(buf, sizeof(buf), "%s_red", track);
@@ -4946,31 +4978,54 @@
                 hFreeConn(&conn);
                 }
             else
                 {
                 ctBedList = ct->bedList;
                 }
 	    bedList2 = bedFilterListInRange(ctBedList, bf, seqName, winStart,
 					    winEnd);
 	    fbList = fbFromBed(database, track, hti, bedList2, winStart, winEnd,
 			       TRUE, FALSE);
 	    bedFreeList(&bedList2);
             if (!ct->bedList)
                 bedFreeList(&ctBedList);
 	    }
 	else
+            {
+#ifdef AND_SUBTRACKS_TOO
+            if (tdb->subtracks)
+                {
+                struct slRef *refLeaves = trackDbListGetRefsToDescendantLeaves(tdb->subtracks);
+                struct slRef *refLeaf = NULL;
+                while ((refLeaf = slPopHead(&refLeaves)) != NULL)
+                    {
+                    struct trackDb *tdbLeaf = refLeaf->val;
+                    if (tdbVisLimitedByAncestors(cart,tdbLeaf,TRUE,TRUE) != tvHide
+                    &&  fbUnderstandTrack(database, tdbLeaf->table)
+                    && !dnaIgnoreTrack(tdbLeaf->table))
+                        {
+                        struct featureBits *fbLeafList = fbGetRange(database, tdbLeaf->table, seqName, winStart, winEnd);
+                        if (fbLeafList != NULL)
+                            fbList = slCat(fbList,fbLeafList); // TODO: merge featureBits to overlaps?
+                        }
+                    freeMem(refLeaf);
+                    }
+                }
+            else
+#endif///def AND_SUBTRACKS_TOO
 	    fbList = fbGetRange(database, tdb->table, seqName, winStart, winEnd);
+            }
 
 	/* Flip underline/italic/bold bits. */
 	getDnaHandleBits(track, "u", uBits, winStart, winEnd, isRc, fbList);
 	getDnaHandleBits(track, "b", bBits, winStart, winEnd, isRc, fbList);
 	getDnaHandleBits(track, "i", iBits, winStart, winEnd, isRc, fbList);
 
 	/* Toggle case if necessary. */
 	sprintf(buf, "%s_case", track);
 	if (cgiBoolean(buf))
 	    {
 	    for (fb = fbList; fb != NULL; fb = fb->next)
 	        {
 		DNA *dna;
 		int start = fb->start - winStart;
 		int end  = fb->end - winStart;