src/hg/hgTracks/hgTracks.c 1.1612

1.1612 2009/12/09 03:30:20 tdreszer
Checkin for FLAT_TRACKS for dragReorder. Also several other features worked out or cleaned up
Index: src/hg/hgTracks/hgTracks.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/hgTracks/hgTracks.c,v
retrieving revision 1.1611
retrieving revision 1.1612
diff -b -B -U 4 -r1.1611 -r1.1612
--- src/hg/hgTracks/hgTracks.c	5 Dec 2009 01:29:00 -0000	1.1611
+++ src/hg/hgTracks/hgTracks.c	9 Dec 2009 03:30:20 -0000	1.1612
@@ -293,10 +293,12 @@
     char link[512];
     safef(link,sizeof(link),"%s?%s=%u&g=%s",
         hgTrackUiName(), cartSessionVarName(),cartSessionId(cart), encodedName);
     char title[128];
+
     safef(title,sizeof(title),"%s controls", shortLabel);
-    imgTrackAddMapItem(curImgTrack,link,title,x, y, x+width, y+height, id);
+    struct imgSlice *curSlice = imgTrackSliceGetByType(curImgTrack,stButton);
+    sliceAddLink(curSlice,link,title);
     }
 else
     {
     hPrintf("<AREA SHAPE=RECT COORDS=\"%d,%d,%d,%d\" ", x, y, x+width, y+height);
@@ -1260,14 +1262,18 @@
 static int doCenterLabels(struct track *track, struct track *parentTrack,
                                 struct hvGfx *hvg, MgFont *font, int y)
 /* Draw center labels.  Return y coord */
 {
-int trackPastTabX = (withLeftLabels ? trackTabWidth : 0);
-int trackPastTabWidth = tl.picWidth - trackPastTabX;
-int fontHeight = mgFontLineHeight(font);
-int insideHeight = fontHeight-1;
 if (track->limitedVis != tvHide)
     {
+#ifdef FLAT_TRACK_LIST
+    if(isWithCenterLabels(track))
+#endif//def FLAT_TRACK_LIST
+        {
+        int trackPastTabX = (withLeftLabels ? trackTabWidth : 0);
+        int trackPastTabWidth = tl.picWidth - trackPastTabX;
+        int fontHeight = mgFontLineHeight(font);
+        int insideHeight = fontHeight-1;
     Color labelColor = (track->labelColor ?
                         track->labelColor : track->ixColor);
     hvGfxTextCentered(hvg, insideX, y+1, insideWidth, insideHeight,
                         labelColor, font, track->longLabel);
@@ -1280,8 +1286,9 @@
     else
         mapBoxToggleVis(hvg, trackPastTabX, y+1,trackPastTabWidth, insideHeight,
                         (theImgBox ? track : parentTrack));
     y += fontHeight;
+        }
     y += track->totalHeight(track, track->limitedVis);
     }
 return y;
 }
@@ -1543,8 +1550,231 @@
     }
 return vis;
 }
 
