8c908f948b09826c6cb4452ee5b282aca41be85e
galt
  Tue Dec 8 21:52:59 2015 -0800
Multi-region (exonMostly). This work allows people to look at virtual chromosomes from a list of regions and then navigate and perform all of the usual functions on it.

diff --git src/hg/hgTracks/cds.c src/hg/hgTracks/cds.c
index dc850b5..94009f9 100644
--- src/hg/hgTracks/cds.c
+++ src/hg/hgTracks/cds.c
@@ -44,43 +44,43 @@
 
 Color lighterShade(struct hvGfx *hvg, Color color, double percentLess);
 /* Find a color which is a percentless 'lighter' shade of color */
 /* Forward declaration */
 
 /* Array of colors used in drawing codons/bases/differences: */
 Color cdsColor[CDS_NUM_COLORS];
 boolean cdsColorsMade = FALSE;
 
 Color getCdsColor(int index)
 {
 assert(index < CDS_NUM_COLORS);
 return cdsColor[index];
 }
 
-static void drawScaledBoxSampleWithText(struct hvGfx *hvg, 
+static void drawScaledBoxWithText(struct hvGfx *hvg, 
                                         int chromStart, int chromEnd,
                                         double scale, int xOff, int y,
                                         int height, Color color, int score,
                                         MgFont *font, char *text, bool zoomed,
                                         int winStart, int maxPixels, boolean isCoding, boolean justifyString)
 /* Draw a box scaled from chromosome to window coordinates with
    a codon or set of 3 or less bases drawn in the box. */
 {
 
 /*first draw the box itself*/
-drawScaledBoxSample(hvg, chromStart, chromEnd, scale, xOff, y, height, 
-		    color, score);
+drawScaledBox(hvg, chromStart, chromEnd, scale, xOff, y, height, 
+		    color);
 
 /*draw text in box if space, and align properly for codons or DNA*/
 if (zoomed)
     {
     int i;
     int x1, x2, w;
     x1 = round((double)(chromStart-winStart)*scale) + xOff;
     x2 = round((double)(chromEnd-winStart)*scale) + xOff;
     if (x2 >= maxPixels)
         x2 = maxPixels - 1;
     w = x2-x1;
     if (w < 1)
         w = 1;
 
     if (chromEnd - chromStart == 3 && isCoding)
@@ -156,35 +156,91 @@
 	}
     }
 
 if (idx < 0)
     return(-1);
 
 if(psl->strand[1] == '-')
     thisQStart = psl->qSize - (qStarts[idx]+psl->blockSizes[idx]);
 else
     thisQStart = qStarts[idx];
 
 return(thisQStart + (s - tStart));
 }
 
 /* Calls to hDnaFromSeq are rather expensive for 2bit, so cache genomic sequence */
+
+struct genoCacheWindow
+{
+struct genoCacheWindow *next;
+struct window *window;
+char *initedTrack;
+struct dnaSeq *cachedGenoDna;
+int cachedGenoStart;
+int cachedGenoEnd;
+};
+
+static struct genoCacheWindow *gcWindows = NULL;
+static struct genoCacheWindow *gcWindow = NULL;
+static struct genoCacheWindow *gcWindowOld = NULL;
+
+static bool setGcWindow()
+/* scan genoCache windows. create new one if not found */
+{
+if (gcWindow && gcWindow->window == currentWindow)
+    return FALSE;
+gcWindowOld = gcWindow;
+for (gcWindow = gcWindows; gcWindow; gcWindow =  gcWindow->next)
+    {
+    if (gcWindow->window == currentWindow)
+	{
+	return TRUE;
+	}
+    }
+AllocVar(gcWindow);
+gcWindow->window = currentWindow;
+slAddTail(&gcWindows, gcWindow);
+return TRUE;
+}
+
+
+
 static char *initedTrack = NULL;
 static struct dnaSeq *cachedGenoDna = NULL;
 static int cachedGenoStart = 0;
 static int cachedGenoEnd = 0;
 
