2d4c0be4a4a481893ae023a20ad68c753872adbb
angie
  Mon Mar 7 10:58:31 2011 -0800
Enabling next/prev-exon arrows for DECIPHER track at b0b's request.Those arrows are implemented for linkedFeatures, so I convert the bed4
DECIPHER items into linkedFeatures during loading, and use lf->extra to
store the phenotypes string used in draw and mapItems.

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index 0414010..86e309b 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -5128,44 +5128,44 @@
     int dir = 0;
     if (bed->strand[0] == '+')
 	dir = 1;
     else if(bed->strand[0] == '-')
 	dir = -1;
     if (dir != 0 && w > 2)
 	{
 	int midY = y + (heightPer>>1);
 	Color textColor = hvGfxContrastingColor(hvg, color);
 	clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing,
 		dir, textColor, TRUE);
 	}
     }
 }
 
-char *decipherPhenotypeList(struct track *tg, struct bed *item)
+char *decipherPhenotypeList(struct track *tg, char *name)
 /* Return list of diseases associated with a DECIPHER entry */
 {
 struct sqlConnection *conn;
 char query[256];
 struct sqlResult *sr;
 char **row;
 char *chp;
 int i=0;
 
 conn = hAllocConn(database);
 
 safef(query,sizeof(query),
-        "select distinct phenotype from decipherRaw where id='%s' order by phenotype", item->name);
+        "select distinct phenotype from decipherRaw where id='%s' order by phenotype", name);
 sr = sqlMustGetResult(conn, query);
 row = sqlNextRow(sr);
 
 /* show up to 20 max entries */
 chp = decipherBuffer;
 while ((row != NULL) && i<20)
     {
     if (i != 0)
 	{
 	safef(chp, 3, "; ");
 	chp++;chp++;
 	}
     safef(chp, 100, "%s", row[0]);
     chp = chp+strlen(row[0]);
     row = sqlNextRow(sr);
@@ -5173,47 +5173,73 @@
     }
 
 if ((i == 20) && (row != NULL))
     {
     safef(chp, 5, " ...");
     chp++;chp++;chp++;chp++;
     }
 
 *chp = '\0';
 
 hFreeConn(&conn);
 sqlFreeResult(&sr);
 return(decipherBuffer);
 }
 