+static int makeRulerZoomBoxes(struct hvGfx *hvg, struct cart *cart,int winStart,int winEnd,int insideWidth,int seqBaseCount,int rulerClickY,int rulerClickHeight)
+{
+/* Make hit boxes that will zoom program around ruler. */
+int boxes = 30;
+int winWidth = winEnd - winStart;
+int newWinWidth = winWidth;
+int i, ws, we = 0, ps, pe = 0;
+int mid, ns, ne;
+double wScale = (double)winWidth/boxes;
+double pScale = (double)insideWidth/boxes;
+char message[32];
+char *zoomType = cartCgiUsualString(cart, RULER_BASE_ZOOM_VAR, ZOOM_3X);
+
+safef(message, sizeof(message), "%s zoom", zoomType);
+if (sameString(zoomType, ZOOM_1PT5X))
+    newWinWidth = winWidth/1.5;
+else if (sameString(zoomType, ZOOM_3X))
+    newWinWidth = winWidth/3;
+else if (sameString(zoomType, ZOOM_10X))
+    newWinWidth = winWidth/10;
+else if (sameString(zoomType, ZOOM_BASE))
+    newWinWidth = insideWidth/tl.mWidth;
+else
+    errAbort("invalid zoom type %s", zoomType);
+
+if (newWinWidth < 1)
+    newWinWidth = 1;
+
+for (i=1; i<=boxes; ++i)
+    {
+    ps = pe;
+    ws = we;
+    pe = round(pScale*i);
+    we = round(wScale*i);
+    mid = (ws + we)/2 + winStart;
+    ns = mid-newWinWidth/2;
+    ne = ns + newWinWidth;
+    if (ns < 0)
+        {
+        ns = 0;
+        ne -= ns;
+        }
+    if (ne > seqBaseCount)
+        {
+        ns -= (ne - seqBaseCount);
+        ne = seqBaseCount;
+        }
+    if(!dragZooming)
+        {
+        mapBoxJumpTo(hvg, ps+insideX,rulerClickY,pe-ps,rulerClickHeight,
+                        chromName, ns, ne, message);
+        }
+    }
+return newWinWidth;
+}
+
+static int doDrawRuler(struct hvGfx *hvg,int *newWinWidth,int *rulerClickHeight,int rulerHeight,int yAfterRuler,
+                     int yAfterBases, MgFont *font,int fontHeight,boolean rulerCds)
+{
+/* draws the ruler. */
+int scaleBarPad = 2;
+int scaleBarHeight = fontHeight;
+int scaleBarTotalHeight = fontHeight + 2 * scaleBarPad;
+int titleHeight = fontHeight;
+int baseHeight = fontHeight;
+//int yAfterBases = yAfterRuler;
+int showPosHeight = fontHeight;
+int codonHeight = fontHeight;
+    struct dnaSeq *seq = NULL;
+    int rulerClickY = 0;
+    *rulerClickHeight = rulerHeight;
+
+    int y = rulerClickY;
+    hvGfxSetClip(hvg, insideX, y, insideWidth, yAfterRuler-y+1);
+    int relNumOff = winStart;
+
+    if (baseTitle)
+        {
+        hvGfxTextCentered(hvg, insideX, y, insideWidth, titleHeight,MG_BLACK, font, baseTitle);
+        *rulerClickHeight += titleHeight;
+        y += titleHeight;
+        }
+    if (baseShowPos||baseShowAsm)
+        {
+        char txt[256];
+        char numBuf[SMALLBUF];
+        char *freezeName = NULL;
+        freezeName = hFreezeFromDb(database);
+        sprintLongWithCommas(numBuf, winEnd-winStart);
+        if(freezeName == NULL)
+            freezeName = "Unknown";
+        if (baseShowPos&&baseShowAsm)
+            safef(txt,sizeof(txt),"%s %s   %s (%s bp)",organism,freezeName,addCommasToPos(database, position),numBuf);
+        else if (baseShowPos)
+            safef(txt,sizeof(txt),"%s (%s bp)",addCommasToPos(database, position),numBuf);
+        else
+            safef(txt,sizeof(txt),"%s %s",organism,freezeName);
+        hvGfxTextCentered(hvg, insideX, y, insideWidth, showPosHeight,MG_BLACK, font, txt);
+        *rulerClickHeight += showPosHeight;
+        freez(&freezeName);
+        y += showPosHeight;
+        }
+    if (baseShowScaleBar)
+        {
+        char scaleText[32];
+        int numBases = winEnd-winStart;
+        int scaleBases = computeScaleBar(numBases, scaleText, sizeof(scaleText));
+        int scalePixels = (int)((double)insideWidth*scaleBases/numBases);
+        int scaleBarX = insideX + (int)(((double)insideWidth-scalePixels)/2);
+        int scaleBarEndX = scaleBarX + scalePixels;
+        int scaleBarY = y + 0.5 * scaleBarTotalHeight;
+        *rulerClickHeight += scaleBarTotalHeight;
+        hvGfxTextRight(hvg, insideX, y + scaleBarPad,
+                (scaleBarX-2)-insideX, scaleBarHeight, MG_BLACK, font, scaleText);
+        hvGfxLine(hvg, scaleBarX, scaleBarY, scaleBarEndX, scaleBarY, MG_BLACK);
+        hvGfxLine(hvg, scaleBarX, y+scaleBarPad, scaleBarX,
+                y+scaleBarTotalHeight-scaleBarPad, MG_BLACK);
+        hvGfxLine(hvg, scaleBarEndX, y+scaleBarPad, scaleBarEndX,
+                y+scaleBarTotalHeight-scaleBarPad, MG_BLACK);
+        y += scaleBarTotalHeight;
+        }
+    if (baseShowRuler)
+        {
+        hvGfxDrawRulerBumpText(hvg, insideX, y, rulerHeight, insideWidth, MG_BLACK,
+                    font, relNumOff, winBaseCount, 0, 1);
+        }
+    *newWinWidth = makeRulerZoomBoxes(hvg, cart,winStart,winEnd,insideWidth,seqBaseCount,rulerClickY,*rulerClickHeight);
+
+    if (zoomedToBaseLevel || rulerCds)
+        {
+        Color baseColor = MG_BLACK;
+        int start, end, chromSize;
+        struct dnaSeq *extraSeq;
+        /* extraSeq has extra leading & trailing bases
+        * for translation in to amino acids */
+        boolean complementRulerBases =
+                cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE);
+        // gray bases if not matching the direction of display
+        if (complementRulerBases != revCmplDisp)
+            baseColor = MG_GRAY;
+
+        /* get sequence, with leading & trailing 3 bases
+         * used for amino acid translation */
+        start = max(winStart - 3, 0);
+        chromSize = hChromSize(database, chromName);
+        end = min(winEnd + 3, chromSize);
+        extraSeq = hDnaFromSeq(database, chromName, start, end, dnaUpper);
+        if (start != winStart - 3 || end != winEnd + 3)
+            {
+            /* at chromosome boundaries, pad with N's to assure
+             * leading & trailing 3 bases */
+            char header[4] = "NNN", trailer[4] = "NNN";
+            int size = winEnd - winStart + 6;
+            char *padded = (char *)needMem(size+1);
+            header[max(3 - winStart, 0)] = 0;
+            trailer[max(winEnd - chromSize + 3, 0)] = 0;
+            safef(padded, size+1, "%s%s%s", header, extraSeq->dna, trailer);
+            extraSeq = newDnaSeq(padded, strlen(padded), extraSeq->name);
+            }
+
+        /* for drawing bases, must clip off leading and trailing 3 bases */
+        seq = cloneDnaSeq(extraSeq);
+        seq = newDnaSeq(seq->dna+3, seq->size-6, seq->name);
+
+        if (zoomedToBaseLevel)
+            drawBases(hvg, insideX, y+rulerHeight, insideWidth, baseHeight,
+                baseColor, font, complementRulerBases, seq);
+
+        /* set up clickable area to toggle ruler visibility */
+            {
+            char newRulerVis[100];
+            safef(newRulerVis, 100, "%s=%s", RULER_TRACK_NAME,
+                         rulerMode == tvFull ?
+                                rulerMenu[tvDense] :
+                                rulerMenu[tvFull]);
+            mapBoxReinvoke(hvg, insideX, y+rulerHeight, insideWidth,baseHeight,
+                NULL, NULL, 0, 0, "", newRulerVis);
+            }
+        if (rulerCds)
+            {
+            /* display codons */
+            int frame;
+            int firstFrame = 0;
+            int mod;            // for determining frame ordering on display
+            struct simpleFeature *sfList;
+            double scale = scaleForWindow(insideWidth, winStart, winEnd);
+
+            /* WARNING: tricky code to assure that an amino acid
+             * stays in the same frame line on the browser during panning.
+             * There may be a simpler way... */
+            if (complementRulerBases)
+                mod = (chromSize - winEnd) % 3;
+            else
+                mod = winStart % 3;
+            if (mod == 0)
+                firstFrame = 0;
+            else if (mod == 1)
+                firstFrame = 2;
+            else if (mod == 2)
+                firstFrame = 1;
+
+            y = yAfterBases;
+            if (complementRulerBases)
+                reverseComplement(extraSeq->dna, extraSeq->size);
+            for (frame = 0; frame < 3; frame++, y += codonHeight)
+                {
+                /* reference frame to start of chromosome */
+                int refFrame = (firstFrame + frame) % 3;
+
+                /* create list of codons in the specified coding frame */
+                sfList = baseColorCodonsFromDna(refFrame, winStart, winEnd,
+                                             extraSeq, complementRulerBases);
+                /* draw the codons in the list, with alternating colors */
+                baseColorDrawRulerCodons(hvg, sfList, scale, insideX, y,
+                                    codonHeight, font, winStart, MAXPIXELS,
+                                    zoomedToCodonLevel);
+                }
+            }
+        }
+    hvGfxUnclip(hvg);
+return y;
+}
+
 void makeActiveImage(struct track *trackList, char *psOutput)
 /* Make image and image map. */
 {
 struct track *track;
@@ -1569,9 +1799,8 @@
 int codonHeight = fontHeight;
 int rulerTranslationHeight = codonHeight * 3;        // 3 frames
 int yAfterRuler = gfxBorder;
 int yAfterBases = yAfterRuler;  // differs if base-level translation shown
-int relNumOff;
 boolean rulerCds = zoomedToCdsColorLevel;
 int rulerClickHeight = 0;
 int newWinWidth = 0;
 
@@ -1587,10 +1816,10 @@
 //struct imgTrack *curImgTrack = NULL; // Make this global for now to avoid huge rewrite
 struct imgSlice *curSlice    = NULL; // No need to be global, only the map needs to be global
 struct mapSet   *curMap      = NULL; // Make this global for now to avoid huge rewrite
 // Set up imgBox dimensions
-int sliceWidth[isMaxSliceTypes]; // Just being explicit
-int sliceOffsetX[isMaxSliceTypes];
+int sliceWidth[stMaxSliceTypes]; // Just being explicit
+int sliceOffsetX[stMaxSliceTypes];
 int sliceHeight        = 0;
 int sliceOffsetY       = 0;
 char *rulerTtl = NULL;
 if(theImgBox)  // theImgBox is a global for now to avoid huge rewrite of hgTracks.  It is started prior to this in doTrackForm()
@@ -1613,16 +1842,20 @@
     memset((char *)sliceWidth,  0,sizeof(sliceWidth));
     memset((char *)sliceOffsetX,0,sizeof(sliceOffsetX));
     if (withLeftLabels)
         {
-        sliceWidth[isButton]   = trackTabWidth + 1;
-        sliceWidth[isSide]     = leftLabelWidth - sliceWidth[isButton] + 2;
-        sliceOffsetX[isSide]   = (revCmplDisp? (tl.picWidth - sliceWidth[isSide] - sliceWidth[isButton]) : sliceWidth[isButton]);
-        sliceOffsetX[isButton] = (revCmplDisp? (tl.picWidth - sliceWidth[isButton]) : 0);
-        }
-    sliceOffsetX[isData] = (revCmplDisp?0:sliceWidth[isSide] + sliceWidth[isButton]);
-    sliceWidth[isData]   = tl.picWidth - (sliceWidth[isSide] + sliceWidth[isButton]);
-    }
+        sliceWidth[stButton]   = trackTabWidth + 1;
+        sliceWidth[stSide]     = leftLabelWidth - sliceWidth[stButton] + 2;
+        sliceOffsetX[stSide]   = (revCmplDisp? (tl.picWidth - sliceWidth[stSide] - sliceWidth[stButton]) : sliceWidth[stButton]);
+        sliceOffsetX[stButton] = (revCmplDisp? (tl.picWidth - sliceWidth[stButton]) : 0);
+        }
+    sliceOffsetX[stData] = (revCmplDisp?0:sliceWidth[stSide] + sliceWidth[stButton]);
+    sliceWidth[stData]   = tl.picWidth - (sliceWidth[stSide] + sliceWidth[stButton]);
+    }
+#ifdef FLAT_TRACK_LIST
+struct flatTracks *flatTracks = NULL;
+struct flatTracks *flatTrack = NULL;
+#endif//def FLAT_TRACK_LIST
 
 if (rulerMode != tvFull)
     {
     rulerCds = FALSE;
@@ -1712,10 +1945,19 @@
 			subtrack->limitedVis = tvMin(vis,subtrack->visibility);
 			subtrack->limitedVisSet = (subtrack->limitedVis != tvHide && subtrack->visibility != subtrack->limitedVis);
 			}
                     }
