3c2afd674ec5ab0ddbc9695caecb1965c93c021a
kate
  Thu Jan 15 13:34:45 2015 -0800
Support for computing track priorities by subtrack color in hgTrackDb
diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 38b1497..34d4e8c 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -3066,30 +3066,44 @@
     {
     int ix;
     for (ix=0;ix<membership->count;ix++)
         {
         if (sameString(name,membership->subgroups[ix]))
             {
             if (value != NULL)
                 *value = cloneString(membership->membership[ix]);
             return TRUE;
             }
         }
     }
 return FALSE;
 }
 
+static char *subtrackColorToCompare(struct trackDb *subtrack)
+/* Convert RGB color to string with scaled hue, suitable for alpha sort */
+{
+struct rgbColor rgbColor;
+rgbColor.r = subtrack->colorR;
+rgbColor.g = subtrack->colorG;
+rgbColor.b = subtrack->colorB;
+struct hslColor hslColor = mgRgbToHsl(rgbColor);
+int hue = hslColor.h * 10;
+char buf[5];
+safef(buf, 5, "%04d", hue);
+return cloneString(buf);
+}
+
 boolean subgroupFindTitle(struct trackDb *parentTdb, char *name,char **value)
 // looks for a a subgroup matching the name and returns the title if found
 {
 if (value != (void*)NULL)
     *value = NULL;
 members_t*members=subgroupMembersGet(parentTdb, name);
 //const members_t *members = membersFindByTag(parentTdb,name);
 //                           Can't use because of dimension dependence
 if (members==NULL)
     return FALSE;
 *value = cloneString(members->groupTitle);
 //subgroupMembersFree(&members);
 return TRUE;
 }
 
@@ -3098,31 +3112,30 @@
 {
 if (value && *value)
     freez(value);
 }
 
 boolean subgroupRequired(char *value)
 /* Returns whether subgroup much be specified for each track.
  * Generally true.  Exceptions are specially defined subgroups */
 {
 return differentString(SUBTRACK_COLOR_SUBGROUP, value);
 }
 
 #define SORT_ON_TRACK_NAME "trackName"
 #define SORT_ON_RESTRICTED "dateUnrestricted"
 
-
 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;
 
 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;
@@ -3217,54 +3230,65 @@
 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);
     freeMem((*sortOrder)->setting);
     freez(sortOrder);
     }
 }
 
 
+
+
 sortableTdbItem *sortableTdbItemCreate(struct trackDb *tdbChild,sortOrder_t *sortOrder)
 // creates a sortable tdb item struct, given a child tdb and its parent's sort table
 // Errors in interpreting a passed in sortOrder will return NULL
 {
 sortableTdbItem *item = NULL;
 if (tdbChild == NULL || tdbChild->shortLabel == NULL)
     return NULL;
 AllocVar(item);
 item->tdb = tdbChild;
 if (sortOrder != NULL)   // Add some sort buttons
     {
     int sIx=0;
     for (sIx=sortOrder->count - 1;sIx>=0;sIx--) // walk backwards to ensure sort order in columns
         {
         sortColumn *column = NULL;
         AllocVar(column);
         column->fwd = sortOrder->forward[sIx];
-        if (!subgroupFind(item->tdb,sortOrder->column[sIx],&(column->value)))
+        char *col = sortOrder->column[sIx];
+        if (!subgroupFind(item->tdb, col, &(column->value)))
             {
-            char *setting = trackDbSetting(item->tdb,sortOrder->column[sIx]);
+            if (sameString(col, SUBTRACK_COLOR_SUBGROUP))
+                {
+                // convert RGB color to hue so alpha sort can compare
+                column->value = subtrackColorToCompare(tdbChild);
+                }
+            else
+                {
+                char *setting = trackDbSetting(item->tdb,col);
                 if (setting != NULL)
                     column->value = cloneString(setting);
                 // No subgroup, assume there is a matching setting (eg longLabel)
                 }
+            }
         if (column->value != NULL)
             slAddHead(&(item->columns), column);
         else
             {
             freez(&column);
             if (item->columns != NULL)
                 slFreeList(&(item->columns));
             freeMem(item);
             return NULL; // sortOrder setting doesn't match items to be sorted.
             }
         }
     }
 return item;
 }
 
