9944d8c4a72a426a07ed2d33a5ea535811dd4461
galt
  Sun Feb 7 23:26:52 2016 -0800
Issue 16666. Makes autoscale work with multi-region for wig, bedGraph, bigWig, and multiWig. doWiggle still TODO.

diff --git src/hg/hgTracks/multiWig.c src/hg/hgTracks/multiWig.c
index a2dd849..7c05cff 100644
--- src/hg/hgTracks/multiWig.c
+++ src/hg/hgTracks/multiWig.c
@@ -158,31 +158,31 @@
 	int blue = fp[2]*FLOAT_FOR_BIGGEST_BYTE;
 	*cp++ = MAKECOLOR_32(red, green, blue);
 	fp += 3;
 	}
     if (hvg->rc)
         reverseLineOfColors(lineBuf, width);
     hvGfxVerticalSmear(hvg, xOff, y + yOff, width, 1, lineBuf, TRUE);
     }
 freez(&lineBuf);
 }
 
 
 static void minMaxVals(struct slRef *refList, double *retMin, double *retMax,
      enum wiggleWindowingEnum windowingFunction,enum wiggleAlwaysZeroEnum alwaysZero, double *yOffsets)
 /* Figure out min/max of everything in list.  The refList contains pointers to
- * preDrawContainers */
+ * preDrawContainers. Calculates the yOffsets used to make the stacked-graph overlay mode. */
 {
 /* Turns out to be *much* shorter to rewrite than to reuse preDrawAutoScale */
 double max = -BIGDOUBLE, min = BIGDOUBLE;
 struct slRef *ref;
 int numTrack = 0;
 for (ref = refList; ref != NULL; numTrack++,ref = ref->next)
     {
     struct preDrawContainer *pre = ref->val;
     if (pre == NULL)  // pre may be null if the bigWig file didn't load
 	continue;
 
     struct preDrawElement *p = pre->preDraw + pre->preDrawZero;
     int width = pre->width;
     int i;
     int offset = numTrack * pre->width;
@@ -250,117 +250,191 @@
     case wiggleAggregateStacked:
 	{
 	wgo = wigGraphOutputStack(xOff, yOff, width, numTracks, hvg);
 	break;
 	}
     default:
 	{
 	errAbort("bad aggregate function (value: %d)\n", wigCart->aggregateFunction);
 	break;
 	}
     }
 return wgo;
 }
 
 
