f0a0c72f15abf7903dcc3f3957dc6f1c0ce68952
tdreszer
  Fri Nov 19 11:26:06 2010 -0800
Support for drag virgins being on top
diff --git src/hg/hgTracks/imageV2.c src/hg/hgTracks/imageV2.c
index 1ad4d1e..c609c04 100644
--- src/hg/hgTracks/imageV2.c
+++ src/hg/hgTracks/imageV2.c
@@ -14,59 +14,154 @@
 
 static char const rcsid[] = "$Id: imageV2.c,v 1.32 2010/05/24 19:53:42 hiram Exp $";
 
 struct imgBox   *theImgBox   = NULL; // Make this global for now to avoid huge rewrite
 //struct image    *theOneImg   = NULL; // Make this global for now to avoid huge rewrite
 struct imgTrack *curImgTrack = NULL; // Make this global for now to avoid huge rewrite
 //struct imgSlice *curSlice    = NULL; // Make this global for now to avoid huge rewrite
 //struct mapSet   *curMap      = NULL; // Make this global for now to avoid huge rewrite
 //struct mapItem  *curMapItem  = NULL; // Make this global for now to avoid huge rewrite
 
 /////////////////////////
 // FLAT TRACKS
 // A simplistic way of flattening the track list before building the image
 // NOTE: Strategy is NOT to use imgBox->imgTracks, since this should be independednt of imageV2
 /////////////////////////
+#define IMGORD_CUSTOM_ONTOP
 void flatTracksAdd(struct flatTracks **flatTracks,struct track *track,struct cart *cart)
 // Adds one track into the flatTracks list
 {
 struct flatTracks *flatTrack;
 AllocVar(flatTrack);
 flatTrack->track = track;
 char var[256];  // The whole reason to do this is to reorder tracks/subtracks in the image!
 safef(var,sizeof(var),"%s_%s",track->tdb->track,IMG_ORDER_VAR);
 flatTrack->order = cartUsualInt(cart, var,IMG_ANYORDER);
+#ifdef IMGORD_CUSTOM_ONTOP
+if(flatTrack->order >= IMG_ORDERTOP)
+#else///ifndef IMGORD_CUSTOM_ONTOP
 if(flatTrack->order >= IMG_ORDEREND)
+#endif///ndef IMGORD_CUSTOM_ONTOP
     {
     cartRemove(cart,var);
     flatTrack->order = IMG_ANYORDER;
     }
+#ifdef IMGORD_CUSTOM_ONTOP
+static int topOrder  = IMG_ORDERTOP; // keep track of the order added to top of image
+#endif///def IMGORD_CUSTOM_ONTOP
 static int lastOrder = IMG_ORDEREND; // keep track of the order added and beyond end
 if( flatTrack->order == IMG_ANYORDER)
+    {
+#ifdef IMGORD_CUSTOM_ONTOP
+    if (track->customTrack)
+        flatTrack->order = ++topOrder; // Custom tracks go to top
+    else
+#endif///def IMGORD_CUSTOM_ONTOP
     flatTrack->order = ++lastOrder;
+    }
 
 slAddHead(flatTracks,flatTrack);
 }
 
 int flatTracksCmp(const void *va, const void *vb)
 // Compare to sort on flatTrack->order
 {
 const struct flatTracks *a = *((struct flatTracks **)va);
 const struct flatTracks *b = *((struct flatTracks **)vb);
 return (a->order - b->order);
 }
 
