a47364d48ccd5b8ee8cdf7b47b7ba9edcfd66f1f
braney
  Wed Apr 16 10:58:32 2014 -0700
fix a crashing bug in hgCustom if the description field is empty on anassembly hub

diff --git src/hg/hgTracks/multiWig.c src/hg/hgTracks/multiWig.c
index 1d89247..b667c56 100644
--- src/hg/hgTracks/multiWig.c
+++ src/hg/hgTracks/multiWig.c
@@ -153,194 +153,231 @@
 	int red = fp[0]*FLOAT_FOR_BIGGEST_BYTE;
 	int green = fp[1]*FLOAT_FOR_BIGGEST_BYTE;
 	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 wiggleAlwaysZeroEnum alwaysZero)
+     enum wiggleAlwaysZeroEnum alwaysZero, double *yOffsets)
 /* Figure out min/max of everything in list.  The refList contains pointers to
  * preDrawContainers */
 {
 /* Turns out to be *much* shorter to rewrite than to reuse preDrawAutoScale */
 double max = -BIGDOUBLE, min = BIGDOUBLE;
 struct slRef *ref;
-for (ref = refList; ref != NULL; ref = ref->next)
+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;
-    for (i=0; i<width; ++i)
+    int offset = numTrack * pre->width;
+    int prevOffset = (numTrack - 1) * pre->width;
+    for (i=0; i<width; ++i, offset++)
 	{
 	if (p->count)
 	    {
 	    if (min > p->min) min = p->min;
 	    if (max < p->max) max = p->max;
+	    if (yOffsets)
+		yOffsets[offset] = p->max;
 	    }
+	else if (yOffsets)
+	    {
+	    yOffsets[offset] = 0;
+	    }
+	if (prevOffset > 0)
+	    yOffsets[offset] += yOffsets[prevOffset];
 	++p;
 	}
     }
 if (alwaysZero == wiggleAlwaysZeroOn)
     {
     if ( max < 0)
 	max = 0.0;
     else if ( min > 0)
 	min = 0.0;
     }
 *retMax = max;
 *retMin = min;
 }
 
+
+static struct wigGraphOutput *setUpWgo(int xOff, int yOff, int width, int height, int numTracks, struct wigCartOptions *wigCart, struct hvGfx *hvg)
+{
+/* Deal with tranparency possibly */
+struct wigGraphOutput *wgo;
+struct floatPic *floatPic = NULL;
+switch(wigCart->aggregateFunction)
+    {
+    case wiggleAggregateTransparent:
+	{
+	//int height = tg->lineHeight;
+	floatPic = floatPicNew(width, height);
+	floatPicSet(floatPic, 1, 1, 1);
+	wgo = wigGraphOutputTransparent(floatPic);
+	break;
+	}
+    case wiggleAggregateNone:
+    case wiggleAggregateSolid:
+	{
+	wgo = wigGraphOutputSolid(xOff, yOff, hvg);
+	break;
+	}
+    case wiggleAggregateStacked:
+	{
+	wgo = wigGraphOutputStack(xOff, yOff, width, numTracks, hvg);
+	break;
+	}
+    }
+return wgo;
+}
+
+
 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;
-char *aggregate = wigFetchAggregateValWithCart(cart, tg->tdb);
-boolean overlay = wigIsOverlayTypeAggregate(aggregate);
 boolean errMsgShown = FALSE;
 int y = yOff;
 boolean errMsgFound = FALSE;
-// determine if any subtracks had errors
+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) && subtrack->networkErrMsg)
+    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->extraUiData;
+struct wigGraphOutput *wgo = setUpWgo(xOff, yOff, width, tg->height, numTracks, wigCart, hvg);
+
 /* Cope with autoScale - we do it here rather than in the child tracks, so that
  * all children can be on same scale. */