+                #ifdef FLAT_TRACK_LIST
+                subtrack->hasUi = track->hasUi;
+                flatTracksAdd(&flatTracks,subtrack,cart);
+                pixHeight += trackPlusLabelHeight(subtrack, fontHeight);
+                #endif//def FLAT_TRACK_LIST
                 }
             }
+        #ifdef FLAT_TRACK_LIST
+        else
+            flatTracksAdd(&flatTracks,track,cart);
+        #endif//def FLAT_TRACK_LIST
         if (maxSafeHeight < (pixHeight+trackPlusLabelHeight(track,fontHeight)))
             {
             char numBuf[SMALLBUF];
             sprintLongWithCommas(numBuf, maxSafeHeight);
@@ -1726,20 +1968,31 @@
             track->limitedVis = tvHide;
             track->limitedVisSet = TRUE;
             }
         else
+        #ifdef FLAT_TRACK_LIST
+        if (!tdbIsComposite(track->tdb))
+        #endif//def FLAT_TRACK_LIST
             pixHeight += trackPlusLabelHeight(track, fontHeight);
         }
     }
+#ifdef FLAT_TRACK_LIST
+flatTracksSort(&flatTracks); // Now we should have a perfectly good flat track list!
+#endif//def FLAT_TRACK_LIST
 
 imagePixelHeight = pixHeight;
 if (psOutput)
     hvg = hvGfxOpenPostScript(pixWidth, pixHeight, psOutput);
 else
     {
 #ifdef USE_PNG
     trashDirFile(&gifTn, "hgt", "hgt", ".png");
+    #ifdef IMAGEv2_BG_IMAGE
+    hvg = hvGfxOpenPng(pixWidth, pixHeight, gifTn.forCgi, (theImgBox!=NULL?TRUE:FALSE));  // transparent when BG is defined
+    #else//ifndef IMAGEv2_BG_IMAGE
     hvg = hvGfxOpenPng(pixWidth, pixHeight, gifTn.forCgi, FALSE);
+    #endif//ndef IMAGEv2_BG_IMAGE
+
 #else
     trashDirFile(&gifTn, "hgt", "hgt", ".gif");
     hvg = hvGfxOpenGif(pixWidth, pixHeight, gifTn.forCgi, FALSE);
 #endif // USE_PNG
@@ -1757,10 +2010,37 @@
 
 /* Find colors to draw in. */
 findTrackColors(hvg, trackList);
 
-// TODO: Prior to image, make all imgTracks, including one for each visible subtrack
-//       Then dragReorder can work per subtrack!!!
+// 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 centerlabel, not reorderable
+        }
+#ifdef FLAT_TRACK_LIST
+    for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next)
+        {
+        track = flatTrack->track;
+#else//ifndef FLAT_TRACK_LIST
+    for (track = trackList; track != NULL; track = track->next)
+        {
+#endif//ndef FLAT_TRACK_LIST
+        if (track->limitedVis != tvHide)
+            {
+            #ifdef FLAT_TRACK_LIST
+            int order = flatTrack->order;
+            #else//ifndef FLAT_TRACK_LIST
+            char var[128];
+            safef(var,sizeof(var),"%s_%s",track->tdb->tableName,IMG_ORDER_VAR);
+            int order = cartUsualInt(cart, var,IMG_ANYORDER);
+            #endif//ndef FLAT_TRACK_LIST
+            curImgTrack = imgBoxTrackFindOrAdd(theImgBox,track->tdb,NULL,track->limitedVis,isWithCenterLabels(track),order);
+            }
+        }
+    }
+
 
 /* Draw mini-buttons. */
 if (withLeftLabels && psOutput == NULL)
     {
@@ -1778,19 +2058,28 @@
             {
             // Mini-buttons (side label slice) for ruler
             sliceHeight      = height + 1;
             sliceOffsetY     = 0;
-            curImgTrack = imgBoxTrackFindOrAdd(theImgBox,NULL,RULER_TRACK_NAME,rulerMode,FALSE,IMG_FIXEDPOS); // No tdb, no centerlabel, not reorderable
-            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isButton,theOneImg,NULL,sliceWidth[isButton],sliceHeight,sliceOffsetX[isButton],sliceOffsetY);
-            curMap      = sliceMapFindOrStart(curSlice,RULER_TRACK_NAME,NULL); // No common linkRoot
+            curImgTrack = imgBoxTrackFind(theImgBox,NULL,RULER_TRACK_NAME);
+            #ifdef FLAT_TRACK_LIST
+            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stButton,NULL,NULL,sliceWidth[stButton],sliceHeight,sliceOffsetX[stButton],sliceOffsetY); // flatTracksButton is all html, no jpg
+            #else//ifndef FLAT_TRACK_LIST
+            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stButton,theOneImg,NULL,sliceWidth[stButton],sliceHeight,sliceOffsetX[stButton],sliceOffsetY);
+            #endif//ndef FLAT_TRACK_LIST
             }
         drawGrayButtonBox(hvg, trackTabX, y, trackTabWidth, height, TRUE);
         mapBoxTrackUi(hvg, trackTabX, y, trackTabWidth, height,
 		      RULER_TRACK_NAME, RULER_TRACK_LABEL, "ruler");
         y += height + 1;
         }