+static void setGc()
+/* set up globals for the current window */
+{
+if (setGcWindow())
+    {
+    if (gcWindowOld)
+	{
+	gcWindowOld->initedTrack     = initedTrack;
+    	gcWindowOld->cachedGenoDna   = cachedGenoDna;
+	gcWindowOld->cachedGenoStart = cachedGenoStart;
+    	gcWindowOld->cachedGenoEnd   = cachedGenoEnd;
+	}
+    initedTrack     = gcWindow->initedTrack;
+    cachedGenoDna   = gcWindow->cachedGenoDna;
+    cachedGenoStart = gcWindow->cachedGenoStart;
+    cachedGenoEnd   = gcWindow->cachedGenoEnd;
+    }
+
+}
+
 static void getLinkedFeaturesSpan(struct linkedFeatures *lfList, int *retStart, int *retEnd,
 				  boolean isSeries)
 /* Find the overall lowest and highest coords in lfList.  If any items hang off the
  * edge of the window, we will end up with coords <winStart and/or >winEnd which is
  * what we want. */
 {
 int start = winStart, end = winEnd;
 if (isSeries)
     {
     struct linkedFeaturesSeries *lfs, *lfsList = (struct linkedFeaturesSeries *)lfList;
     for (lfs = lfsList;  lfs != NULL;  lfs = lfs->next)
 	{
 	if (lfs->start < start)
 	    start = lfs->start;
 	if (lfs->end > end)
@@ -200,30 +256,31 @@
 	    start = lf->start;
 	if (lf->end > end)
 	    end = lf->end;
 	}
     }
 if (retStart)
     *retStart = start;
 if (retEnd)
     *retEnd = end;
 }
 
 static char *getCachedDna(int chromStart, int chromEnd)
 /* Return a pointer into our cached genomic dna.  chromEnd is just for
  * bounds-checking (honor system).  Do not change or free the return value! */
 {
+setGc();
 if (!initedTrack || !cachedGenoDna)
     errAbort("getCachedDnaAt called before baseColorInitTrack?!");
 if (chromStart < cachedGenoStart || chromEnd > cachedGenoEnd)
     errAbort("getCachedDnaAt: coords %d,%d are out of cached range %d,%d",
 	     chromStart, chromEnd, cachedGenoStart, cachedGenoEnd);
 return &(cachedGenoDna->dna[chromStart - cachedGenoStart]);
 }
 
 static void getNextCodonDna(char *retStr, int n, struct genePred *gp, int startI,
 			    boolean posStrand)
 /* Get at most n bases from coding exons following exon startI. */
 {
 int i, j, thisN;
 int cdsExonStart, cdsExonEnd;
 char *codonDna;
@@ -1373,87 +1430,87 @@
     boolean isCoding = (drawOpt == baseColorDrawItemCodons || drawOpt == baseColorDrawDiffCodons);
 
     mrnaBases[0] = '\0';
     if (psl && isCoding)
 	getMrnaBases(psl, mrnaSeq, mrnaS, s, e, (lf->orientation == -1),
 		    mrnaBases, &queryInsertion);
     if (queryInsertion && isCoding)
 	color = cdsColor[CDS_QUERY_INSERTION];
 
     dyStringAppendN(dyMrnaSeq, (char*)&mrnaSeq->dna[mrnaS], e-s);
 
     if (drawOpt == baseColorDrawItemBases)
 	{
 	if (cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE))
 	    complement(dyMrnaSeq->string, dyMrnaSeq->stringSize);
-	drawScaledBoxSampleWithText(hvg, s, e, scale, xOff, y, heightPer, 
+	drawScaledBoxWithText(hvg, s, e, scale, xOff, y, heightPer, 
 				    color, lf->score, font, dyMrnaSeq->string,
 				    zoomedToBaseLevel, winStart, maxPixels, isCoding, TRUE);
 	}
     else if (drawOpt == baseColorDrawItemCodons)
 	{
 	if (e <= lf->tallEnd)
 	    {
 	    boolean startColor = FALSE;
 	    /* re-set color of this block based on mrna codons rather than
 	     * genomic, but keep the odd/even cycle of dark/light shades. */
 	    int mrnaGrayIx = codonToGrayIx(mrnaBases, (grayIx > 26), NULL,
 					   FALSE, TRUE);
 	    if (color == cdsColor[CDS_START])
                 startColor = TRUE;
 	    color = colorAndCodonFromGrayIx(hvg, mrnaCodon, mrnaGrayIx,
 					    ixColor);
 	    if (startColor && sameString(mrnaCodon,"M"))
                 color = cdsColor[CDS_START];
-	    drawScaledBoxSampleWithText(hvg, s, e, scale, xOff, y, heightPer, 
+	    drawScaledBoxWithText(hvg, s, e, scale, xOff, y, heightPer, 
 					color, lf->score, font, mrnaCodon,
 					zoomedToCodonLevel, winStart,
 					maxPixels, isCoding, TRUE);
 	    }
 	else
 	    drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color);
 	}
     else if (drawOpt == baseColorDrawDiffBases)
 	{
 	char *diffStr = NULL;
 	char *genoDna = getCachedDna(s, e);
 	diffStr = needMem(sizeof(char) * (e - s + 1));
 	maskDiffString(diffStr, dyMrnaSeq->string, genoDna, ' ');
 	if (cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE))
 	    complement(diffStr, strlen(diffStr));
-	drawScaledBoxSampleWithText(hvg, s, e, scale, xOff, y, heightPer, 
+	drawScaledBoxWithText(hvg, s, e, scale, xOff, y, heightPer, 
 				    color, lf->score, font, diffStr, 
 				    zoomedToBaseLevel, winStart, maxPixels, isCoding, TRUE);
 	freeMem(diffStr);
 	}
     else if (drawOpt == baseColorDrawDiffCodons)
 	{
 	if (e <= lf->tallEnd)
 	    {
 	    /* Color codons red wherever mrna differs from genomic;
 	     * keep the odd/even cycle of dark/light shades. */
 	    colorAndCodonFromGrayIx(hvg, genomicCodon, grayIx, ixColor);
 	    int mrnaGrayIx = mrnaCodonToGrayIx(mrnaBases, genomicCodon[0],
 					       (grayIx > 26));
 	    color = colorAndCodonFromGrayIx(hvg, mrnaCodon, mrnaGrayIx,
 					    ixColor);
 	    // Look up mrnaCodon again because if mrnaGrayIx is GRAYIX_SYN_PROT,
 	    // codon value is lost:
 	    safef(mrnaCodon, sizeof(mrnaCodon), "%c", baseColorLookupCodon(mrnaBases));
 	    if (mrnaCodon[0] != genomicCodon[0])
 		{
-		drawScaledBoxSampleWithText(hvg, s, e, scale, xOff, y, 
+		drawScaledBoxWithText(hvg, s, e, scale, xOff, y, 
 					    heightPer, color, lf->score, font,
 					    mrnaCodon, zoomedToCodonLevel,
 					    winStart, maxPixels, isCoding, TRUE);
 		}
 	    else
 		drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color);
 	    }
 	else
 	    drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, color);
 	}
     else if (drawOpt != baseColorDrawCds)
         errAbort("Unknown drawOpt: %d<br>\n", drawOpt);
 
     dyStringFree(&dyMrnaSeq);
     }
