8cb0eb5850ff9883a1a278c1607998f0a6046bcb
max
  Thu Aug 4 08:56:32 2016 -0700
adding internal ability to draw multiple highlights.
refs #14951. There is no way to set these currently in the UI,
as this would be a whole project of its own. Also, in multi-exon
mode, it will only draw the first region, if multiple ones are defined.

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index 216be7e..d7916a8 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -2085,65 +2085,79 @@
 
 static void rAddToTrackHash(struct hash *trackHash, struct track *trackList)
 /* Add list and any children of list to hash. */
 {
 struct track *track;
 for (track = trackList; track != NULL; track = track->next)
     {
     hashAddUnique(trackHash, track->track, track);
     rAddToTrackHash(trackHash, track->subtracks);
     }
 }
 
 struct highlightVar
 // store highlight information
 {
+struct highlightVar *next;
 char *db;
 char *chrom;
 long chromStart;
 long chromEnd;
 char *hexColor;
 };
 
 struct highlightVar *parseHighlightInfo()
-// Parse highlight info from cart var
-// db.chrom:start-end#hexColor
+// Parse highlight info from cart var to a linked list of highlightVar structs
+// db.chrom:start-end#hexColor|db.chrom:start-end#hexColor|...
 {
-struct highlightVar *h = NULL;
+struct highlightVar *hlList = NULL;
 char *highlightDef = cartOptionalString(cart, "highlight");
 if(highlightDef)
     {
+    char *hlArr[256];
+    int hlCount = chopByChar(cloneString(highlightDef), '|', hlArr, ArraySize(hlArr));
+    int i;
+    for (i=0; i<hlCount; i++)
+        {
+        char *oneHl = hlArr[i];
+        struct highlightVar *h;
         AllocVar(h);
-    h->db     = cloneNextWordByDelimiter(&highlightDef,'.');
-    h->chrom  = cloneNextWordByDelimiter(&highlightDef,':');
+        h->db     = cloneNextWordByDelimiter(&oneHl,'.');
+        h->chrom  = cloneNextWordByDelimiter(&oneHl,':');
         // long to handle virt chrom coordinates
-    h->chromStart = atol(cloneNextWordByDelimiter(&highlightDef,'-'));
-    h->chromEnd   = atol(cloneNextWordByDelimiter(&highlightDef,'#'));
+        h->chromStart = atol(cloneNextWordByDelimiter(&oneHl,'-'));
+        h->chromEnd   = atol(cloneNextWordByDelimiter(&oneHl,'#'));
         h->chromStart--; // Not zero based
         if (highlightDef && *highlightDef != '\0')
-	h->hexColor = cloneString(highlightDef);
+            h->hexColor = cloneString(oneHl);
+        slAddHead(&hlList, h);
+        }
+    slReverse(&hlList);
     }
-return h;
+return hlList;
 }
 
-void highlightRegion(struct cart *cart, struct hvGfx *hvg, int imagePixelHeight)
-// Highlights a region in the image.  Only done if theImgBox is not defined.
+static void highlightRegions(struct cart *cart, struct hvGfx *hvg, int imagePixelHeight)
+// Highlights regions in the image.  Only done if theImgBox is not defined.
 // Thus it is done for ps/pdf and view image but the hgTracks image is highlighted via js
 {
-struct highlightVar *h = parseHighlightInfo();
+struct highlightVar *hlList = parseHighlightInfo();
 
-if(h && theImgBox == NULL) // Only highlight region when imgBox is not used. (pdf and show-image)
+if(hlList && theImgBox == NULL) // Only highlight region when imgBox is not used. (pdf and show-image)
+    {
+    struct highlightVar *h;
+    for (h=hlList; h; h=h->next) 
         {
         if (virtualSingleChrom()) // DISGUISE VMODE
             {
             if ((h->db && sameString(h->db, database))
             &&  (h->chrom && sameString(h->chrom,chromName)))
                 {
                 char position[1024];
                 safef(position, sizeof position, "%s:%ld-%ld", h->chrom, h->chromStart, h->chromEnd);
                 char *newPosition = undisguisePosition(position); // UN-DISGUISE VMODE
                 if (startsWith("virt:", newPosition))
                     {
                     parseVPosition(newPosition, &h->chrom, &h->chromStart, &h->chromEnd);
                     }
                 }	    
             }
@@ -2164,30 +2178,31 @@
             if (width < 2)
                 width = 2;
 
             // Default color to light blue, but if setting has color, use it.
             unsigned int hexColor = MAKECOLOR_32(170, 255, 255);
             if (h->hexColor)
                 {
                 long rgb = strtol(h->hexColor,NULL,16); // Big and little Endians
                 hexColor = MAKECOLOR_32( ((rgb>>16)&0xff), ((rgb>>8)&0xff), (rgb&0xff) );
                 }
 
             hvGfxBox(hvg, fullInsideX + startPixels, 0, width, imagePixelHeight, hexColor);
             }
         }
     }
+}
 
 struct hash *makeGlobalTrackHash(struct track *trackList)
 /* Create a global track hash and returns a pointer to it. */
 {
 trackHash = newHash(8);
 rAddToTrackHash(trackHash, trackList);
 return trackHash;
 }
 
 //void domAddMenu(char *afterMenuId, char *newMenuId, char *label) 
 ///* Append a new drop down menu after a given menu, by changing the DOM with jquery  */
 //{
 //printf("$('#%s').last().after('<li class=\"menuparent\" id=\"%s\"><span>%s</span>"
 //    "<ul style=\"display: none; visibility: hidden;\"></ul></li>');\n", 
 //    afterMenuId, newMenuId, label);
@@ -4653,31 +4668,31 @@
         hvgSide = hvGfxOpenPng(pixWidth, pixHeight, pngTnSide.forCgi, transparentImage);
 
         // Also add the side image
         theSideImg = imgBoxImageAdd(theImgBox,pngTnSide.forHtml,NULL,pixWidth, pixHeight,FALSE);
         hvgSide->rc = revCmplDisp;
         initColors(hvgSide);
         }
     }
 hvg->rc = revCmplDisp;
 initColors(hvg);
 
 /* Start up client side map. */
 hPrintf("<MAP id='map' Name=%s>\n", mapName);
 
 if (theImgBox == NULL)  // imageV2 highlighting is done by javascript. This does pdf and view-image highlight
-    highlightRegion(cart, hvg, imagePixelHeight);
+    highlightRegions(cart, hvg, imagePixelHeight);
 
 for (window=windows; window; window=window->next)
     {
     /* Find colors to draw in. */
     findTrackColors(hvg, window->trackList);
     }
 
 
 // Good to go ahead and add all imgTracks regardless of buttons, left label, centerLabel, etc.
 if (theImgBox)
     {
     if (rulerMode != tvHide)
         {
         curImgTrack = imgBoxTrackFindOrAdd(theImgBox,NULL,RULER_TRACK_NAME,rulerMode,FALSE,
                                            IMG_FIXEDPOS); // No tdb, no centerLbl, not reorderable