+#ifdef FLAT_TRACK_LIST
+    for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next)
+        {
+        track = flatTrack->track;
+#else//ifndef FLAT_TRACK_LIST
     for (track = trackList; track != NULL; track = track->next)
         {
+#endif//ndef FLAT_TRACK_LIST
         int h, yStart = y, yEnd;
         if (track->limitedVis != tvHide)
             {
             y += trackPlusLabelHeight(track, fontHeight);
@@ -1809,21 +2098,23 @@
                             h, track->hasUi);
             if(theImgBox)
                 {
                 // Mini-buttons (side label slice) for tracks
-                sliceHeight      = h;
-                sliceOffsetY     = yStart;
-                curImgTrack = imgBoxTrackFindOrAdd(theImgBox,track->tdb,NULL,track->limitedVis,isWithCenterLabels(track),IMG_ANYORDER);
-                curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isButton,theOneImg,NULL,sliceWidth[isButton],sliceHeight,sliceOffsetX[isButton],sliceOffsetY);
+                sliceHeight      = yEnd - yStart;
+                sliceOffsetY     = yStart - 1;
+                curImgTrack = imgBoxTrackFind(theImgBox,track->tdb,NULL);
+                #ifdef FLAT_TRACK_LIST
+                curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stButton,NULL,NULL,sliceWidth[stButton],sliceHeight,sliceOffsetX[stButton],sliceOffsetY); // flatTracksButton is all html, no jpg
+                #else//ifndef FLAT_TRACK_LIST
+                curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stButton,theOneImg,NULL,sliceWidth[stButton],sliceHeight,sliceOffsetX[stButton],sliceOffsetY);
+                #endif//ndef FLAT_TRACK_LIST
                 }
             if (track->hasUi)
                 {
-                if(theImgBox)
-                    {
-                    curMap      = sliceMapFindOrStart(curSlice,track->tdb->tableName,NULL); // No common linkRoot
-                    }
-                mapBoxTrackUi(hvg, trackTabX, yStart, trackTabWidth, h,
-			      track->mapName, track->shortLabel, track->mapName);
+                if(tdbIsCompositeChild(track->tdb))
+                    mapBoxTrackUi(hvg, trackTabX, yStart, trackTabWidth, (yEnd - yStart - 1), track->tdb->parent->tableName, track->tdb->parent->shortLabel, track->mapName);
+                else
+                    mapBoxTrackUi(hvg, trackTabX, yStart, trackTabWidth, h, track->mapName, track->shortLabel, track->mapName);
             }
 	    }
 	}
     butOff = trackTabX + trackTabWidth;
@@ -1844,10 +2135,10 @@
             {
             // side label slice for ruler
             sliceHeight      = basePositionHeight + (rulerCds ? rulerTranslationHeight : 0) + 1;
             sliceOffsetY     = 0;
-            curImgTrack = imgBoxTrackFindOrAdd(theImgBox,NULL,RULER_TRACK_NAME,rulerMode,FALSE,IMG_FIXEDPOS); // No tdb, no centerlabel,not reorderable
-            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isSide,theOneImg,NULL,sliceWidth[isSide],sliceHeight,sliceOffsetX[isSide],sliceOffsetY);
+            curImgTrack = imgBoxTrackFind(theImgBox,NULL,RULER_TRACK_NAME);
+            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stSide,theOneImg,NULL,sliceWidth[stSide],sliceHeight,sliceOffsetX[stSide],sliceOffsetY);
             curMap      = sliceMapFindOrStart(curSlice,RULER_TRACK_NAME,NULL); // No common linkRoot
             }
         if (baseTitle)
             {
@@ -1901,10 +2192,16 @@
             }
             if (rulerCds)
                 y += rulerTranslationHeight;
 	}
+#ifdef FLAT_TRACK_LIST
+    for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next)
+        {
+        track = flatTrack->track;
+#else//ifndef FLAT_TRACK_LIST
     for (track = trackList; track != NULL; track = track->next)
         {
+#endif//ndef FLAT_TRACK_LIST
         if (track->limitedVis == tvHide)
             continue;
          if(theImgBox)
             {
@@ -1913,13 +2210,14 @@
             // This will need to change to allow drag and drop.  Until then the subtrack center labels will drag scroll while the composte will not.
             // But as soon as subtracks are individual image tracks: problems with buttons, left labels, center labels, drag and drop, etc.
             sliceHeight      = trackPlusLabelHeight(track, fontHeight);
             sliceOffsetY     = y;
-            curImgTrack = imgBoxTrackFindOrAdd(theImgBox,track->tdb,NULL,track->limitedVis,isWithCenterLabels(track),IMG_ANYORDER);
-            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isSide,theOneImg,NULL,sliceWidth[isSide],sliceHeight,sliceOffsetX[isSide],sliceOffsetY);
+            curImgTrack = imgBoxTrackFind(theImgBox,track->tdb,NULL);
+            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stSide,theOneImg,NULL,sliceWidth[stSide],sliceHeight,sliceOffsetX[stSide],sliceOffsetY);
             curMap      = sliceMapFindOrStart(curSlice,track->tdb->tableName,NULL); // No common linkRoot
             }
-        if (trackIsCompositeWithSubtracks(track))  //TODO: Change when tracks->subtracks are always set for composite
+#ifndef FLAT_TRACK_LIST
+        if (trackIsCompositeWithSubtracks(track))
             {
             struct track *subtrack;
             if (isWithCenterLabels(track))
                 y += fontHeight;
@@ -1932,8 +2230,9 @@
                 }
             track->nextItemButtonable = FALSE; // Composites are not NextItemButtonable (but subtracks may be)
             }
         else
+#endif//ndef FLAT_TRACK_LIST
             y = doLeftLabels(track, hvg, font, y);
         }
     }
 else
@@ -1950,18 +2249,30 @@
         // NOTE: The background image could easily be a reusable file, based upon zoom level and width.  Height could propbaby easily be stretched.
         // struct image *bgImg = imgBoxImageAdd(theImgBox,gifBg.forHtml,
         //    (char *)(dragZooming?"click or drag mouse in base position track to zoom in" : NULL),
         //    pixWidth, pixHeight,FALSE);