@@ -1479,77 +1536,77 @@
 char codon[64] = " ";
 Color color = colorAndCodonFromGrayIx(hvg, codon, grayIx, originalColor);
 if (sf->codonIndex)
     safef(codon, sizeof(codon), "%c %d", codon[0], sf->codonIndex);
 /* When we are zoomed out far enough so that multiple bases/codons share the 
  * same pixel, we have to draw differences in a separate pass (baseColorOverdrawDiff)
  * so don't waste time drawing the differences here: */
 boolean zoomedOutToPostProcessing =
     ((drawOpt == baseColorDrawDiffBases && !zoomedToBaseLevel) ||
      (drawOpt == baseColorDrawDiffCodons && !zoomedToCdsColorLevel));
 
 if (drawOpt == baseColorDrawGenomicCodons && (e-s <= 3))
     {
     if (lf->highlightColor)
 	{
-	drawScaledBoxSample(hvg, s, e, scale, xOff, y, heightPer, 
-			    lf->highlightColor, lf->score );
-	drawScaledBoxSampleWithText(hvg, s, e, scale, xOff, y+1, heightPer-2, 
+	drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, 
+			    lf->highlightColor);
+	drawScaledBoxWithText(hvg, s, e, scale, xOff, y+1, heightPer-2, 
 				    color, lf->score, font, codon, 
 				    zoomedToCodonLevel, winStart, maxPixels, TRUE, !sf->codonIndex);
 	}
     else
 	{
-	drawScaledBoxSampleWithText(hvg, s, e, scale, xOff, y, heightPer, 
+	drawScaledBoxWithText(hvg, s, e, scale, xOff, y, heightPer, 
 				    color, lf->score, font, codon, 
 				    zoomedToCodonLevel, winStart, maxPixels, TRUE, !sf->codonIndex);
 	}
     }
 else if (mrnaSeq != NULL && (psl != NULL || sf != NULL) && !zoomedOutToPostProcessing &&
 	 drawOpt != baseColorDrawGenomicCodons && drawOpt != baseColorDrawOff)
     {
     if (lf->highlightColor)
 	{
-	drawScaledBoxSample(hvg, s, e, scale, xOff, y, heightPer, 
-			    lf->highlightColor, lf->score );
+	drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, 
+			    lf->highlightColor);
 	drawDiffTextBox(hvg, xOff+1, y+1, scale, heightPer-2, font, 
 			color, chromName, s, e, sf, psl, mrnaSeq, lf,
 			grayIx, drawOpt, maxPixels,
 			tg->colorShades, originalColor);
 	}
     else
 	{
 	drawDiffTextBox(hvg, xOff, y, scale, heightPer, font, 
 			color, chromName, s, e, sf, psl, mrnaSeq, lf,
 			grayIx, drawOpt, maxPixels,
 			tg->colorShades, originalColor);
 	}
     }
 else
     {
     /* revert to normal coloring */
     if (lf->highlightColor)
 	{
-	drawScaledBoxSample(hvg, s, e, scale, xOff, y, heightPer, 
-			    lf->highlightColor, lf->score );
-	drawScaledBoxSample(hvg, s, e, scale, xOff+1, y+1, heightPer -2, 
-			    color, lf->score );
+	drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, 
+			    lf->highlightColor);
+	drawScaledBox(hvg, s, e, scale, xOff+1, y+1, heightPer -2, 
+			    color);
 	}
     else
 	{
-	drawScaledBoxSample(hvg, s, e, scale, xOff, y, heightPer, 
-			    color, lf->score );
+	drawScaledBox(hvg, s, e, scale, xOff, y, heightPer, 
+			    color);
 	}
     }
 }
 
 
 static void drawCdsDiffCodonsOnly(struct track *tg,  struct linkedFeatures *lf,
 			   struct hvGfx *hvg, int xOff,
 			   int y, double scale, int heightPer,
 			   struct dnaSeq *mrnaSeq, struct psl *psl,
 			   int winStart)
 /* Draw red boxes only where mRNA codons differ from genomic.  This assumes
  * that lf has been drawn already, we're zoomed out past zoomedToCdsColorLevel,
  * we're not in dense mode etc. */
 {
 struct simpleFeature *sf = NULL;
@@ -1757,30 +1814,31 @@
 	    (psl->tSize - (psl->tStarts[lastBlk] + psl->blockSizes[lastBlk])) :
 	    (psl->tStarts[lastBlk] + psl->blockSizes[lastBlk]);
 	drawVertLine(lf, hvg, s, xOff, y, heightPer-1, scale,
 		     cdsColor[CDS_QUERY_INSERTION_AT_END]);
 	}
     }
 }
 
 void baseColorInitTrack(struct hvGfx *hvg, struct track *tg)
 /* Set up base coloring state (e.g. cache genomic sequence) for tg.
  * This must be called by tg->drawItems if baseColorDrawSetup is used 
  * in tg->drawItemAt.  Peeks at tg->drawItems method to determine whether
  * tg is linkedFeatures or linkedFeaturesSeries (currently the only
  * two supported track types -- bed, psl etc. are subclasses of these). */
 {
+setGc();
 if (initedTrack == NULL || differentString(tg->track, initedTrack))
     {
     int overallStart, overallEnd;
     boolean isSeries = FALSE;
 #ifdef USE_BAM
     if (tg->drawItems == linkedFeaturesSeriesDraw
         || tg->drawItems == bamLinkedFeaturesSeriesDraw)
 #else
     if (tg->drawItems == linkedFeaturesSeriesDraw)
 #endif
 	isSeries = TRUE;
     else if (!baseColorCanDraw(tg))
 	errAbort("baseColorInitTrack: track %s has a type not recognized by baseColorCanDraw.",
 		 tg->track);
     getLinkedFeaturesSpan((struct linkedFeatures *)tg->items, &overallStart, &overallEnd,
@@ -1794,30 +1852,31 @@
 	}
     initedTrack = cloneString(tg->track);
     }
 
 /* allocate colors for coding coloring */
 if (!cdsColorsMade)
     { 
     makeCdsShades(hvg, cdsColor);
     cdsColorsMade = TRUE;
     }
 }
 
 static void checkTrackInited(struct track *tg, char *what)
 /* Die if baseColorInitTrack has not been called (most recently) for this track. */
 {
+setGc();
 if (initedTrack == NULL || differentString(tg->track, initedTrack))
     errAbort("Error: Track %s should have been baseColorInitTrack'd before %s.  "
 	     "(tg->drawItems may be unrecognized by baseColorCanDraw)",
 	     tg->track, what);
 }
 
 enum baseColorDrawOpt baseColorDrawSetup(struct hvGfx *hvg, struct track *tg,
 			struct linkedFeatures *lf,
 			struct dnaSeq **retMrnaSeq, struct psl **retPsl)
 /* Returns the CDS coloring option, allocates colors if necessary, and 
  * returns the sequence and psl record for the given item if applicable. 
  * Note: even if base coloring is not enabled, this will return psl and 
  * mrna seq if query insert/polyA coloring is enabled.
  * baseColorInitTrack must be called before this (in tg->drawItems) --
  * this is meant to be called by tg->drawItemAt (i.e. linkedFeaturesDrawAt). */