-static void multiWigDraw(struct track *tg, int seqStart, int seqEnd,
+static void multiWigPreDraw(struct track *tg, int seqStart, int seqEnd,
         struct hvGfx *hvg, int xOff, int yOff, int width, 
         MgFont *font, Color color, enum trackVisibility vis)
-/* Draw items in multiWig container. */
+/* Pre-Draw multiWig container calls preDraw on all subtracks. */
 {
+int y = yOff;  // The y value here should not matter.
 struct track *subtrack;
-boolean errMsgShown = FALSE;
-int y = yOff;
-boolean errMsgFound = FALSE;
+
+struct wigCartOptions *wigCart = tg->wigCartData;
+
+// we want to the order to be the same in all the modes 
+if (wigCart->aggregateFunction == wiggleAggregateStacked)
+    slReverse(&tg->subtracks);
+
 int numTracks = 0;
 // determine if any subtracks had errors and count them up
 for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
     {
     if (isSubtrackVisible(subtrack) )
 	{
 	numTracks++;
-	if (subtrack->networkErrMsg)
-	    errMsgFound = TRUE;
 	}
     }
 
-if (errMsgFound)
-    {
-    Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor);
-    hvGfxBox(hvg, xOff, yOff, width, tg->height, yellow);
-    }
-
-struct wigCartOptions *wigCart = tg->wigCartData;
 struct wigGraphOutput *wgo = setUpWgo(xOff, yOff, width, tg->height, numTracks, wigCart, hvg);
+tg->wigGraphOutput = wgo;
 
-// we want to the order to be the same in all the modes 
-if (wigCart->aggregateFunction == wiggleAggregateStacked)
-    slReverse(&tg->subtracks);
-
-/* Cope with autoScale and stacked bars - we do it here rather than in the child tracks, so that
- * all children can be on same scale. */
+// Cope with autoScale and stacked bars - we do it here rather than in the child tracks, so that
+// all children can be on same scale.
 double minVal, maxVal;
 
-/* Force load of all predraw arrays so can do calcs. Build up list, and then
- * figure out max/min.  No worries about multiple loading, the loaders protect
- * themselves. */
+// Force load of all predraw arrays so can do calcs. Build up list, and then
+// figure out max/min.  No worries about multiple loading, the loaders protect
+// themselves. 
 struct slRef *refList = NULL;
 for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
     {
     if (isSubtrackVisible(subtrack))
 	{
 	struct preDrawContainer *pre = subtrack->loadPreDraw(subtrack, seqStart, seqEnd, width);
 
 	if (pre != NULL)  // pre maybe null if the load fails
 	    {
-	    preDrawWindowFunction(pre->preDraw, pre->preDrawSize, wigCart->windowingFunction,
-		    wigCart->transformFunc, wigCart->doNegative);
-	    preDrawSmoothing(pre->preDraw, pre->preDrawSize, wigCart->smoothingWindow);
-	    pre->smoothingDone = TRUE;
+	    pre->skipAutoscale = TRUE;
+	    subtrack->preDrawItems(subtrack, seqStart, seqEnd, hvg, xOff, y, width, font, color, vis);
 	    refAdd(&refList, pre);
 	    }
 	}
     }
 slReverse(&refList);
+
 minMaxVals(refList, &minVal, &maxVal, wigCart->windowingFunction,  wigCart->alwaysZero, wgo->yOffsets);
 slFreeList(&refList);
 
 if (!wigCart->autoScale)
     {
     minVal = wigCart->minY;
     maxVal = wigCart->maxY;
     }
 
-/* Loop through again setting up the wigCarts of the children to have minY/maxY for
- * our limits and autoScale off. */
+// Loop through again setting up the wigCarts of the children to have minY/maxY for
+// our limits and autoScale off.
 for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
     {
-    if (!isSubtrackVisible(subtrack))
-	continue;
-
+    if (isSubtrackVisible(subtrack))
+	{
 	struct wigCartOptions *wigCart = subtrack->wigCartData;
 	wigCart->minY = minVal;
 	wigCart->maxY = maxVal;
 	wigCart->autoScale = wiggleScaleManual;
 	struct preDrawContainer *pre = subtrack->preDrawContainer;
-
 	if (pre != NULL)  // pre maybe null if the load fails
 	    {
 	    pre->graphUpperLimit = maxVal;
 	    pre->graphLowerLimit = minVal;
 	    }
 	}
+    }
+}
+
+static void multiWigMultiRegionGraphLimits(struct track *tg)
+/* Set graphLimits for subtracks. */
+{
+struct track *subtrack;
+
+double graphUpperLimit = -BIGDOUBLE;
+double graphLowerLimit = BIGDOUBLE;
+struct window *w;
+struct track *tgs;
+
+for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
+    {
+    if (isSubtrackVisible(subtrack))
+	{
+	// find common graphLimits across all windows.
+	for(w=windows,tgs=subtrack; w; w=w->next,tgs=tgs->nextWindow)
+	    {
+	    struct preDrawContainer *pre = tgs->preDrawContainer;
+	    if (pre != NULL)  // pre maybe null if the load fails
+		{
+		if (pre->graphUpperLimit > graphUpperLimit)
+		    graphUpperLimit = pre->graphUpperLimit;
+		if (pre->graphLowerLimit < graphLowerLimit)
+		    graphLowerLimit = pre->graphLowerLimit;
+		}
+	    }
+	break;  // can exit since the rest of the subtracks have been set to the same limits.
+	}
+    }
+
+// set same common graphLimits across all subtracks.
+for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
+    {
+    if (isSubtrackVisible(subtrack))
+	{
+	// set same common graphLimits across all windows.
+	for(w=windows,tgs=subtrack; w; w=w->next,tgs=tgs->nextWindow)
+	    {
+	    struct wigCartOptions *wigCart = tgs->wigCartData;
+	    wigCart->minY = graphUpperLimit;
+	    wigCart->maxY = graphLowerLimit;
+	    struct preDrawContainer *pre = tgs->preDrawContainer;
+	    if (pre != NULL)  // pre maybe null if the load fails
+		{
+		pre->graphUpperLimit = graphUpperLimit;
+		pre->graphLowerLimit = graphLowerLimit;
+		}
+	    tgs->graphUpperLimit = graphUpperLimit;
+	    tgs->graphLowerLimit = graphLowerLimit;
+	    }
+	}
+    }
+}
+
+static void multiWigDraw(struct track *tg, int seqStart, int seqEnd,
+        struct hvGfx *hvg, int xOff, int yOff, int width, 
+        MgFont *font, Color color, enum trackVisibility vis)
+/* Draw items in multiWig container. */
+{
+struct track *subtrack;
+boolean errMsgShown = FALSE;
+int y = yOff;
+boolean errMsgFound = FALSE;
+// determine if any subtracks had errors and count them up
+for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
+    {
+    if (isSubtrackVisible(subtrack) )
+	{
+	if (subtrack->networkErrMsg)
+	    errMsgFound = TRUE;
+	}
+    }
+
+if (errMsgFound)
+    {
+    Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor);
+    hvGfxBox(hvg, xOff, yOff, width, tg->height, yellow);
+    }
+
+struct wigCartOptions *wigCart = tg->wigCartData;
+struct wigGraphOutput *wgo = tg->wigGraphOutput;
 
 int numTrack = 0;
 for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
     {
     if (isSubtrackVisible(subtrack))
 	{
         if (!subtrack->networkErrMsg || !errMsgShown)
 	    {
 	    if (subtrack->networkErrMsg)
 	       errMsgShown = TRUE;
 	    wgo->numTrack = numTrack++;
 	    subtrack->wigGraphOutput = wgo;
 	    int height = subtrack->totalHeight(subtrack, vis);
 	    hvGfxSetClip(hvg, xOff, y, width, height);
 	    if (wigCart->aggregateFunction != wiggleAggregateNone)
@@ -485,18 +559,20 @@
 {
 containerLoadItems(track);
 struct track *subtrack;
 for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next)
     {
     subtrack->mapsSelf = FALSE;	/* Round about way to tell wig not to do own mapping. */
     }
 }
 
 void multiWigContainerMethods(struct track *track)
 /* Override general container methods for multiWig. */
 {
 track->syncChildVisToSelf = TRUE;
 track->loadItems = multiWigLoadItems;
 track->totalHeight = multiWigTotalHeight;
+track->preDrawItems = multiWigPreDraw;
+track->preDrawMultiRegion = multiWigMultiRegionGraphLimits;
 track->drawItems = multiWigDraw;
 track->drawLeftLabels = multiWigLeftLabels;
 }