+    struct hvGfx *bgImg = hvg; // Default to the one image
+    #if defined(IMAGEv2_BG_IMAGE) && defined(USE_PNG)
+    if(theImgBox)
+        {
+        struct tempName gifBg;
+        trashDirFile(&gifBg, "hgt", "bg", ".png");  // TODO: We could have a few static files by (pixHeight*pixWidth)  And I doubt pixHeight is needed!
+        bgImg = hvGfxOpenPng(pixWidth, pixHeight, gifBg.forCgi, FALSE);
+        imgBoxImageAdd(theImgBox,gifBg.forHtml,NULL,pixWidth, pixHeight,TRUE); // Adds BG image
+        }
+    #endif //defined(IMAGEv2_BG_IMAGE) && defined(USE_PNG)
     int height = pixHeight - 2*gfxBorder;
     int x;
-    Color lightBlue = hvGfxFindRgb(hvg, &guidelineColor);
+    Color lightBlue = hvGfxFindRgb(bgImg, &guidelineColor);
 
-    hvGfxSetClip(hvg, insideX, gfxBorder, insideWidth, height);
+    hvGfxSetClip(bgImg, insideX, gfxBorder, insideWidth, height);
     y = gfxBorder;
 
     for (x = insideX+guidelineSpacing-1; x<pixWidth; x += guidelineSpacing)
-	hvGfxBox(hvg, x, y, 1, height, lightBlue);
-    hvGfxUnclip(hvg);
+        hvGfxBox(bgImg, x, y, 1, height, lightBlue);
+    hvGfxUnclip(bgImg);
+    if(bgImg != hvg)
+        hvGfxClose(&bgImg);
     }
 
 /* Show ruler at top. */
 if (rulerMode != tvHide)
@@ -1970,229 +2281,31 @@
         {
         // data slice for ruler
         sliceHeight      = basePositionHeight + (rulerCds ? rulerTranslationHeight : 0) + 1;
         sliceOffsetY     = 0;
-        curImgTrack = imgBoxTrackFindOrAdd(theImgBox,NULL,RULER_TRACK_NAME,rulerMode,FALSE,IMG_FIXEDPOS); // No tdb, no centerlabel,not reorderable
-        curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isData,theOneImg,rulerTtl,sliceWidth[isData],sliceHeight,sliceOffsetX[isData],sliceOffsetY);
+        curImgTrack = imgBoxTrackFind(theImgBox,NULL,RULER_TRACK_NAME);
+        curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stData,theOneImg,rulerTtl,sliceWidth[stData],sliceHeight,sliceOffsetX[stData],sliceOffsetY);
         curMap      = sliceMapFindOrStart(curSlice,RULER_TRACK_NAME,NULL); // No common linkRoot
         }
