e1ba0aaa1baec345d56cc8a518b8450c3e5d74c3
tdreszer
  Wed Jan 22 14:31:22 2014 -0800
Checking in new feature 'drag-select highlight', which was originally coded by Larry.  Redmine #709 (been on the shelf for awhile).
diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index c57b6b2..560111e 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -1906,30 +1906,72 @@
 hvGfxUnclip(hvg);
 return y;
 }
 
 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);
     }
 }
 
+void highlightRegion(struct cart *cart, struct hvGfx *hvg, int insideX, int imagePixelHeight,
+                       int winStart, int winEnd)
+// Highlights a region 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
+{
+char *highlightDef = cartOptionalString(cart, "highlight");
+if(highlightDef && theImgBox == NULL) // Only highlight region when imgBox is not used.
+    {
+    // expect db.chrom:start-end#hexColor
+    char *db     = cloneNextWordByDelimiter(&highlightDef,'.');
+    char *chrom  = cloneNextWordByDelimiter(&highlightDef,':');
+    int chromStart = atoi(cloneNextWordByDelimiter(&highlightDef,'-'));
+    int chromEnd   = atoi(cloneNextWordByDelimiter(&highlightDef,'#'));
+    if ((db    != NULL && sameString(db,   database ))
+    &&  (chrom != NULL && sameString(chrom,chromName))
+    &&  (chromEnd != 0)
+    &&  (chromStart <= winEnd && chromEnd >= winStart))
+        {
+        chromStart--; // Not zero based
+        chromStart = max(chromStart, winStart);
+        chromEnd = min(chromEnd, winEnd);
+        double pixelsPerBase = scaleForPixels(insideWidth + 1);
+        int startPixels = pixelsPerBase * (chromStart - winStart); // floor
+        if (startPixels < 0)
+            startPixels *= -1;  // reverse complement
+        int width = pixelsPerBase * (double)(chromEnd - chromStart) + 0.5; // round up
+        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 (highlightDef != NULL && *highlightDef != '\0')
+            {
+            long rgb = strtol(highlightDef,NULL,16); // Big and little Endians
+            hexColor = MAKECOLOR_32( ((rgb>>16)&0xff), ((rgb>>8)&0xff), (rgb&0xff) );
+            }
+
+        hvGfxBox(hvg, insideX + 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 makeActiveImage(struct track *trackList, char *psOutput)
 /* Make image and image map. */
 {
 struct track *track;
 MgFont *font = tl.font;
 struct hvGfx *hvg;
@@ -2154,30 +2196,33 @@
         trashDirFile(&gifTnSide, "hgtSide", "side", ".png");
         hvgSide = hvGfxOpenPng(pixWidth, pixHeight, gifTnSide.forCgi, transparentImage);
 
         // Also add the side image
         theSideImg = imgBoxImageAdd(theImgBox,gifTnSide.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.
+    highlightRegion(cart, hvg, insideX, imagePixelHeight, winStart, winEnd);
+
 /* Find colors to draw in. */
 findTrackColors(hvg, 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
         }
 
     for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next)
         {
         track = flatTrack->track;
@@ -4539,40 +4584,30 @@
     if (showTrackControls)
         {
 	/* Break into a second form so that zooming and scrolling
 	 * can be done with a 'GET' so that user can back up from details
 	 * page without Internet Explorer popping up an annoying dialog.
 	 * Do rest of page as a 'POST' so that the ultra-long URL from
 	 * all the track controls doesn't break things.  IE URL limit
 	 * is 2000 bytes, but some firewalls impose a ~1000 byte limit.
 	 * As a side effect of breaking up the page into two forms
 	 * we need to repeat the position in a hidden variable here
 	 * so that zoom/scrolling always has current position to work
 	 * from. */
         // This 'dirty' field is used to check if js/ajax changes to the page have occurred.
         // If so and it is reached by the back button, a page reload will occur instead.
         hPrintf("<INPUT TYPE='text' style='display:none;' name='dirty' id='dirty' VALUE='false'>\n");
-        // Define BACK_SUPPORT to support the back-button via jquery.histoty.js
-#define BACK_SUPPORT
-#ifndef BACK_SUPPORT
-        // Unfortunately this does not work in IE, so IE will get reloaded only after this full load
-        // NOTE: Larry and I have seen that the new URL is not even used, but this will abort
-        //       the page load and hasten the isDirty() check in hgTracks.js
-        hPrintf("<script type='text/javascript'>if (document.getElementById('dirty').value == "
-                "'true') {document.getElementById('dirty').value = 'false'; "
-                "window.location = '%s?hgsid=%d';}</script>\n",hgTracksName(),cart->sessionId);
-#endif//ndef BACK_SUPPORT
         hPrintf("<INPUT TYPE=HIDDEN id='positionHidden' NAME=\"position\" "
                 "VALUE=\"%s:%d-%d\">", chromName, winStart+1, winEnd);
         hPrintf("\n%s", trackGroupsHidden1->string);
         hPrintf("</CENTER></FORM>\n");
         hPrintf("<FORM ACTION=\"%s\" NAME=\"TrackForm\" id=\"TrackForm\" METHOD=\"POST\">\n\n",
                 hgTracksName());
 	    hPrintf("%s", trackGroupsHidden2->string);
 	    freeDyString(&trackGroupsHidden1);
 	    freeDyString(&trackGroupsHidden2);
 	if (!psOutput) cartSaveSession(cart);   /* Put up hgsid= as hidden variable. */
 	clearButtonJavascript = "document.TrackForm.position.value=''; document.getElementById('suggest').value='';";
 	hPrintf("<CENTER>");
 	}
 
 
@@ -5685,33 +5720,31 @@
     }
 
 jsonForClient = newJsonObject(newHash(8));
 jsonObjectAdd(jsonForClient, "cgiVersion", newJsonString(CGI_VERSION));
 boolean searching = differentString(cartUsualString(cart, TRACK_SEARCH,"0"), "0");
 
 if(!trackImgOnly)
     {
     // Write out includes for css and js files
     hWrites(commonCssStyles());
     jsIncludeFile("jquery.js", NULL);
     jsIncludeFile("jquery-ui.js", NULL);
     jsIncludeFile("utils.js", NULL);
     jsIncludeFile("ajax.js", NULL);
     jsIncludeFile("jquery.watermarkinput.js", NULL);
-#ifdef BACK_SUPPORT
     jsIncludeFile("jquery.history.js", NULL);  // Experimental
-#endif//def BACK_SUPPORT
     if(!searching)
         {
         jsIncludeFile("jquery.imgareaselect.js", NULL);
         }
     jsIncludeFile("autocomplete.js", NULL);
     jsIncludeFile("hgTracks.js", NULL);
 
 #ifdef LOWELAB
     jsIncludeFile("lowetooltip.js", NULL);
 #endif///def LOWELAB
 
     webIncludeResourceFile("jquery-ui.css");
     if (!searching)     // NOT doing search
         {
         webIncludeResourceFile("jquery.contextmenu.css");
@@ -5784,22 +5817,28 @@
     {
     /* currently not used */
     cartRemove(cart, configShowEncodeGroups);
     struct grp *grp = NULL, *grps = hLoadGrps(database);
     for (grp = grps; grp != NULL; grp = grp->next)
         if (startsWith("encode", grp->name))
             collapseGroup(grp->name, FALSE);
     configPageSetTrackVis(-2);
     }
 else
     {
     tracksDisplay();
     }
 
 jsonObjectAdd(jsonForClient, "measureTiming", newJsonBoolean(measureTiming));
+// js code needs to know if a highlightRegion is defined for this db
+char *highlightDef = cartOptionalString(cart, "highlight");
+if (highlightDef && startsWith(database,highlightDef) && highlightDef[strlen(database)] == '.')
+    jsonObjectAdd(jsonForClient, "highlight", newJsonString(highlightDef));
+jsonObjectAdd(jsonForClient, "enableHighlightingDialog",
+              newJsonBoolean(cartUsualBoolean(cart, "enableHighlightingDialog", TRUE)));
 hPrintf("<script type='text/javascript'>\n");
 jsonPrint((struct jsonElement *) jsonForClient, "hgTracks", 0);
 hPrintf("</script>\n");
 
 if (measureTiming)
     measureTime("Time at end of doMiddle, next up cart write");
 }