+void decipherLoad(struct track *tg)
+/* Convert bed4 to linkedFeatures so we can have next "exon" arrows. */
+{
+struct sqlConnection *conn = hAllocConn(database);
+struct linkedFeatures *lfList = NULL;
+int rowOffset = 0;
+struct sqlResult *sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset);
+char **row = NULL;
+while ((row = sqlNextRow(sr)) != NULL)
+    {
+    struct bed *bed = bedLoad(row+rowOffset);
+    bed->score = 1000;
+    bed->strand[0] = '.';
+    bed->thickStart = bed->chromStart;
+    bed->thickEnd = bed->chromEnd;
+    struct linkedFeatures *lf = bedMungToLinkedFeatures(&bed, tg->tdb, 4, 0, 1000, FALSE);
+    lf->extra = cloneString(decipherPhenotypeList(tg, lf->name));
+    slAddHead(&lfList, lf);
+    }
+sqlFreeResult(&sr);
+hFreeConn(&conn);
+slReverse(&lfList);
+slSort(&lfList, linkedFeaturesCmp);
+tg->items = lfList;
+}
+
 Color decipherColor(struct track *tg, void *item, struct hvGfx *hvg)
 /* Return color to draw DECIPHER entry */
 {
-struct bed *bedItem = item;
+struct linkedFeatures *lf = item;
 int col = tg->ixColor;
 struct sqlConnection *conn = hAllocConn(database);
 struct sqlResult *sr;
 char **row;
 char query[256];
 char cond_str[256];
 char *decipherId = NULL;
 
 /* color scheme:
 	RED:	If the entry is a deletion (mean ratio < 0)
 	BLUE:	If the entry is a duplication (mean ratio > 0)
 */
-safef(cond_str, sizeof(cond_str),"name='%s' ", bedItem->name);
+safef(cond_str, sizeof(cond_str),"name='%s' ", lf->name);
 decipherId = sqlGetField(database, "decipher", "name", cond_str);
 if (decipherId != NULL)
     {
     if (hTableExists(database, "decipherRaw"))
     	{
     	safef(query, sizeof(query), "select mean_ratio > 0 from decipherRaw where id = '%s'", decipherId);
     	sr = sqlGetResult(conn, query);
     	if ((row = sqlNextRow(sr)) != NULL)
             {
 	    if (sameWord(row[0], "1"))
 	    	{
 	    	col = MG_BLUE;
 	    	}
 	    else
 		{
@@ -5234,85 +5260,88 @@
 	    	col = MG_GRAY;
 	    	}
 	    }
 	sqlFreeResult(&sr);
 	}
     }
 hFreeConn(&conn);
 return(col);
 }
 
 static void decipherDrawAt(struct track *tg, void *item,
 	struct hvGfx *hvg, int xOff, int y,
 	double scale, MgFont *font, Color color, enum trackVisibility vis)
 /* Draw a single superfamily item at position. */
 {
-struct bed *bed = item;
-char *sPhenotypes;
+struct linkedFeatures *lf = item;
+char *sPhenotypes = lf->extra;
 int heightPer = tg->heightPer;
-int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff;
-int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff;
+int x1 = round((double)((int)lf->start-winStart)*scale) + xOff;
+int x2 = round((double)((int)lf->end-winStart)*scale) + xOff;
 int w;
 
-sPhenotypes = decipherPhenotypeList(tg, item);
 w = x2-x1;
 if (w < 1)
     w = 1;
 if (color)
     {
     hvGfxBox(hvg, x1, y, w, heightPer, decipherColor(tg, item, hvg));
 
     if (vis == tvFull)
         {
         hvGfxTextRight(hvg, x1-mgFontStringWidth(font, sPhenotypes)-2, y,
 		    mgFontStringWidth(font, sPhenotypes),
                     heightPer, MG_BLACK, font, sPhenotypes);
         }
     if (tg->drawName && vis != tvSquish)
 	{
 	/* Clip here so that text will tend to be more visible... */
-	char *s = tg->itemName(tg, bed);
+	char *s = tg->itemName(tg, item);
 	w = x2-x1;
 	if (w > mgFontStringWidth(font, s))
 	    {
 	    Color textColor = hvGfxContrastingColor(hvg, color);
 	    hvGfxTextCentered(hvg, x1, y, w, heightPer, textColor, font, s);
 	    }
 	}
-    if (vis != tvDense)
-   	mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1, y, x2 - x1, heightPer,
-	         tg->track, tg->mapItemName(tg, bed), sPhenotypes);
     }
-if (tg->subType == lfWithBarbs)
+}
+
+void decipherMapItem(struct track *tg, struct hvGfx *hvg, void *item,
+		     char *itemName, char *mapItemName, int start, int end,
+		     int x, int y, int width, int height)
+/* Special mouseover text from lf->extra (phenotype list). */
     {
-    int dir = 0;
-    if (bed->strand[0] == '+')
-	dir = 1;
-    else if(bed->strand[0] == '-')
-	dir = -1;
-    if (dir != 0 && w > 2)
+// Don't bother if we are imageV2 and a dense child.
+if(!theImgBox || tg->limitedVis != tvDense || !tdbIsCompositeChild(tg->tdb))
 	{
-	int midY = y + (heightPer>>1);
-	Color textColor = hvGfxContrastingColor(hvg, color);
-	clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing,
-		dir, textColor, TRUE);
-	}
+    struct linkedFeatures *lf = item;
+    char *directUrl = trackDbSetting(tg->tdb, "directUrl");
+    boolean withHgsid = (trackDbSetting(tg->tdb, "hgsid") != NULL);
+    char *phenotypes = lf->extra;
+    char *mouseOverText = isEmpty(phenotypes) ? lf->name : phenotypes;
+    mapBoxHgcOrHgGene(hvg, start, end, x, y, width, height, tg->track,
+                    mapItemName, mouseOverText, directUrl, withHgsid, NULL);
     }
 }
+
 void decipherMethods(struct track *tg)
 /* Methods for DECIPHER track. */
 {
+linkedFeaturesMethods(tg);
+tg->loadItems = decipherLoad;
+tg->mapItem = decipherMapItem;
 tg->itemColor   = decipherColor;
 tg->drawItemAt 	= decipherDrawAt;
 }
 
 char *emptyName(struct track *tg, void *item)
 /* Return name of item. */
 {
 return("");
 }
 
 void rdmrMethods(struct track *tg)
 /* Methods for R-DMR track. */
 {
 tg->itemName = emptyName;
 }