-    struct dnaSeq *seq = NULL;
-    int rulerClickY = 0;
-    rulerClickHeight = rulerHeight;
-
-    y = rulerClickY;
-    hvGfxSetClip(hvg, insideX, y, insideWidth, yAfterRuler-y+1);
-    relNumOff = winStart;
-
-    if (baseTitle)
-	{
-	hvGfxTextCentered(hvg, insideX, y, insideWidth, titleHeight,
-			    MG_BLACK, font, baseTitle);
-	rulerClickHeight += titleHeight;
-	y += titleHeight;
-	}
-    if (baseShowPos||baseShowAsm)
-	{
-	char txt[256];
-	char numBuf[SMALLBUF];
-	char *freezeName = NULL;
-	freezeName = hFreezeFromDb(database);
-	sprintLongWithCommas(numBuf, winEnd-winStart);
-	if(freezeName == NULL)
-	    freezeName = "Unknown";
-	if (baseShowPos&&baseShowAsm)
-    	    safef(txt,sizeof(txt),"%s %s   %s (%s bp)",organism,freezeName,addCommasToPos(database, position),numBuf);
-	else if (baseShowPos)
-    	    safef(txt,sizeof(txt),"%s (%s bp)",addCommasToPos(database, position),numBuf);
-	else
-    	    safef(txt,sizeof(txt),"%s %s",organism,freezeName);
-	hvGfxTextCentered(hvg, insideX, y, insideWidth, showPosHeight,
-			    MG_BLACK, font, txt);
-	rulerClickHeight += showPosHeight;
-	freez(&freezeName);
-	y += showPosHeight;
-	}
-    if (baseShowScaleBar)
-	{
-	char scaleText[32];
-	int numBases = winEnd-winStart;
-	int scaleBases = computeScaleBar(numBases, scaleText, sizeof(scaleText));
-	int scalePixels = (int)((double)insideWidth*scaleBases/numBases);
-	int scaleBarX = insideX + (int)(((double)insideWidth-scalePixels)/2);
-	int scaleBarEndX = scaleBarX + scalePixels;
-	int scaleBarY = y + 0.5 * scaleBarTotalHeight;
-	rulerClickHeight += scaleBarTotalHeight;
-	hvGfxTextRight(hvg, insideX, y + scaleBarPad,
-		       (scaleBarX-2)-insideX, scaleBarHeight, MG_BLACK, font, scaleText);
-	hvGfxLine(hvg, scaleBarX, scaleBarY, scaleBarEndX, scaleBarY, MG_BLACK);
-	hvGfxLine(hvg, scaleBarX, y+scaleBarPad, scaleBarX,
-		       y+scaleBarTotalHeight-scaleBarPad, MG_BLACK);
-	hvGfxLine(hvg, scaleBarEndX, y+scaleBarPad, scaleBarEndX,
-		       y+scaleBarTotalHeight-scaleBarPad, MG_BLACK);
-	y += scaleBarTotalHeight;
-	}
-    if (baseShowRuler)
-	{
-	hvGfxDrawRulerBumpText(hvg, insideX, y, rulerHeight, insideWidth, MG_BLACK,
-			       font, relNumOff, winBaseCount, 0, 1);
-	}
-    {
-    /* Make hit boxes that will zoom program around ruler. */
-    int boxes = 30;
-    int winWidth = winEnd - winStart;
-    newWinWidth = winWidth;
-    int i, ws, we = 0, ps, pe = 0;
-    int mid, ns, ne;
-    double wScale = (double)winWidth/boxes;
-    double pScale = (double)insideWidth/boxes;
-    char message[32];
-    char *zoomType = cartCgiUsualString(cart, RULER_BASE_ZOOM_VAR, ZOOM_3X);
-
-    safef(message, sizeof(message), "%s zoom", zoomType);
-    if (sameString(zoomType, ZOOM_1PT5X))
-        newWinWidth = winWidth/1.5;
-    else if (sameString(zoomType, ZOOM_3X))
-        newWinWidth = winWidth/3;
-    else if (sameString(zoomType, ZOOM_10X))
-        newWinWidth = winWidth/10;
-    else if (sameString(zoomType, ZOOM_BASE))
-        newWinWidth = insideWidth/tl.mWidth;
-    else
-        errAbort("invalid zoom type %s", zoomType);
-
-    if (newWinWidth < 1)
-	newWinWidth = 1;
-
-    for (i=1; i<=boxes; ++i)
-	{
-	ps = pe;
-	ws = we;
-	pe = round(pScale*i);
-	we = round(wScale*i);
-	mid = (ws + we)/2 + winStart;
-	ns = mid-newWinWidth/2;
-	ne = ns + newWinWidth;
-	if (ns < 0)
-	    {
-	    ns = 0;
-	    ne -= ns;
-	    }
-	if (ne > seqBaseCount)
-	    {
-	    ns -= (ne - seqBaseCount);
-	    ne = seqBaseCount;
-	    }
-        if(!dragZooming)
-            {
-            mapBoxJumpTo(hvg, ps+insideX,rulerClickY,pe-ps,rulerClickHeight,
-                         chromName, ns, ne, message);
-            }
-	}
-    }
-    if (zoomedToBaseLevel || rulerCds)
-        {
-        Color baseColor = MG_BLACK;
-        int start, end, chromSize;
-        struct dnaSeq *extraSeq;
-	/* extraSeq has extra leading & trailing bases
-	 * for translation in to amino acids */
-        boolean complementRulerBases =
-                cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE);
-        // gray bases if not matching the direction of display
-        if (complementRulerBases != revCmplDisp)
-            baseColor = MG_GRAY;
-
-        /* get sequence, with leading & trailing 3 bases
-         * used for amino acid translation */
-        start = max(winStart - 3, 0);
-        chromSize = hChromSize(database, chromName);
-        end = min(winEnd + 3, chromSize);
-        extraSeq = hDnaFromSeq(database, chromName, start, end, dnaUpper);
-        if (start != winStart - 3 || end != winEnd + 3)
-            {
-            /* at chromosome boundaries, pad with N's to assure
-             * leading & trailing 3 bases */
-            char header[4] = "NNN", trailer[4] = "NNN";
-            int size = winEnd - winStart + 6;
-            char *padded = (char *)needMem(size+1);
-            header[max(3 - winStart, 0)] = 0;
-            trailer[max(winEnd - chromSize + 3, 0)] = 0;
-            safef(padded, size+1, "%s%s%s", header, extraSeq->dna, trailer);
-            extraSeq = newDnaSeq(padded, strlen(padded), extraSeq->name);
-            }
-
-        /* for drawing bases, must clip off leading and trailing 3 bases */
-        seq = cloneDnaSeq(extraSeq);
-        seq = newDnaSeq(seq->dna+3, seq->size-6, seq->name);
-
-        if (zoomedToBaseLevel)
-    	    drawBases(hvg, insideX, y+rulerHeight, insideWidth, baseHeight,
-		  baseColor, font, complementRulerBases, seq);
-
-        /* set up clickable area to toggle ruler visibility */
-            {
-            char newRulerVis[100];
-            safef(newRulerVis, 100, "%s=%s", RULER_TRACK_NAME,
-                         rulerMode == tvFull ?
-                                rulerMenu[tvDense] :
-                                rulerMenu[tvFull]);
-            mapBoxReinvoke(hvg, insideX, y+rulerHeight, insideWidth,baseHeight,
-			   NULL, NULL, 0, 0, "", newRulerVis);
-            }
-        if (rulerCds)
-            {
-            /* display codons */
-            int frame;
-            int firstFrame = 0;
-            int mod;            // for determining frame ordering on display
-            struct simpleFeature *sfList;
-            double scale = scaleForWindow(insideWidth, winStart, winEnd);
-
-            /* WARNING: tricky code to assure that an amino acid
-             * stays in the same frame line on the browser during panning.
-             * There may be a simpler way... */
-            if (complementRulerBases)
-                mod = (chromSize - winEnd) % 3;
-            else
-                mod = winStart % 3;
-            if (mod == 0)
-                firstFrame = 0;
-            else if (mod == 1)
-                firstFrame = 2;
-            else if (mod == 2)
-                firstFrame = 1;
-
-            y = yAfterBases;
-            if (complementRulerBases)
-                reverseComplement(extraSeq->dna, extraSeq->size);
-            for (frame = 0; frame < 3; frame++, y += codonHeight)
-                {
-                /* reference frame to start of chromosome */
-                int refFrame = (firstFrame + frame) % 3;
-
-                /* create list of codons in the specified coding frame */
-                sfList = baseColorCodonsFromDna(refFrame, winStart, winEnd,
-                                             extraSeq, complementRulerBases);
-                /* draw the codons in the list, with alternating colors */
-                baseColorDrawRulerCodons(hvg, sfList, scale, insideX, y,
-                                    codonHeight, font, winStart, MAXPIXELS,
-                                    zoomedToCodonLevel);
-                }
-            }
-        }
-    hvGfxUnclip(hvg);
+    y = doDrawRuler(hvg,&newWinWidth,&rulerClickHeight,rulerHeight,yAfterRuler,yAfterBases,font,fontHeight,rulerCds);
     }
 
 /* Draw center labels. */
 if (withCenterLabels)
     {
     hvGfxSetClip(hvg, insideX, gfxBorder, insideWidth, pixHeight - 2*gfxBorder);
     y = yAfterRuler;
+#ifdef FLAT_TRACK_LIST
+    for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next)
+        {
+        track = flatTrack->track;
+#else//ifndef FLAT_TRACK_LIST
     for (track = trackList; track != NULL; track = track->next)
         {
-        struct track *subtrack;
+#endif//ndef FLAT_TRACK_LIST
         if (track->limitedVis == tvHide)
             continue;
+
         if(theImgBox)
             {
             //if (isWithCenterLabels(track))  // NOTE: Since track may not have centerlabel but subtrack may (How?), then must always make this slice!
             // center label slice of tracks
@@ -2200,12 +2313,13 @@
             // This will need to change to allow drag and drop.  Until then the subtrack center labels will drag scroll while the composte will not.
             // But as soon as subtracks are individual image tracks: problems with buttons, left labels, center labels, drag and drop, etc.
             sliceHeight      = fontHeight;
             sliceOffsetY     = y;
-            curImgTrack = imgBoxTrackFindOrAdd(theImgBox,track->tdb,NULL,track->limitedVis,isWithCenterLabels(track),IMG_ANYORDER);
-            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isCenter,theOneImg,NULL,sliceWidth[isData],sliceHeight,sliceOffsetX[isData],sliceOffsetY);
+            curImgTrack = imgBoxTrackFind(theImgBox,track->tdb,NULL);
+            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stCenter,theOneImg,NULL,sliceWidth[stData],sliceHeight,sliceOffsetX[stData],sliceOffsetY);
             curMap      = sliceMapFindOrStart(curSlice,track->tdb->tableName,NULL); // No common linkRoot
             }
