d55f8036a2a03c72c31b2e70d6adb22d8d0301cb
kate
  Thu Aug 9 15:52:05 2018 -0700
Add setting to offset target endpoints from source endpoints. refs #21109

diff --git src/hg/hgTracks/interactTrack.c src/hg/hgTracks/interactTrack.c
index b19dba2..688a982 100644
--- src/hg/hgTracks/interactTrack.c
+++ src/hg/hgTracks/interactTrack.c
@@ -168,47 +168,49 @@
 {
 int sourceCenter = 0, targetCenter = 0;
 interactRegionCenters(inter, &sourceCenter, &targetCenter);
 return abs(targetCenter - sourceCenter);
 }
 
 int getX(int pos, int seqStart, double scale, int xOff)
 /* Get x coordinate of a genomic location. Return -1 if off-screen */
 {
 if (pos < seqStart)
     return -1;
 return ((double)(pos - seqStart + .5) * scale) + xOff;
 }
 
 struct interactTrackInfo {
-    boolean isDirectional;
+    boolean isDirectional; // source and target are distinct item types
+    boolean isOffset;   // source and target ends are on different horizontals
     boolean doOtherLabels;  // true to suppress labels on other chrom items (prevent overlap)
     int maxSize;        // longest interaction (midpoint to midpoint) in bp
     int fontHeight;
     int sameCount;      // number of same chromosome interactions in window
     int sameHeight;     // vertical space for same chromosome interactions
     int otherCount;     // number of other chromosome interactions in window
     int otherHeight;    // vertical space for other chromosome interactions
 } interactTrackInfo;
 
 struct interactTrackInfo *interactGetTrackInfo(struct track *tg, int seqStart, struct hvGfx *hvg,                                                       int xOff, MgFont *font, double scale)
 /* Get layout info from interact items in window */
 {
 struct interactTrackInfo *tInfo = NULL;
 AllocVar(tInfo);
 tInfo->doOtherLabels = TRUE;
 tInfo->isDirectional = interactUiDirectional(tg->tdb);
+tInfo->isOffset = interactUiOffset(tg->tdb);
 
 char *otherChrom = NULL;
 int prevLabelEnd = 0, prevLabelStart = 0;
 char *prevLabel = 0;
 struct interact *inter;
 
 for (inter = (struct interact *)tg->items; inter; inter = inter->next)
     {
     otherChrom = interactOtherChrom(inter);
     if (otherChrom == NULL)
         {
         tInfo->sameCount++;
         // determine maximum interaction size, for later use laying out 'peaks'
         int size = interactSize(inter);
         if (size > tInfo->maxSize)
@@ -376,125 +378,132 @@
     // NOTE: until time permits, force to rectangle when in reversed strand mode.
 
     if (sOnScreen)
         {
         // draw foot of source region (2 pixels high)
         hvGfxBox(hvg, sX - sWidth, yOff, sWidth + sWidth + 1, 2, color);
         if (vis == tvDense || !tOnScreen || draw == DRAW_LINE || hvg->rc)
             {
             // draw vertical
             if (isReversed)
                 hvGfxDottedLine(hvg, sX, yOff, sX, peak, color, TRUE);
             else
                 hvGfxLine(hvg, sX, yOff, sX, peak, color);
             }
         }
+    int yOffTarget = (tInfo->isOffset ? yOff + tg->height/20 + 1 : yOff);
     if (tOnScreen)
         {
         // draw foot of target region (2 pixels high)
-        hvGfxBox(hvg, tX - tWidth, yOff, tWidth + tWidth + 1, 2, color);
+        hvGfxBox(hvg, tX - tWidth, yOffTarget, tWidth + tWidth + 1, 2, color);
         if (vis == tvDense || !sOnScreen || draw == DRAW_LINE || hvg->rc)
             {
             // draw vertical
             if (isReversed)
-                hvGfxDottedLine(hvg, tX, yOff, tX, peak, color, TRUE);
+                hvGfxDottedLine(hvg, tX, yOffTarget, tX, peak, color, TRUE);
             else
-                hvGfxLine(hvg, tX, yOff, tX, peak, color);
+                hvGfxLine(hvg, tX, yOffTarget, tX, peak, color);
             }
         }
     if (vis == tvDense)
         continue;
 
     // Full mode: add map boxes and draw interaction
+    int highlightColor = MG_WHITE;
     int chromStart = inter->chromStart;
     int chromEnd = inter->chromEnd;
     char *nameBuf = NULL;
     if (sOnScreen)
         {
         // add map box to source region
         nameBuf = isEmptyTextField(inter->sourceName) ? statusBuf : inter->sourceName;
+        //hvGfxBox(hvg, sX-1, yOff-1, 3, 3, peakColor); // needed ?
         hvGfxBox(hvg, sX-1, yOff, 3, 2, peakColor);
-        hvGfxBox(hvg, sX, yOff, 1, 1, MG_WHITE);
+        hvGfxBox(hvg, sX, yOff, 1, 1, highlightColor);
         mapBoxHgcOrHgGene(hvg, chromStart, chromEnd, 
                            sX - sWidth, yOff, sWidth * 2, 4,
                            tg->track, itemBuf, nameBuf, NULL, TRUE, NULL);
         }
     if (tOnScreen)
         {
         // add map box to target region
         nameBuf = isEmptyTextField(inter->targetName) ? statusBuf : inter->targetName;
-        hvGfxBox(hvg, tX-1, yOff, 3, 2, peakColor);
-        hvGfxBox(hvg, tX, yOff, 1, 1, MG_WHITE);
+        //hvGfxBox(hvg, tX-1, yOffTarget-1, 3, 3, tInfo->isDirectional ? MG_MAGENTA : peakColor);
+        hvGfxBox(hvg, tX-1, yOffTarget, 3, 2, tInfo->isDirectional ? MG_MAGENTA : peakColor);
+        hvGfxBox(hvg, tX, yOffTarget, 1, 1, highlightColor);
         mapBoxHgcOrHgGene(hvg, chromStart, chromEnd, 
-                        tX - tWidth, yOff, tWidth * 2, 4,
+                        //tX - tWidth, yOffTarget, tWidth * 2, 4,
+                        tX - tWidth, yOffTarget, tWidth * 2, 3,
                         tg->track, itemBuf, nameBuf, NULL, TRUE, NULL);
         }
     if ((s < seqStart && t < seqStart) || (s > seqEnd && t > seqEnd))
         continue;
 
     // Draw interaction and map boxes
     int lowerX = 0, upperX = 0;
     if (s < t)
         {
         lowerX = sOnScreen ? sX : xOff;
         upperX = tOnScreen ? tX : xOff + width;
         }
     else
         {
         lowerX = tOnScreen ? tX : xOff;
         upperX = sOnScreen ? sX : xOff + width;
         }
     if (draw == DRAW_LINE || !sOnScreen || !tOnScreen || hvg->rc)
         {
         // draw horizontal line between region centers at 'peak' height
         if (isReversed)
             hvGfxDottedLine(hvg, lowerX, peak, upperX, peak, color, TRUE);
         else
             hvGfxLine(hvg, lowerX, peak, upperX, peak, color);
 
         // map box on mid-point of horizontal line
         int xMap = lowerX + (double)(upperX-lowerX)/2;
         int yMap = peak-1;
         hvGfxBox(hvg, xMap-1, peak-1, 3, 3, peakColor);
-        hvGfxBox(hvg, xMap, peak, 1, 1, MG_WHITE);
+        hvGfxBox(hvg, xMap, peak, 1, 1, highlightColor);
         mapBoxHgcOrHgGene(hvg, chromStart, chromEnd, xMap-1, yMap-1, 3, 3,
                            tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
         continue;
         }
     // Draw curves
     if (draw == DRAW_CURVE)
         {
         int peakX = ((upperX - lowerX + 1) / 2) + lowerX;
         int peakY = peak + 30; // admittedly a hack (obscure how to define ypeak of curve)
-        int maxY = hvGfxCurve(hvg, lowerX, yOff, peakX, peakY, upperX, yOff, color, isReversed);
+        int maxY = hvGfxCurve(hvg, lowerX, 
+                                (isReversed ? yOffTarget : yOff), peakX, peakY, upperX, 
+                                (isReversed ? yOff : yOffTarget), color, isReversed);
         // curve drawer does not use peakY as expected, so it returns actual max Y used
         // draw map box on peak
         hvGfxBox(hvg, peakX-1, maxY-1, 3, 3, peakColor);
-        hvGfxBox(hvg, peakX, maxY, 1, 1, MG_WHITE);
+        hvGfxBox(hvg, peakX, maxY, 1, 1, highlightColor);
         mapBoxHgcOrHgGene(hvg, chromStart, chromEnd, peakX-1, maxY-1, 3, 3,
                        tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
         }
     else if (draw == DRAW_ELLIPSE)
         {
-        int yLeft = yOff + peakHeight;
-        int yTop = yOff - peakHeight;
+        int yLeft = yOffTarget + peakHeight;
+        int yTop = yOffTarget - peakHeight;
         hvGfxEllipseDraw(hvg, lowerX, yLeft, upperX, yTop, color, ELLIPSE_BOTTOM, isReversed);
         // draw map box on peak
-        int maxY = peakHeight + yOff;
+        int maxY = peakHeight + yOffTarget;
         int peakX = ((upperX - lowerX + 1) / 2) + lowerX;
         hvGfxBox(hvg, peakX-1, maxY-1, 3, 3, peakColor);
-        hvGfxBox(hvg, peakX, maxY, 1, 1, MG_WHITE);
+        hvGfxBox(hvg, peakX, maxY, 1, 1, highlightColor);
         mapBoxHgcOrHgGene(hvg, chromStart, chromEnd, peakX-1, maxY-1, 3, 3,
                        tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
         }
     }
 }
 
 void interactDrawLeftLabels(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)
 /* Override default */
 {
 }
 
 void interactMethods(struct track *tg)