@@ -1876,31 +1935,31 @@
    of codons. Used for browser ruler in full mode*/
 {
 struct simpleFeature *sf;
 
 if (!cdsColorsMade)
     {
     makeCdsShades(hvg, cdsColor);
     cdsColorsMade = TRUE;
     }
 
 for (sf = sfList; sf != NULL; sf = sf->next)
     {
     char codon[4];
     Color color = colorAndCodonFromGrayIx(hvg, codon, sf->grayIx, MG_GRAY);
     if (zoomedToText)
-        drawScaledBoxSampleWithText(hvg, sf->start, sf->end, scale, insideX, y,
+        drawScaledBoxWithText(hvg, sf->start, sf->end, scale, insideX, y,
 				    height, color, 1.0, font, codon, TRUE,
 				    winStart, maxPixels, TRUE, TRUE);
     else
         /* zoomed in just enough to see colored boxes */
         drawScaledBox(hvg, sf->start, sf->end, scale, xOff, y, height, color);
     }
 }
 
 
 void baseColorDrawCleanup(struct linkedFeatures *lf, struct dnaSeq **pMrnaSeq,
 			  struct psl **pPsl)
 /* Free structures allocated just for base/cds coloring. */
 {
 // We could free lf->original here (either genePredFree or pslFree, depending
 // on the type -- but save time by skipping that.  Maybe we should save time