+#ifndef FLAT_TRACK_LIST
         if (trackIsCompositeWithSubtracks(track))  //TODO: Change when tracks->subtracks are always set for composite
             {
             if (isWithCenterLabels(track))
                 y = doCenterLabels(track, track, hvg, font, y) - track->height; /* subtrack heights tallied below: */
@@ -2215,11 +2329,12 @@
                 // FIXME: This special case allows the subtrack center label map items to be put into the data slice
                 // When subtracks are carved up into individual imgTracks, then this will not be necessary
                 sliceHeight      = trackPlusLabelHeight(track, fontHeight) - fontHeight;
                 sliceOffsetY     = y;
-                curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isData,theOneImg,NULL,sliceWidth[isData],sliceHeight,sliceOffsetX[isData],sliceOffsetY);
+                curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stData,theOneImg,NULL,sliceWidth[stData],sliceHeight,sliceOffsetX[stData],sliceOffsetY);
                 curMap      = sliceMapFindOrStart(curSlice,track->tdb->tableName,NULL); // No common linkRoot
                 }
+            struct track *subtrack;
             for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next)
                 {
                 if (isSubtrackVisible(subtrack))
                     {
@@ -2230,8 +2345,9 @@
                     }
                 }
             }
         else
+#endif//ndef FLAT_TRACK_LIST
             y = doCenterLabels(track, track, hvg, font, y);
         }
     hvGfxUnclip(hvg);
     }
@@ -2241,30 +2357,38 @@
     long lastTime = 0;
     y = yAfterRuler;
     if (measureTiming)
         lastTime = clock1000();
+#ifdef FLAT_TRACK_LIST
+    for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next)
+        {
+        track = flatTrack->track;
+#else//ifndef FLAT_TRACK_LIST
     for (track = trackList; track != NULL; track = track->next)
         {
+#endif//ndef FLAT_TRACK_LIST
         if (track->limitedVis == tvHide)
                 continue;
+
+        int centerLabelHeight = (isWithCenterLabels(track) ? fontHeight : 0);
+        int yStart = y + centerLabelHeight;
+        int yEnd   = y + trackPlusLabelHeight(track, fontHeight);
         if(theImgBox)
             {
             // data slice of tracks
             // FIXME: Notice I am treating all subtracks as indivisible from their composite
             // This will need to change to allow drag and drop.  Until then the subtrack center labels will drag scroll while the composte will not.
             // But as soon as subtracks are individual image tracks: problems with buttons, left labels, center labels, drag and drop, etc.
-            sliceHeight      = trackPlusLabelHeight(track, fontHeight) - (isWithCenterLabels(track) ? fontHeight : 0);
-            sliceOffsetY     = y + (isWithCenterLabels(track) ? fontHeight : 0);
-            char var[128];     // FIXME: The cart var should update the tracks and the sort should be on the tracks.  This would allow printing the image
-            safef(var,sizeof(var),"%s_%s",track->tdb->tableName,IMG_ORDER_VAR);
-            int order = cartUsualInt(cart, var,IMG_ANYORDER);
-            curImgTrack = imgBoxTrackUpdateOrAdd(theImgBox,track->tdb,NULL,track->limitedVis,isWithCenterLabels(track),order);
+            sliceOffsetY     = yStart;
+            sliceHeight      = yEnd - yStart - 1;
+            curImgTrack = imgBoxTrackFind(theImgBox,track->tdb,NULL);
             if(sliceHeight > 0)
                 {
-                curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isData,theOneImg,NULL,sliceWidth[isData],sliceHeight,sliceOffsetX[isData],sliceOffsetY);
+                curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stData,theOneImg,NULL,sliceWidth[stData],sliceHeight,sliceOffsetX[stData],sliceOffsetY);
                 curMap      = sliceMapFindOrStart(curSlice,track->tdb->tableName,NULL); // No common linkRoot
                 }
             }
+#ifndef FLAT_TRACK_LIST
         if (trackIsCompositeWithSubtracks(track))  //TODO: Change when tracks->subtracks are always set for composite
             {
             struct track *subtrack;
             if (isWithCenterLabels(track))
@@ -2275,19 +2399,35 @@
                     y = doDrawItems(subtrack, hvg, font, y, &lastTime);
                 }
             }
         else
+#endif//ndef FLAT_TRACK_LIST
             y = doDrawItems(track, hvg, font, y, &lastTime);
+
+#if defined(IMAGEv2_DRAG_REORDER) && defined(FLAT_TRACK_LIST)
+        if (theImgBox && track->limitedVis == tvDense && tdbIsCompositeChild(track->tdb))
+            mapBoxToggleVis(hvg, 0, yStart,tl.picWidth, sliceHeight,track); // Strange mabBoxToggleLogic handles reverse complement itself so x=0, width=tl.picWidth
+#endif// defined(IMAGEv2_DRAG_REORDER) && defined(FLAT_TRACK_LIST)
+
+        if(yEnd!=y)
+            warn("Slice height does not add up.  Expecting %d != %d actual",yEnd - yStart - 1,y-yStart);
         }
+        y++;
 }
 /* if a track can draw its left labels, now is the time since it
  *	knows what exactly happened during drawItems
  */
 if (withLeftLabels)
     {
     y = yAfterRuler;
+#ifdef FLAT_TRACK_LIST
+    for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next)
+        {
+        track = flatTrack->track;
+#else//ifndef FLAT_TRACK_LIST
     for (track = trackList; track != NULL; track = track->next)
         {
+#endif//ndef FLAT_TRACK_LIST
         if (track->limitedVis == tvHide)
                 continue;
         if(theImgBox)
             {
@@ -2296,12 +2436,13 @@
             // This will need to change to allow drag and drop.  Until then the subtrack center labels will drag scroll while the composte will not.
             // But as soon as subtracks are individual image tracks: problems with buttons, left labels, center labels, drag and drop, etc.
             sliceHeight      = trackPlusLabelHeight(track, fontHeight);
             sliceOffsetY     = y;
-            curImgTrack = imgBoxTrackFindOrAdd(theImgBox,track->tdb,NULL,track->limitedVis,isWithCenterLabels(track),IMG_ANYORDER);
-            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isSide,theOneImg,NULL,sliceWidth[isSide],sliceHeight,sliceOffsetX[isSide],sliceOffsetY);
+            curImgTrack = imgBoxTrackFind(theImgBox,track->tdb,NULL);
+            curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stSide,theOneImg,NULL,sliceWidth[stSide],sliceHeight,sliceOffsetX[stSide],sliceOffsetY);
             curMap      = sliceMapFindOrStart(curSlice,track->tdb->tableName,NULL); // No common linkRoot
             }
+#ifndef FLAT_TRACK_LIST
         if (trackIsCompositeWithSubtracks(track))  //TODO: Change when tracks->subtracks are always set for composite
             {
             struct track *subtrack;
             if (isWithCenterLabels(track))
@@ -2316,31 +2457,41 @@
                         y += trackPlusLabelHeight(subtrack, fontHeight);
                     }
                 }
             }
