7aa4e34c4a9855457ff806186ba65594e03ae6ac
kate
  Wed Dec 30 16:03:35 2020 -0800
First cut support for multiRegionBedUrl setting. refs #26385

diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index fad4bc0..b96c22b 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -43,30 +43,31 @@
 #include "memgfx.h"
 #include "trackHub.h"
 #include "gtexUi.h"
 #include "genbank.h"
 #include "htmlPage.h"
 #include "longRange.h"
 #include "barChartUi.h"
 #include "interactUi.h"
 #include "interact.h"
 #include "hicUi.h"
 #include "bigDbSnp.h"
 #include "customComposite.h"
 #include "trackVersion.h"
 #include "hubConnect.h"
 #include "bigBedFilter.h"
+#include "net.h"
 
 #define SMALLBUF 256
 #define MAX_SUBGROUP 9
 #define ADD_BUTTON_LABEL        "add"
 #define CLEAR_BUTTON_LABEL      "clear"
 #define JBUFSIZE 2048
 
 
 #define DEF_BUTTON "<IMG id=\"btn_%s\" src=\"../images/%s\" alt=\"%s\">\n"
 #define DEF_BUTTON_JS "setCheckBoxesThatContain('%s',true,false,'%s','','%s');" \
 	       "setCheckBoxesThatContain('%s',false,false,'%s','_defOff','%s');" 
 #define DEFAULT_BUTTON(nameOrId,anc,beg,contains) \
     printf(DEF_BUTTON,(anc),"defaults_sm.png","default"); \
     safef(id, sizeof id, "btn_%s", (anc)); \
     jsOnEventByIdF("click", id, DEF_BUTTON_JS,(nameOrId),(beg),(contains),(nameOrId),(beg),(contains)); 
@@ -329,33 +330,176 @@
     if (safeObj == NULL || safeObj->vars == NULL)
         return FALSE;
     }
 
 char id[256];
 safef(id, sizeof id, "div_%s_link", tdb->track);
 printf("%s<A id='%s' HREF='#a_meta_%s' "
    "title='Show metadata details...'>%s<img src='../images/downBlue.png'/></A>",
    (embeddedInText?"&nbsp;":"<P>"),id,tdb->track, (title?title:""));
 jsOnEventByIdF("click", id, "return metadataShowHide(\"%s\",%s,true);", 
     tdb->track, showLongLabel?"true":"false");
 printf("<DIV id='div_%s_meta' style='display:none;'>%s</div>",tdb->track, metadataAsHtmlTable(db,tdb,showLongLabel,FALSE));
 return TRUE;
 }
 
