fb06bed25a9f45eaef8a875f3efbd45cfc14e804
max
  Mon Jul 20 04:43:21 2020 -0700
fixing PDF output for new highlight cart variable format, also fixes a related problem that just came up on the ML, refs #25887

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index 8686b2e..b1c35f8 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -2132,56 +2132,84 @@
 }
 
 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 to a linked list of highlightVar structs
-// db.chrom:start-end#hexColor|db.chrom:start-end#hexColor|...
+// Accepts three input formats for the highlight variable:
+// 1) db.chrom:start-end (format in very old carts)
+// 2) db.chrom:start-end#hexColor|db.chrom:start-end#hexColor|... (old format)
+// 3) db#chrom#start#end#hexColor|db#chrom#start#end#hexColor|... (current format, to allow . in seq names)
+//
 {
 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;
+        char *chromStart, *chromEnd;
         AllocVar(h);
+        if (countSeparatedItems(oneHl, '#')==5)
+            // the new format: db#chrom#start#end#color
+            {
+            h->db     = cloneNextWordByDelimiter(&oneHl,'#');
+            h->chrom  = cloneNextWordByDelimiter(&oneHl,'#');
+            chromStart = cloneNextWordByDelimiter(&oneHl,'#');
+            chromEnd = cloneNextWordByDelimiter(&oneHl,'#');
+            h->hexColor = cloneString(oneHl);
+            }
+        else  // the syntax only used in old saved sessions
+            // the old format: db.chr:start-end followed optionally by #color
+            {
             h->db     = cloneNextWordByDelimiter(&oneHl,'.');
             h->chrom  = cloneNextWordByDelimiter(&oneHl,':');
+            chromStart = cloneNextWordByDelimiter(&oneHl,'-');
+            chromEnd = cloneNextWordByDelimiter(&oneHl,'#');
+            if (oneHl && *oneHl != '\0')
+                h->hexColor = cloneString(oneHl);
+            }
+
+        if (!isEmpty(chromStart) && !isEmpty(chromEnd) && 
+                isNumericString(chromStart) && isNumericString(chromEnd) &&
+                !isEmpty(h->db) && !isEmpty(h->chrom))
+            {
             // long to handle virt chrom coordinates
-        h->chromStart = atol(cloneNextWordByDelimiter(&oneHl,'-'));
-        h->chromEnd   = atol(cloneNextWordByDelimiter(&oneHl,'#'));
+            h->chromStart = atol(chromStart);
+            h->chromEnd   = atol(chromEnd);
             h->chromStart--; // Not zero based
-        if (highlightDef && *highlightDef != '\0')
-            h->hexColor = cloneString(oneHl);
             slAddHead(&hlList, h);
             }
+        }
+
     slReverse(&hlList);
     }
+
 return hlList;
 }
 
 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 *hlList = parseHighlightInfo();
 
 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
@@ -8475,36 +8503,38 @@
      * go along with this trick */
     hPrintf("<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1 WIDTH=%d COLS=%d><TR>\n",
             tl.picWidth, 27);
 #ifndef USE_NAVIGATION_LINKS
     hPrintf("<TD COLSPAN=6 ALIGN=left NOWRAP>");
     hPrintf("move start<BR>");
     hButtonWithOnClick("hgt.dinkLL", " < ", "move start position to the left",
                        "return imageV2.navigateButtonClick(this);");
     hTextVar("dinkL", cartUsualString(cart, "dinkL", "2.0"), 3);
     hButtonWithOnClick("hgt.dinkLR", " > ", "move start position to the right",
                        "return imageV2.navigateButtonClick(this);");
     hPrintf("</TD>");
     hPrintf("<td width='30'>&nbsp;</td>\n");
 #endif//ndef USE_NAVIGATION_LINKS
     hPrintf("<TD class='infoText' COLSPAN=15 style=\"white-space:normal\">"); // allow this text to wrap
-    hWrites("Click on a feature for details. ");
-    hWrites("Click or drag in the base position track to zoom in. ");
-    hWrites("Click side bars for track options. ");
-    hWrites("Drag side bars or labels up or down to reorder tracks. ");
-    hWrites("Drag tracks left or right to new position. ");
-    hWrites("Press \"?\" for keyboard shortcuts. ");
+    //hWrites("Click on a feature for details. ");
+    //hWrites("Click or drag in the base position track to zoom in. ");
+    //hWrites("Click side bars for track options. ");
+    //hWrites("Drag side bars or labels up or down to reorder tracks. ");
+    //hWrites("Drag tracks left or right to new position. ");
+    //hWrites("Press \"?\" for keyboard shortcuts. ");
+    hWrites("Unsure how to use the Genome Browser? ");
+    hWrites("Have a look at our <a href='../goldenPath/help/hgTracksHelp.html#FineTuning'>Tutorial</a>");
     hPrintf("</TD>");
 #ifndef USE_NAVIGATION_LINKS
     hPrintf("<td width='30'>&nbsp;</td>\n");
     hPrintf("<TD COLSPAN=6 ALIGN=right NOWRAP>");
     hPrintf("move end<BR>");
     hButtonWithOnClick("hgt.dinkRL", " < ", "move end position to the left",
                        "return imageV2.navigateButtonClick(this);");
     hTextVar("dinkR", cartUsualString(cart, "dinkR", "2.0"), 3);
     hButtonWithOnClick("hgt.dinkRR", " > ", "move end position to the right",
                        "return imageV2.navigateButtonClick(this);");
     hPrintf("</TD>");
 #endif//ndef USE_NAVIGATION_LINKS
     hPrintf("</TR></TABLE>\n");
 
     /* Display bottom control panel. */
@@ -8584,33 +8614,33 @@
 
     if (showTrackControls)
 	{
 	/* Display viewing options for each track. */
         /* Chuck: This is going to be wrapped in a table so that
          * the controls don't wrap around randomly */
         hPrintf("<table border=0 cellspacing=1 cellpadding=1 width=%d>\n", CONTROL_TABLE_WIDTH);
         hPrintf("<tr><td align='left'>\n");
 
         hButtonWithOnClick("hgt.collapseGroups", "collapse all", "collapse all track groups",
                            "return vis.expandAllGroups(false)");
         hPrintf("</td>");
 
         hPrintf("<td colspan='%d' class='infoText' align='CENTER' nowrap>"
                 "Use drop-down controls below and press refresh to alter tracks "
-                "displayed.<BR>"
-                "Tracks with lots of items will automatically be displayed in "
-                "more compact modes.</td>\n", MAX_CONTROL_COLUMNS - 2);
+                "displayed.<BR>", MAX_CONTROL_COLUMNS -2 );
+                //"Tracks with lots of items will automatically be displayed in "
+                //"more compact modes.</td>\n", MAX_CONTROL_COLUMNS - 2);
 
         hPrintf("<td align='right'>");
         hButtonWithOnClick("hgt.expandGroups", "expand all", "expand all track groups",
                            "return vis.expandAllGroups(true)");
         hPrintf("</td></tr>");
 
         cg = startControlGrid(MAX_CONTROL_COLUMNS, "left");
 	for (group = groupList; group != NULL; group = group->next)
 	    {
 	    if (group->trackList == NULL)
 		continue;
 
 	    struct trackRef *tr;
 
 	    /* check if group section should be displayed */