-struct wigCartOptions *wigCart = tg->extraUiData;
 if (wigCart->autoScale)
     {
     /* 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);
 	    refAdd(&refList, pre);
 	    }
 	}
     double minVal, maxVal;
-    minMaxVals(refList, &minVal, &maxVal, wigCart->alwaysZero);
+    minMaxVals(refList, &minVal, &maxVal, wigCart->alwaysZero, wgo->yOffsets);
     slFreeList(&refList);
 
     /* Cope with log transform if need be */
     if (wigCart->transformFunc == wiggleTransformFuncLog)
          {
 	 minVal = wiggleLogish(minVal);
 	 maxVal = wiggleLogish(maxVal);
 	 }
 
     /* 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)
         {
 	struct wigCartOptions *wigCart = subtrack->extraUiData;
 	wigCart->minY = minVal;
 	wigCart->maxY = maxVal;
 	wigCart->autoScale = wiggleScaleManual;
 	}
     }
 
-/* Deal with tranparency possibly */
-struct wigGraphOutput *wgo;
-struct floatPic *floatPic = NULL;
-if (wigCart->transparent)
-    {
-    int height = tg->lineHeight;
-    floatPic = floatPicNew(width, height);
-    floatPicSet(floatPic, 1, 1, 1);
-    wgo = wigGraphOutputTransparent(floatPic);
-    }
-else
-    wgo = wigGraphOutputSolid(xOff, yOff, hvg);
-
+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 (overlay)
+	    if (wigCart->aggregateFunction != wiggleAggregateNone)
 		subtrack->lineHeight = tg->lineHeight;
 	    subtrack->drawItems(subtrack, seqStart, seqEnd, hvg, xOff, y, width, font, color, vis);
-	    if (!overlay)
+	    if (wigCart->aggregateFunction == wiggleAggregateNone)
 		{
 		y += height + 1;
 		wgo->yOff = y;
 		}
 	    hvGfxUnclip(hvg);
 	    }
 	}
     }
 
-if (wigCart->transparent)
+if (wigCart->aggregateFunction == wiggleAggregateTransparent)
    {
-   floatPicIntoHvg(floatPic, xOff, yOff, hvg);
-   floatPicFree(&floatPic);
+   floatPicIntoHvg(wgo->image, xOff, yOff, hvg);
+   floatPicFree((struct floatPic **)&wgo->image);
    }
 
 char *url = trackUrl(tg->track, chromName);
 mapBoxHgcOrHgGene(hvg, seqStart, seqEnd, xOff, y, width, tg->height, tg->track, tg->track, NULL,
 	      url, TRUE, NULL);
 }
 
 static int multiWigTotalHeight(struct track *tg, enum trackVisibility vis)
 /* Return total height of multiWigcontainer. */
 {
-char *aggregate = wigFetchAggregateValWithCart(cart, tg->tdb);
-boolean overlay = wigIsOverlayTypeAggregate(aggregate);
+struct wigCartOptions *wigCart = tg->extraUiData;
 int totalHeight =  0;
-if (overlay)                                                                                       
+if (wigCart->aggregateFunction !=  wiggleAggregateNone)
     totalHeight =  wigTotalHeight(tg, vis);                                                        
 struct track *subtrack;
 for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
     {
     if (isSubtrackVisible(subtrack))
 	{
 	// Logic is slightly complicated by fact we want to call the totalHeight
 	// method for each subtrack even if in overlay mode.
 	int oneHeight = subtrack->totalHeight(subtrack, vis);
-	if (!overlay)
+	if (wigCart->aggregateFunction ==  wiggleAggregateNone)
 	    {
 	    if (totalHeight != 0)
 	       totalHeight += 1;
 	    totalHeight += oneHeight;
 	    }
 	}
     }
 tg->height = totalHeight;
 return totalHeight;
 }
 
 static boolean graphLimitsAllSame(struct track *trackList, struct track **retFirstTrack)
 /* Return TRUE if graphUpperLimit and graphLowerLimit same for all tracks. */
 {
 struct track *firstTrack = NULL;
@@ -353,33 +390,32 @@
 	    *retFirstTrack = firstTrack = track;
 	else if (track->graphUpperLimit != firstTrack->graphUpperLimit 
 	    || track->graphLowerLimit != firstTrack->graphLowerLimit)
 	    return FALSE;
 	}
     }
 return firstTrack != NULL;
 }
 
 static void multiWigLeftLabels(struct track *tg, int seqStart, int seqEnd,
 	struct hvGfx *hvg, int xOff, int yOff, int width, int height,
 	boolean withCenterLabels, MgFont *font, Color color,
 	enum trackVisibility vis)
 /* Draw left labels - by deferring to first subtrack. */
 {
-char *aggregate = wigFetchAggregateValWithCart(cart, tg->tdb);
-boolean overlay = wigIsOverlayTypeAggregate(aggregate);
-if (overlay)
+struct wigCartOptions *wigCart = tg->extraUiData;
+if (wigCart->aggregateFunction != wiggleAggregateNone)
     {
     struct track *firstVisibleSubtrack = NULL;
     boolean showNumbers = graphLimitsAllSame(tg->subtracks, &firstVisibleSubtrack);
     struct track *subtrack = (showNumbers ? firstVisibleSubtrack : tg->subtracks);
     wigLeftAxisLabels(tg, seqStart, seqEnd, hvg, xOff, yOff, width, height, withCenterLabels,
 	    font, color, vis, tg->shortLabel, subtrack->graphUpperLimit, 
 	    subtrack->graphLowerLimit, showNumbers);
     }
 else
     {
     struct track *subtrack;
     int y = yOff;
     if (withCenterLabels)
        y += tl.fontHeight+1;
     for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)