+/* Multi-region UI */
+
+boolean makeMultiRegionLink(char *db, struct trackDb *tdb)
+/* Make a link to launch browser in multi-region custom URL mode, based on
+ * track setting. This includes creating a custom track displaying the regions.
+ * The link switches to exit multi-region if browser is already in multi-region mode
+ * based on regions defined for this track. */
+{
+char *regionUrl = trackDbSetting(tdb, MULTI_REGION_BED_URL);
+if (isEmpty(regionUrl))
+    return FALSE;
+
+// make custom track for regions, alternating colors
+
+// TODO: truncate CT name and label at word boundary
+// TODO: fix bedPackDense to work with multi-region
+// TODO: limit number of regions ?
+struct dyString *dsCustomText = dyStringCreate(
+            "track name=\'%s Regions\' description=\'Regions of interest for track: %s' "
+            "visibility=dense bedPackDense=on labelOnFeature=on itemRgb=on noScoreFilter=on\n",
+                tdb->shortLabel, tdb->longLabel);
+
+#ifdef LATER
+// TODO: libify
+struct dyString *ds = NULL;
+struct errCatch *errCatch = errCatchNew();
+if (errCatchStart(errCatch))
+    {
+    int sd = netUrlOpen(regionUrl);
+    if (sd >= 0)
+        {
+        char *newUrl = NULL;
+        int newSd = 0;
+        if (netSkipHttpHeaderLinesHandlingRedirect(sd, regionUrl, &newSd, &newUrl))
+            {
+            if (newUrl) /* redirect can modify the url */
+                {
+                freeMem(newUrl);
+                sd = newSd;
+                }
+
+            ds = netSlurpFile(sd);
+            close(sd);
+            }
+        }
+    }
+errCatchEnd(errCatch);
+if (errCatch->gotError)
+    warn("%s", errCatch->message->string);
+
+// how come no warning if bad file ?
+errCatchFree(&errCatch);
+#endif
+
+// TODO: support $D, etc. in URL
+int sd = netUrlOpen(regionUrl);
+if (sd < 0)
+    return FALSE;
+struct dyString *dsRegionBed = netSlurpFile(sd);
+close(sd);
+if (!dsRegionBed)
+    return FALSE;
+char *regionBedTxt = dyStringCannibalize(&dsRegionBed);
+
+// count fields in BED. Accept up to BED9 (user-spec colors)
+char *bedTxt = cloneString(regionBedTxt);
+struct lineFile *lf = lineFileOnString(NULL, TRUE, bedTxt);
+char *words[9];
+int bedSize = lineFileChopNext(lf, words, sizeof words);
+lineFileClose(&lf);
+freeMem(bedTxt);
+
+lf = lineFileOnString(NULL, TRUE, regionBedTxt);
+
+char *colorLight = "184,201,255";       // blue
+char *colorDark = "0,0,0";              // black
+char *color = colorLight;
+boolean doLightColor = TRUE;
+
+int id = 1;
+char name[100];
+char userColor[10];
+struct bed *region;
+
+while (lineFileChopNext(lf, words, bedSize))
+    {
+    region = bedLoadN(words, bedSize);
+    if (bedSize < 9)
+        {
+        // assign alternating light/dark color
+        color = doLightColor ? colorLight : colorDark;
+        doLightColor = !doLightColor;
+        }
+    else
+        {
+        // no lib ? sigh
+        int colorIx = (int)region->itemRgb;
+        struct rgbColor rgb = colorIxToRgb(colorIx);
+        safef(userColor, sizeof userColor, "%d,%d,%d", rgb.b, rgb.g, rgb.r);
+
+        // or this ? -- uglier but deeper in code
+        //safef(userColor, sizeof userColor, "%d,%d,%d", (region->itemRgb & 0xff0000) >> 16,
+            //(region->itemRgb & 0xff00) >> 8, (region->itemRgb & 0xff));
+        }
+    if (bedSize < 4)
+        {
+        // region label based on chrom and an item number
+        safef(name, sizeof name, "r%d/%s", id++, region->chrom);
+        }
+    dyStringPrintf(dsCustomText, "%s\t%d\t%d\t%s\t"
+                        "0\t.\t%d\t%d\t%s\n",
+                            region->chrom, region->chromStart, region->chromEnd,  name,
+                            region->chromStart, region->chromEnd, color);
+    }
+lineFileClose(&lf);
+
+char customHtml[1000];
+safef(customHtml, sizeof customHtml, "<h2>Description</h2>\n"
+    "<p>This custom track displays regions of interest for the "
+    "<a href='../cgi-bin/hgTrackUi?db=%s&g=%s'><em>%s</em> track</a>.</p>",
+        db, tdb->track, tdb->shortLabel);
+
+// TODO: support #padding in custom regions file
+
+printf("<p><a target='_blank' "
+            "href='../cgi-bin/hgTracks?"
+                "virtMode=1&"
+                "virtModeType=customUrl&"
+                "virtWinFull=on&"
+                "virtShortDesc=%s&"
+                "multiRegionsBedUrl=%s&"
+                "%s=%s&"
+                "%s=%s'>"
+            "View regions of interest</a>"
+                " for this track in multi-region view</a> (custom regions mode)</p>",
+                    tdb->track, cgiEncode(regionUrl),
+                    CT_CUSTOM_DOC_TEXT_VAR, cgiEncode(customHtml),
+                    CT_CUSTOM_TEXT_VAR, cgiEncode(dyStringCannibalize(&dsCustomText)));
+return TRUE;
+}
+
 void extraUiLinks(char *db,struct trackDb *tdb)
 // Show metadata, and downloads, schema links where appropriate
 {
+makeMultiRegionLink(db, tdb);
+
 struct slPair *pairs = trackDbMetaPairs(tdb);
 if (pairs != NULL)
     printf("<b>Metadata:</b><br>%s\n", pairsAsHtmlTable( pairs, tdb, FALSE, FALSE));
 else if (!tdbIsComposite(tdb) && !trackHubDatabase(db) && (metadataForTable(db, tdb, NULL) != NULL))
     printf("<b>Metadata:</b><br>%s\n", metadataAsHtmlTable(db, tdb, FALSE, FALSE));
 
 boolean schemaLink = trackDataAccessible(db, tdb);
 boolean downloadLink = (trackDbSetting(tdb, "wgEncode") != NULL && !tdbIsSuperTrack(tdb));
 int links = 0;
 if (schemaLink)
     links++;
 if (downloadLink)
     links++;
 
 if (links > 0)