f03bf118cfa39ac47fe74b06c48297af26b50448
kate
  Fri Jan 9 16:07:30 2015 -0800
Sortable subtrack list now includes color patch with header.  Still needs sorting logic for the column
diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 0fd4066..a33907f 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -3090,54 +3090,64 @@
     return FALSE;
 *value = cloneString(members->groupTitle);
 //subgroupMembersFree(&members);
 return TRUE;
 }
 
 void subgroupFree(char **value)
 // frees subgroup memory
 {
 if (value && *value)
     freez(value);
 }
 
 #define SORT_ON_TRACK_NAME "trackName"
 #define SORT_ON_RESTRICTED "dateUnrestricted"
+#define SUBTRACK_COLOR_PATCH "subtrackColor"
+#define SUBTRACK_COLOR_HEADER "Color"
 
 sortOrder_t *sortOrderGet(struct cart *cart,struct trackDb *parentTdb)
 // Parses any list sort order instructions for parent of subtracks (from cart or trackDb)
 // Some trickiness here.  sortOrder->sortOrder is from cart (changed by user action),
 // as is sortOrder->order, But columns are in original tdb order (unchanging)!
 // However, if cart is null, all is from trackDb.ra
 {
 int ix;
 char *setting = trackDbSetting(parentTdb, "sortOrder");
 if (setting == NULL) // Must be in trackDb or not a sortable table
     return NULL;
+if (trackDbSetting(parentTdb, "showSubtrackColorOnUi"))
+    {
+    // insert color sort indicator as first column
+    struct dyString *ds = newDyString(0);
+    dyStringPrintf(ds, "%s=+ %s", SUBTRACK_COLOR_PATCH, setting);
+    setting = dyStringCannibalize(&ds);
+    }
 
 sortOrder_t *sortOrder = needMem(sizeof(sortOrder_t));
 sortOrder->htmlId = needMem(strlen(parentTdb->track)+15);
 safef(sortOrder->htmlId, (strlen(parentTdb->track)+15), "%s.sortOrder", parentTdb->track);
 char *cartSetting = NULL;
 if (cart != NULL)
     cartSetting = cartCgiUsualString(cart, sortOrder->htmlId, setting);
 // If setting is bigger than cartSetting, then it may be due to a trackDb change
 if (cart != NULL && strlen(cartSetting) > strlen(setting))
     sortOrder->sortOrder = cloneString(cartSetting);  // cart order
 else
     sortOrder->sortOrder = cloneString(setting);      // old cart value is abandoned!
 
+/* parse setting into sortOrder */
 sortOrder->setting = cloneString(setting);
 sortOrder->count   = chopByWhite(sortOrder->setting,NULL,0);  // Get size
 if (cart && !stringIn(SORT_ON_TRACK_NAME,setting))
     sortOrder->count += 1;
 if (cart && !stringIn(SORT_ON_RESTRICTED,setting))
     sortOrder->count += 1;
 sortOrder->column  = needMem(sortOrder->count*sizeof(char*));
 int foundColumns = chopByWhite(sortOrder->setting, sortOrder->column,sortOrder->count);
 sortOrder->title   = needMem(sortOrder->count*sizeof(char*));
 sortOrder->forward = needMem(sortOrder->count*sizeof(boolean));
 sortOrder->order   = needMem(sortOrder->count*sizeof(int));
 if (cart && foundColumns < sortOrder->count)
     {
     int columnCount = foundColumns;
     int size = 0;
@@ -3183,32 +3193,38 @@
         char* pos2 = sortOrder->sortOrder;
         for (;*pos2 && pos2 < pos;pos2++)
             {
             if (*pos2 == '=') // Discovering sort order in cart
                 ord++;
             }
         sortOrder->forward[ix] = (pos[strlen(sortOrder->column[ix]) + 1] == '+');
         sortOrder->order[ix] = ord;
         }
     else  // give up on cartSetting
         {
         sortOrder->forward[ix] = TRUE;
         sortOrder->order[ix] = ix+1;
         }
     if (ix < foundColumns)
+        {
+        // Subtrack color column requires special handling
+        if (ix == 0 && sameString(SUBTRACK_COLOR_PATCH, sortOrder->column[ix]))
+            sortOrder->title[ix] = SUBTRACK_COLOR_HEADER;
+        else
             subgroupFindTitle(parentTdb,sortOrder->column[ix],&(sortOrder->title[ix]));
         }
+    }
 return sortOrder;  // NOTE cloneString:words[0]==*sortOrder->column[0]
 }                  // and will be freed when sortOrder is freed
 
 void sortOrderFree(sortOrder_t **sortOrder)
 // frees any previously obtained sortOrder settings
 {
 if (sortOrder && *sortOrder)
     {
     int ix;
     for (ix=0;ix<(*sortOrder)->count;ix++) { subgroupFree(&((*sortOrder)->title[ix])); }
     freeMem((*sortOrder)->sortOrder);
     freeMem((*sortOrder)->htmlId);
     freeMem((*sortOrder)->column);
     freeMem((*sortOrder)->forward);
     freeMem((*sortOrder)->order);
@@ -4009,32 +4025,30 @@
 /* Print header of subtrack table, including classes describing display appearance and behavior.
    Return number of columns */
 {
 char buffer[SMALLBUF];
 boolean useDragAndDrop = settings->useDragAndDrop;
 sortOrder_t *sortOrder = settings->sortOrder;
 if (sortOrder != NULL)
     puts("<THEAD class=sortable>");
 else
     puts("<THEAD>");
 int colspan = 3;
 if (sortOrder != NULL)
     colspan = sortOrder->count+2;
 else if (!tdbIsMultiTrack(parentTdb)) // An extra column for subVis/wrench so dragAndDrop works
     colspan++;
-if (settings->colorPatch)
-    colspan += 1;
 int columnCount = 0;
 if (sortOrder != NULL)
     printf("<TR id=\"subtracksHeader\" class='sortable%s'>\n",
                 useDragAndDrop ? " nodrop nodrag" : "");
 else
     {
     printf("<TR%s>", useDragAndDrop ? " id='noDrag' class='nodrop nodrag'" : "");
     // First table row contains the display "selected/visible" or "all" radio buttons
     // NOTE: list subtrack radio buttons are inside tracklist table header if
     //       there are no sort columns.  The reason is to ensure spacing of lines
     //       column headers when the only column header is "Restricted Until"
     printf("<TD colspan='%d'><B>List subtracks:&nbsp;", colspan);
     char javascript[JBUFSIZE];
     safef(javascript, sizeof(javascript),
           "class='allOrOnly' onclick='showOrHideSelectedSubtracks(true);'");