@@ -4343,57 +4367,55 @@
             {
             #define SUBTRACK_CFG_WRENCH "<span class='clickable%s' onclick='return " \
                                         "subCfg.cfgToggle(this,\"%s\");' title='Configure this " \
                                         "subtrack'><img src='../images/wrench.png'></span>\n"
             printf(SUBTRACK_CFG_WRENCH,(visibleCB ? "":" disabled"),subtrack->track);
             }
         }
     printf("</TD>");
 
     // If sortable, then there must be a column per sortable dimension
     if (sortOrder != NULL)
         {
         int sIx=0;
         for (sIx=0; sIx <sortOrder->count; sIx++)
             {
-            ix = stringArrayIx(sortOrder->column[sIx], membership->subgroups, membership->count);
+            char *col = sortOrder->column[sIx];
+            ix = stringArrayIx(col, membership->subgroups, membership->count);
                                 // TODO: Sort needs to expand from subGroups to labels as well
             if (ix >= 0)
                 {
                 char *titleRoot=NULL;
-                if (cvTermIsEmpty(sortOrder->column[sIx],membership->titles[ix]))
+                if (cvTermIsEmpty(col, membership->titles[ix]))
                     titleRoot = cloneString(" &nbsp;");
                 else
                     titleRoot = labelRoot(membership->titles[ix],NULL);
                 // Each sortable column requires hidden goop (in the "abbr" field currently)
                 // which is the actual sort on value
                 printf("<TD id='%s_%s' abbr='%s' align='left'>&nbsp;",
-                       subtrack->track,sortOrder->column[sIx],membership->membership[ix]);
+                       subtrack->track, col, membership->membership[ix]);
                 printf("%s",titleRoot);
                 puts("</TD>");
                 freeMem(titleRoot);
                 }
-            else if (sameString(sortOrder->column[sIx], SUBTRACK_COLOR_SUBGROUP))
+            else if (sameString(col, SUBTRACK_COLOR_SUBGROUP))
                 {
-                struct rgbColor rgbColor;
-                rgbColor.r = subtrack->colorR;
-                rgbColor.g = subtrack->colorG;
-                rgbColor.b = subtrack->colorB;
-                struct hslColor hslColor = mgRgbToHsl(rgbColor);
-                int hue = hslColor.h * 10;
-                printf("<TD id='%s_%s' abbr='%04d' bgcolor='#%02X%02X%02X'>&nbsp;&nbsp;&nbsp;&nbsp;</TD>",
-                    subtrack->track, sortOrder->column[sIx], hue, rgbColor.r, rgbColor.g, rgbColor.b);
+                char *hue = subtrackColorToCompare(subtrack);
+                printf("<TD id='%s_%s' abbr='%s' bgcolor='#%02X%02X%02X'>"
+                        "&nbsp;&nbsp;&nbsp;&nbsp;</TD>",
+                    subtrack->track, col, hue, 
+                        subtrack->colorR, subtrack->colorG, subtrack->colorB);
                 }
             }
         }
     else  // Non-sortable tables do not have sort by columns but will display a short label
         { // (which may be a configurable link)
         printf("<TD>&nbsp;");
         hierarchy_t *hierarchy = hierarchySettingGet(parentTdb);
         indentIfNeeded(hierarchy,membership);
         hierarchyFree(&hierarchy);
         printf("%s",subtrack->shortLabel);
         puts("</TD>");
         }
 
     // The long label column (note that it may have a metadata dropdown)
     printf("<TD title='select to copy'>&nbsp;%s", subtrack->longLabel);