+#ifdef IMGORD_CUSTOM_ONTOP
+void flatTracksSort(struct flatTracks **flatTracks)
+// This routine sorts the imgTracks then forces tight ordering, so new tracks wil go to the end
+{
+// flatTracks list has 2 sets of "order": those already dragReordered (below IMG_ORDERTOP)
+// and those not yet reordered (above).  Within those not yet dragReordered are 2 sets:
+// Those that begin numbering at IMG_ORDERTOP and those that begin at IMG_ORDEREND.
+// This routine must determine if there are any already dragOrdered, and if so, position the
+// newcomers in place.  Newly appearing customTracks will appear at top, while newly appearing
+// standard tracks appear at the end of the image.
+int haveBeenOrderd = 0, imgOrdHighest=0; // Keep track of reordered count and position
+int notYetOrdered = 0, toBeTopHighest=0; // Keep track of those to be reordered, and top ordered
+
+// First determine what if anything needs to be rearranged.
+struct flatTracks *oneTrack = *flatTracks;
+for(;oneTrack!=NULL;oneTrack = oneTrack->next)
+    {
+    if (oneTrack->order <= IMG_ORDERTOP)
+        {
+        haveBeenOrderd++;
+        if (imgOrdHighest < oneTrack->order )
+            imgOrdHighest = oneTrack->order;
+        }
+    else
+        {
+        notYetOrdered++;
+        if (oneTrack->order <= IMG_ORDEREND) // && oneTrack->order >= IMG_ORDERTOP
+            {
+            if (toBeTopHighest < oneTrack->order )
+                toBeTopHighest = oneTrack->order;
+            }
+        }
+    }
+
+// If some have previously been dragOrdered AND some new ones need to be given an explicit order
+if (haveBeenOrderd > 0 && notYetOrdered > 0)
+    {
+    char var[256];
+    int gapOnTopNeeded = 0;
+    if (toBeTopHighest > 0)
+        {
+        gapOnTopNeeded = toBeTopHighest - IMG_ORDERTOP;
+        imgOrdHighest += gapOnTopNeeded; // Will be after this loop
+        // Warning: Will need to throw away ALL previous orderings (even those not currently in image)!
+        safef(var,sizeof(var),"*_%s",IMG_ORDER_VAR);
+        cartRemoveLike(cart, var);
+        }
+    int gapFromOrderedToEnd = (IMG_ORDEREND - imgOrdHighest);  // This difference should be removed from any with IMG_ORDEREND
+    for(oneTrack = *flatTracks;oneTrack!=NULL;oneTrack = oneTrack->next)
+        {
+        if (oneTrack->order <= IMG_FIXEDPOS)
+            ;  // Untouchables
+        else if (oneTrack->order <= IMG_ORDERTOP && gapOnTopNeeded > 0)
+            {  // Already order tracks will need to be pushed down.
+            oneTrack->order += gapOnTopNeeded;
+            safef(var,sizeof(var),"%s_%s",oneTrack->track->track,IMG_ORDER_VAR);
+            cartSetInt(cart, var, oneTrack->order);
+            }
+        else if (oneTrack->order >= IMG_ORDERTOP
+             &&  oneTrack->order <  IMG_ORDEREND && gapOnTopNeeded > 0)
+            {  // Unordered custom tracks will need to be added to top!
+            oneTrack->order -= IMG_ORDERTOP; // Force to top
+            safef(var,sizeof(var),"%s_%s",oneTrack->track->track,IMG_ORDER_VAR);
+            cartSetInt(cart, var, oneTrack->order);
+            }
+        else if (oneTrack->order >= IMG_ORDEREND && gapFromOrderedToEnd)
+            {  // Normal unordered tracks can fill in the trailing numbers
+            oneTrack->order -= gapFromOrderedToEnd;
+            safef(var,sizeof(var),"%s_%s",oneTrack->track->track,IMG_ORDER_VAR);
+            cartSetInt(cart, var, oneTrack->order);
+            }
+        }
+    }
+
+if (flatTracks && *flatTracks)
+    slSort(flatTracks, flatTracksCmp);
+}
+
+#else///ifndef IMGORD_CUSTOM_ONTOP
+
 void flatTracksSort(struct flatTracks **flatTracks)
 // This routine sorts the imgTracks then forces tight ordering, so new tracks wil go to the end
 {
 // flatTracks list has 2 sets of "order": those already dragReordered (below IMG_ORDEREND)
 // and those not yet reordered (above).  It has been decided that adding new tracks to an
 // existing order should always put the new tracks below existing and treat them as if they
 // were reordered there.  Thus all new tracks should get an imgOrd below IMG_ORDEREND.
 // The result is turning on a successive set of new tracks will have them appear below all others.
 int imgOrdSet = 0;
 boolean notYetOrdered = FALSE;
 struct flatTracks *oneTrack = *flatTracks;
 for(;oneTrack!=NULL;oneTrack = oneTrack->next)
     {
     if (oneTrack->order <= IMG_ORDEREND
     &&  imgOrdSet < oneTrack->order )
@@ -80,30 +175,32 @@
     for(oneTrack = *flatTracks;oneTrack!=NULL;oneTrack = oneTrack->next)
         {
         if (oneTrack->order >= imgOrdSet)
             {
             oneTrack->order -= imgOrdSet;
             char var[256];
             safef(var,sizeof(var),"%s_%s",oneTrack->track->track,IMG_ORDER_VAR);
             cartSetInt(cart, var, oneTrack->order);
             }
         }
     }
 
 if (flatTracks && *flatTracks)
     slSort(flatTracks, flatTracksCmp);
 }
+#endif///ndef IMGORD_CUSTOM_ONTOP
+
 
 void flatTracksFree(struct flatTracks **flatTracks)
 // Frees all memory used to support flatTracks (underlying tracks are untouched)
 {
 if(flatTracks && *flatTracks)
     {
     struct flatTracks *flatTrack;
     while((flatTrack = slPopHead(flatTracks)) != NULL)
         freeMem(flatTrack);
     }
 }
 
 // TODO: Move to trackDb.h and trackDbCustom.c
 enum kindOfParent {
     kopChildless     = 0,