-            else if (track->drawLeftLabels != NULL)
+        else
+#endif//ndef FLAT_TRACK_LIST
+            {
+            if (track->drawLeftLabels != NULL)
                 y = doOwnLeftLabels(track, hvg, font, y);
             else
                 y += trackPlusLabelHeight(track, fontHeight);
         }
     }
+    }
 
 
 /* Make map background. */
 y = yAfterRuler;
+#ifdef FLAT_TRACK_LIST
+for (flatTrack = flatTracks; flatTrack != NULL; flatTrack = flatTrack->next)
+    {
+    track = flatTrack->track;
+#else//ifndef FLAT_TRACK_LIST
 for (track = trackList; track != NULL; track = track->next)
     {
+#endif//ndef FLAT_TRACK_LIST
     if (track->limitedVis != tvHide)
         {
         if(theImgBox)
             {
             // Set imgTrack in case any map items will be set
             sliceHeight      = trackPlusLabelHeight(track, fontHeight);
             sliceOffsetY     = y;
-            curImgTrack = imgBoxTrackFindOrAdd(theImgBox,track->tdb,NULL,track->limitedVis,isWithCenterLabels(track),IMG_ANYORDER);
+            curImgTrack = imgBoxTrackFind(theImgBox,track->tdb,NULL);
             // It is possible that some side label heights need adjusting (but I doubt it)...
             //if (withLeftLabels)
-            //    curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,isSide,theOneImg,NULL,sliceWidth[isSide],sliceHeight,sliceOffsetX[isSide],sliceOffsetY);
+            //    curSlice    = imgTrackSliceUpdateOrAdd(curImgTrack,stSide,theOneImg,NULL,sliceWidth[stSide],sliceHeight,sliceOffsetX[stSide],sliceOffsetY);
             }
         y = doTrackMap(track, hvg, y, fontHeight, trackPastTabX, trackPastTabWidth);
         }
     }
@@ -2380,8 +2531,11 @@
     hPrintf("<IMG SRC = \"%s\" BORDER=1 WIDTH=%d HEIGHT=%d USEMAP=#%s %s id='trackMap'",
         gifTn.forHtml, pixWidth, pixHeight, mapName, titleAttr);
     hPrintf("><BR>\n");
     }
+#ifdef FLAT_TRACK_LIST
+flatTracksFree(&flatTracks);
+#endif//def FLAT_TRACK_LIST
 }
 
 static void printEnsemblAnchor(char *database, char* archive,
 	char *chrName, int start, int end)
@@ -3444,9 +3598,9 @@
     {
     hPrintf("<TD ALIGN=CENTER><A HREF=\"http://ws120.wormbase.org/db/seq/gbrowse/wormbase?name=%s:%d-%d\" TARGET=_blank class=\"topbar\">%s</A></TD>",
         skipChr(chromName), winStart+1, winEnd, "WormBase");
     }
-hPrintf("<TD ALIGN=CENTER><A HREF=\"../cgi-bin/hgTracks?%s=%u&hgt.psOutput=on\" class=\"topbar\">%s</A></TD>\n",cartSessionVarName(),
+hPrintf("<TD ALIGN=CENTER><A HREF=\"../cgi-bin/hgTracks?%s=%u&hgt.psOutput=on\" id='pdfLink' class=\"topbar\">%s</A></TD>\n",cartSessionVarName(),
        cartSessionId(cart), "PDF/PS");
 if (wikiLinkEnabled())
     {
     printf("<TD ALIGN=CENTER><A HREF=\"../cgi-bin/hgSession?%s=%u"
@@ -4010,8 +4164,18 @@
 if (measureTiming)
     uglyTime("getTrackList");
 #endif /* SOON */
 
+#ifdef IMAGEv2_DRAG_REORDER
+// honor defaultImgOrder
+if(cgiVarExists("hgt.defaultImgOrder"))
+    {
+    char wildCard[32];
+    safef(wildCard,sizeof(wildCard),"*_%s",IMG_ORDER_VAR);
+    cartRemoveLike(cart, wildCard);
+    }
+#endif//def IMAGEv2_DRAG_REORDER
+
 /* Honor hideAll and visAll variables */
 if (hideAll || defaultTracks)
     {
     int vis = (hideAll ? tvHide : -1);
@@ -4258,27 +4422,43 @@
     /* note a trick of WIDTH=27 going on here.  The 6,15,6 widths following
      * go along with this trick */
     hPrintf("<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=1 WIDTH=%d COLS=%d><TR>\n",
     	tl.picWidth, 27);
+#ifndef IMAGEv2_DRAG_SCROLL
     hPrintf("<TD COLSPAN=6 ALIGN=CENTER NOWRAP>");
     hPrintf("move start<BR>");
     hButton("hgt.dinkLL", " < ");
     hTextVar("dinkL", cartUsualString(cart, "dinkL", "2.0"), 3);
     hButton("hgt.dinkLR", " > ");
-    hPrintf("</TD><TD COLSPAN=15 style=\"white-space:normal\">"); // allow this text to wrap
+    hPrintf("</TD>");
+#endif//ndef IMAGEv2_DRAG_SCROLL
+    hPrintf("<TD COLSPAN=15 style=\"white-space:normal\">"); // allow this text to wrap
     hWrites("Click on a feature for details. ");
     hWrites(dragZooming ? "Click or drag in the base position track to zoom in. " : "Click on base position to zoom in around cursor. ");
-    hWrites("Click gray/blue bars on left for track options and descriptions.");
+#ifdef IMAGEv2_DRAG_REORDER
+    hWrites("Click side bars for track options. ");
+    hWrites("Drag side bars or labels up or down to reorder tracks. ");
+#else//ifndef IMAGEv2_DRAG_REORDER
+    hWrites("Click gray/blue bars on left for track options and descriptions. ");
+#endif//ndef IMAGEv2_DRAG_REORDER
+#ifdef IMAGEv2_DRAG_SCROLL
+    hWrites("Drag tracks left or right to new position. ");
+#else//ifndef IMAGEv2_DRAG_SCROLL
     hPrintf("</TD><TD COLSPAN=6 ALIGN=CENTER NOWRAP>");
     hPrintf("move end<BR>");
     hButton("hgt.dinkRL", " < ");
     hTextVar("dinkR", cartUsualString(cart, "dinkR", "2.0"), 3);
     hButton("hgt.dinkRR", " > ");
+#endif//ndef IMAGEv2_DRAG_SCROLL
     hPrintf("</TD></TR></TABLE>\n");
     // smallBreak();
 
     /* Display bottom control panel. */
     hButton("hgt.reset", "default tracks");
+#ifdef IMAGEv2_DRAG_REORDER
+	hPrintf("&nbsp;");
+    hButton("hgt.defaultImgOrder", "default order");
+#endif//def IMAGEv2_DRAG_REORDER
     // if (showTrackControls)  - always show "hide all", Hiram 2008-06-26
 	{
 	hPrintf("&nbsp;");
 	hButton("hgt.hideAll", "hide all");