b8180d9f6d41dc708a2f249ba892cbca311e7a06
jcasper
  Mon Feb 27 11:38:55 2023 -0800
Adding transparency support for colors refs #30569

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index 3409f93..6d317b6 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -199,31 +199,31 @@
 long virtSeqBaseCount = 0;       // number of bases in virtual chromosome
 long virtWinBaseCount = 0;       // number of bases in virtual chrom (end - start)
 long virtWinStart = 0;  // start of virtual window in bases
 long virtWinEnd = 0;    //   end of virtual window in bases
 long defaultVirtWinStart = 0;  // default start of virtual window in bases
 long defaultVirtWinEnd = 0;    // default end   of virtual window in bases
 //char *virtPosition = NULL;          /* Name of virtual position. TODO REMOVE? */
 char *virtChromName = NULL;         /* Name of virtual chrom */
 boolean virtMode = FALSE;           /* Are we in virtual chrom mode? */
 boolean virtChromChanged = FALSE;    /* Has the virtChrom changed? */
 boolean emAltHighlight = FALSE;     /* Highlight alternativing regions in virt view? */
 int emPadding = 6;                  /* # bases padding for exon-mostly regions */
 int gmPadding = 6;                  /* # bases padding for gene-mostly regions */
 char *emGeneTable = NULL;           /* Gene table to use for exon mostly */
 struct track *emGeneTrack = NULL;   /* Track for gene table for exon mostly */
-struct rgbColor vertWindowSeparatorColor = { 255, 220, 220};  // light red
+struct rgbColor vertWindowSeparatorColor = { 255, 220, 220, 255};  // light red
 char *multiRegionsBedUrl = "";     /* URL to Multi-window bed regions file */
 
 // demo2
 int demo2NumWindows = 70;
 int demo2WindowSize = 200;
 int demo2StepSize = 200;
 
 // singleTrans (single transcript)
 char *singleTransId = "uc001uub.1";
 
 // singleAltHaplos (single haplotype)
 char *singleAltHaploId = "chr6_cox_hap2";
 
 char *virtModeType = "default";  /* virtual chrom mode type */
 char *lastVirtModeType = "default";
@@ -257,124 +257,124 @@
 boolean withNextExonArrows = FALSE;	/* Display next exon navigation buttons near center labels? */
 boolean withExonNumbers = FALSE;	/* Display exon and intron numbers in mouseOver instead of item name */
 boolean revCmplDisp = FALSE;          /* reverse-complement display */
 
 boolean measureTiming = FALSE;	/* DON'T EDIT THIS -- use CGI param "&measureTiming=." . */
 struct track *trackList = NULL;    /* List of all tracks. */
 struct cart *cart;	/* The cart where we keep persistent variables. */
 
 int seqBaseCount;	/* Number of bases in sequence. */
 int winBaseCount;	/* Number of bases in window. */
 
 int maxShade = 9;	/* Highest shade in a color gradient. */
 Color shadesOfGray[10+1];	/* 10 shades of gray from white to black
                                  * Red is put at end to alert overflow. */
 Color shadesOfBrown[10+1];	/* 10 shades of brown from tan to tar. */
-struct rgbColor brownColor = {100, 50, 0};
-struct rgbColor tanColor = {255, 240, 200};
-struct rgbColor guidelineColor = {220, 220, 255};
-struct rgbColor multiRegionAltColor = {235, 235, 255};
-struct rgbColor undefinedYellowColor = {240,240,180};
+struct rgbColor brownColor = {100, 50, 0, 255};
+struct rgbColor tanColor = {255, 240, 200, 255};
+struct rgbColor guidelineColor = {220, 220, 255, 255};
+struct rgbColor multiRegionAltColor = {235, 235, 255, 255};
+struct rgbColor undefinedYellowColor = {240,240,180, 255};
 
 Color shadesOfSea[10+1];       /* Ten sea shades. */
-struct rgbColor darkSeaColor = {0, 60, 120};
-struct rgbColor lightSeaColor = {200, 220, 255};
+struct rgbColor darkSeaColor = {0, 60, 120, 255};
+struct rgbColor lightSeaColor = {200, 220, 255, 255};
 
 struct hash *hgFindMatches; /* The matches found by hgFind that should be highlighted. */
 
 struct trackLayout tl;
 
 void initTl()
 /* Initialize layout around small font and a picture about 600 pixels
  * wide. */
 {
 trackLayoutInit(&tl, cart);
 
 }
 
 static boolean isTooLightForTextOnWhite(struct hvGfx *hvg, Color color)
 /* Return TRUE if text in this color would probably be invisible on a white background. */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 int colorTotal = rgbColor.r + 2*rgbColor.g + rgbColor.b;
 return colorTotal >= 512;
 }
 
 Color darkerColor(struct hvGfx *hvg, Color color)
 /* Get darker shade of a color - half way between this color and black */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 rgbColor.r = ((int)rgbColor.r)/2;
 rgbColor.g = ((int)rgbColor.g)/2;
 rgbColor.b = ((int)rgbColor.b)/2;
-return hvGfxFindColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b);
+return hvGfxFindAlphaColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b, rgbColor.a);
 }
 
 Color somewhatDarkerColor(struct hvGfx *hvg, Color color)
 /* Get a somewhat darker shade of a color - 1/3 of the way towards black. */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 rgbColor.r = (2*(int)rgbColor.r)/3;
 rgbColor.g = (2*(int)rgbColor.g)/3;
 rgbColor.b = (2*(int)rgbColor.b)/3;
-return hvGfxFindColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b);
+return hvGfxFindAlphaColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b, rgbColor.a);
 }
 
 Color slightlyDarkerColor(struct hvGfx *hvg, Color color)
 /* Get a slightly darker shade of a color - 1/4 of the way towards black. */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 rgbColor.r = (9*(int)rgbColor.r)/10;
 rgbColor.g = (9*(int)rgbColor.g)/10;
 rgbColor.b = (9*(int)rgbColor.b)/10;
-return hvGfxFindColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b);
+return hvGfxFindAlphaColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b, rgbColor.a);
 }
 
 Color lighterColor(struct hvGfx *hvg, Color color)
 /* Get lighter shade of a color - half way between this color and white */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 rgbColor.r = (rgbColor.r+255)/2;
 rgbColor.g = (rgbColor.g+255)/2;
 rgbColor.b = (rgbColor.b+255)/2;
-return hvGfxFindColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b);
+return hvGfxFindAlphaColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b, rgbColor.a);
 }
 
 Color somewhatLighterColor(struct hvGfx *hvg, Color color)
 /* Get a somewhat lighter shade of a color - 1/3 of the way towards white. */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 rgbColor.r = (2*rgbColor.r+255)/3;
 rgbColor.g = (2*rgbColor.g+255)/3;
 rgbColor.b = (2*rgbColor.b+255)/3;
-return hvGfxFindColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b);
+return hvGfxFindAlphaColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b, rgbColor.a);
 }
 
 boolean trackIsCompositeWithSubtracks(struct track *track)
 /* Temporary function until all composite tracks point to their own children */
 {
 return (tdbIsComposite(track->tdb) && track->subtracks != NULL);
 }
 
 Color slightlyLighterColor(struct hvGfx *hvg, Color color)
 /* Get slightly lighter shade of a color - closer to gray actually  */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 rgbColor.r = (rgbColor.r+128)/2;
 rgbColor.g = (rgbColor.g+128)/2;
 rgbColor.b = (rgbColor.b+128)/2;
-return hvGfxFindColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b);
+return hvGfxFindAlphaColorIx(hvg, rgbColor.r, rgbColor.g, rgbColor.b, rgbColor.a);
 }
 
 boolean winTooBigDoWiggle(struct cart *cart, struct track *tg)
 /* return true if we wiggle because the window size exceeds a certain threshold? */
 {
 boolean doWiggle = FALSE;
 char *setting = trackDbSetting(tg->tdb, "maxWindowCoverage" );
 if (setting)
     {
     unsigned size = sqlUnsigned(setting);
     if ((size > 0) && ((winEnd - winStart) > size))
         doWiggle = TRUE;
     }
 return doWiggle;
 }
@@ -3333,36 +3333,36 @@
 {
 makeGrayShades(hvg);
 makeBrownShades(hvg);
 makeSeaShades(hvg);
 orangeColor = hvGfxFindColorIx(hvg, 230, 130, 0);
 brickColor = hvGfxFindColorIx(hvg, 230, 50, 110);
 blueColor = hvGfxFindColorIx(hvg, 0,114,198);
 darkBlueColor = hvGfxFindColorIx(hvg, 0,70,140);
 greenColor = hvGfxFindColorIx(hvg, 28,206,40);
 darkGreenColor = hvGfxFindColorIx(hvg, 28,140,40);
 }
 
 void makeRedGreenShades(struct hvGfx *hvg)
 /* Allocate the shades of Red, Green, Blue and Yellow for expression tracks */
 {
-static struct rgbColor black = {0, 0, 0};
-static struct rgbColor red = {255, 0, 0};
-static struct rgbColor green = {0, 255, 0};
-static struct rgbColor blue = {0, 0, 255};
-static struct rgbColor yellow = {255, 255, 0};
-static struct rgbColor white  = {255, 255, 255};
+static struct rgbColor black = {0, 0, 0, 255};
+static struct rgbColor red = {255, 0, 0, 255};
+static struct rgbColor green = {0, 255, 0, 255};
+static struct rgbColor blue = {0, 0, 255, 255};
+static struct rgbColor yellow = {255, 255, 0, 255};
+static struct rgbColor white  = {255, 255, 255, 255};
 hvGfxMakeColorGradient(hvg, &black, &blue, EXPR_DATA_SHADES, shadesOfBlue);
 hvGfxMakeColorGradient(hvg, &black, &red, EXPR_DATA_SHADES, shadesOfRed);
 hvGfxMakeColorGradient(hvg, &black, &green, EXPR_DATA_SHADES, shadesOfGreen);
 hvGfxMakeColorGradient(hvg, &black, &yellow, EXPR_DATA_SHADES, shadesOfYellow);
 hvGfxMakeColorGradient(hvg, &white, &blue,   EXPR_DATA_SHADES, shadesOfBlueOnWhite);
 hvGfxMakeColorGradient(hvg, &white, &red,    EXPR_DATA_SHADES, shadesOfRedOnWhite);
 hvGfxMakeColorGradient(hvg, &white, &green,  EXPR_DATA_SHADES, shadesOfGreenOnWhite);
 hvGfxMakeColorGradient(hvg, &white, &yellow, EXPR_DATA_SHADES, shadesOfYellowOnWhite);
 hvGfxMakeColorGradient(hvg, &yellow, &blue,   EXPR_DATA_SHADES, shadesOfBlueOnYellow);
 hvGfxMakeColorGradient(hvg, &yellow, &red,    EXPR_DATA_SHADES, shadesOfRedOnYellow);
 exprBedColorsMade = TRUE;
 }
 
 Color getOrangeColor()
 {
@@ -3571,83 +3571,77 @@
    if (x1 < 0) x1 = 0;
    if (x2 > hvg->width) x2 = hvg->width;
    if (x2-x1 > 0)
        hvGfxLine(hvg, x1, y, x2, y, color);
    }
 }
 
 static void lfColors(struct track *tg, struct linkedFeatures *lf,
         struct hvGfx *hvg, Color *retColor, Color *retBarbColor)
 /* Figure out color to draw linked feature in. */
 {
 if (!((lf->isBigGenePred) ||(lf->filterColor == 0)|| (lf->filterColor == -1)))
     {
     if (lf->useItemRgb)
 	{
-	struct rgbColor itemRgb;
-	itemRgb.r = (lf->filterColor & 0xff0000) >> 16;
-	itemRgb.g = (lf->filterColor & 0xff00) >> 8;
-	itemRgb.b = lf->filterColor & 0xff;
-	*retColor = *retBarbColor =
-		hvGfxFindColorIx(hvg, itemRgb.r, itemRgb.g, itemRgb.b);
+        *retColor = *retBarbColor = bedColorToGfxColor(lf->filterColor);
 	}
     else
 	*retColor = *retBarbColor = lf->filterColor;
     }
 else if (tg->itemColor)
     {
     *retColor = tg->itemColor(tg, lf, hvg);
     *retBarbColor = tg->ixAltColor;
     }
 else if (tg->colorShades)
     {
     boolean isXeno = (tg->subType == lfSubXeno)
                                 || (tg->subType == lfSubChain)
                                 || startsWith("mrnaBla", tg->table);
     *retColor =  tg->colorShades[lf->grayIx+isXeno];
     *retBarbColor =  tg->colorShades[lf->grayIx];
     }
 else
     {
     *retColor = tg->ixColor;
     *retBarbColor = tg->ixAltColor;
     }
 }
 
 Color bigGenePredColor(struct track *tg, void *item,  struct hvGfx *hvg)
 /* Determine the color of the name for the bigGenePred linked feature. */
 {
 struct linkedFeatures *lf = item;
-struct rgbColor itemRgb;
-itemRgb.r = (lf->filterColor & 0xff0000) >> 16;
-itemRgb.g = (lf->filterColor & 0xff00) >> 8;
-itemRgb.b = lf->filterColor & 0xff;
-return hvGfxFindColorIx(hvg, itemRgb.r, itemRgb.g, itemRgb.b);
+return bedColorToGfxColor(lf->filterColor);
 }
 
 Color blackItemNameColor(struct track *tg, void *item, struct hvGfx *hvg)
 /* Force item name (label) color to black */
 {
 return hvGfxFindColorIx(hvg, 0, 0, 0);
 }
 
 Color linkedFeaturesNameColor(struct track *tg, void *item, struct hvGfx *hvg)
 /* Determine the color of the name for the linked feature. */
 {
 Color col, barbCol;
 lfColors(tg, item, hvg, &col, &barbCol);
-return col;
+// Draw the item name fully opaque even even the item itself is drawn with alpha
+struct rgbColor rgb = hvGfxColorIxToRgb(hvg, col);
+rgb.a = 255;
+return hvGfxFindRgb(hvg, &rgb);
 }
 
 struct simpleFeature *simpleFeatureCloneList(struct simpleFeature *list)
 /* Just copies the simpleFeature list. This is good for making a copy */
 /* when the codon list is made. */
 {
 struct simpleFeature *ret = NULL;
 struct simpleFeature *cur;
 for (cur = list; cur != NULL; cur = cur->next)
     {
     struct simpleFeature *newSf = NULL;
     AllocVar(newSf);
     newSf->start = cur->start;
     newSf->end = cur->end;
     newSf->qStart = cur->qStart;
@@ -7727,31 +7721,31 @@
     {
     nonCodingTypeIncludeCart[i] = cartUsualBoolean(cart, nonCodingTypeIncludeStrings[i], nonCodingTypeIncludeDefault[i]);
     }
 /* Convert genePred in window to linked feature */
 tg->items = lfFromGenePredInRange(tg, tg->table, chromName, winStart, winEnd);
 /* filter items on selected criteria if filter is available */
 filterItems(tg, filterNonCoding, "include");
 }
 
 Color ensGeneNonCodingColor(struct track *tg, void *item, struct hvGfx *hvg)
 /* Return color to draw Ensembl non-coding gene/pseudogene in. */
 {
 char condStr[255];
 char *bioType;
 Color color = {MG_GRAY};  /* Set default to gray */
-struct rgbColor hAcaColor = {0, 128, 0}; /* darker green, per request by Weber */
+struct rgbColor hAcaColor = {0, 128, 0, 255}; /* darker green, per request by Weber */
 Color hColor;
 struct sqlConnection *conn;
 char *name;
 
 conn = hAllocConn(database);
 hColor = hvGfxFindColorIx(hvg, hAcaColor.r, hAcaColor.g, hAcaColor.b);
 name = tg->itemName(tg, item);
 sqlSafef(condStr, sizeof condStr, "name='%s'", name);
 bioType = sqlGetField(database, "ensGeneNonCoding", "biotype", condStr);
 
 if (sameWord(bioType, "miRNA"))    color = MG_RED;
 if (sameWord(bioType, "misc_RNA")) color = MG_BLACK;
 if (sameWord(bioType, "snRNA"))    color = MG_BLUE;
 if (sameWord(bioType, "snoRNA"))   color = MG_MAGENTA;
 if (sameWord(bioType, "rRNA"))     color = MG_CYAN;
@@ -9568,31 +9562,31 @@
 /* Make track for rna genes . */
 {
 tg->loadItems = loadRnaGene;
 tg->freeItems = freeRnaGene;
 tg->itemName = rnaGeneName;
 tg->itemColor = rnaGeneColor;
 }
 
 
 Color ncRnaColor(struct track *tg, void *item, struct hvGfx *hvg)
 /* Return color of ncRna track item. */
 {
 char condStr[255];
 char *rnaType;
 Color color = {MG_GRAY};  /* Set default to gray */
-struct rgbColor hAcaColor = {0, 128, 0}; /* darker green, per request by Weber */
+struct rgbColor hAcaColor = {0, 128, 0, 255}; /* darker green, per request by Weber */
 Color hColor;
 struct sqlConnection *conn;
 char *name;
 
 conn = hAllocConn(database);
 hColor = hvGfxFindColorIx(hvg, hAcaColor.r, hAcaColor.g, hAcaColor.b);
 
 name = tg->itemName(tg, item);
 sqlSafef(condStr, sizeof condStr, "name='%s'", name);
 rnaType = sqlGetField(database, "ncRna", "type", condStr);
 
 if (sameWord(rnaType, "miRNA"))    color = MG_RED;
 if (sameWord(rnaType, "misc_RNA")) color = MG_BLACK;
 if (sameWord(rnaType, "snRNA"))    color = MG_BLUE;
 if (sameWord(rnaType, "snoRNA"))   color = MG_MAGENTA;
@@ -9606,31 +9600,31 @@
 }
 
 void ncRnaMethods(struct track *tg)
 /* Make track for ncRna. */
 {
 tg->itemColor = ncRnaColor;
 }
 
 Color wgRnaColor(struct track *tg, void *item, struct hvGfx *hvg)
 /* Return color of wgRna track item. */
 {
 char condStr[255];
 char *rnaType;
 Color color = {MG_BLACK};  /* Set default to black.  But, if we got black, something is wrong. */
 Color hColor;
-struct rgbColor hAcaColor = {0, 128, 0}; /* darker green */
+struct rgbColor hAcaColor = {0, 128, 0, 255}; /* darker green */
 struct sqlConnection *conn;
 char *name;
 
 conn = hAllocConn(database);
 hColor = hvGfxFindColorIx(hvg, hAcaColor.r, hAcaColor.g, hAcaColor.b);
 
 name = tg->itemName(tg, item);
 sqlSafef(condStr, sizeof condStr, "name='%s'", name);
 rnaType = sqlGetField(database, "wgRna", "type", condStr);
 if (sameWord(rnaType, "miRna"))   color = MG_RED;
 if (sameWord(rnaType, "HAcaBox")) color = hColor;
 if (sameWord(rnaType, "CDBox"))   color = MG_BLUE;
 if (sameWord(rnaType, "scaRna"))  color = MG_MAGENTA;
 
 hFreeConn(&conn);
@@ -12088,30 +12082,31 @@
                     found = FALSE;
                 break;
                 }
             }
         }
     sqlFreeResult(&sr);
     if (found)
         {
         /* need to convert color string to rgb */
         // check how these are found for trackDb
         colorClone = cloneString(colorString);
         chopString(colorClone, sep, rgbVals, size);
         gClassColor.r = (sqlUnsigned(rgbVals[0]));
         gClassColor.g = (sqlUnsigned(rgbVals[1]));
         gClassColor.b = (sqlUnsigned(rgbVals[2]));
+        gClassColor.a = 0xff;
 
         /* find index for color */
         color = hvGfxFindRgb(hvg, &gClassColor);
         }
     }
 hFreeConn(&conn);
 /* return index for color to draw item */
 return color;
 }
 
 void drawColorMethods(struct track *tg)
 /* Fill in color track items based on chrom  */
 {
 char *optionStr ;
 optionStr = cartUsualStringClosestToHome(cart, tg->tdb,FALSE,"color", "off");
@@ -13006,34 +13001,36 @@
     Lighter Green:
         for Class 1 OMIM records
     Light Green:
         for Class 2 OMIM records
     Dark Green:
         for Class 3 OMIM records
     Purple:
         for Class 4 OMIM records
     Light Gray:
         for Others
 */
 
 lighter.r = (6*normal->r + 4*255) / 10;
 lighter.g = (6*normal->g + 4*255) / 10;
 lighter.b = (6*normal->b + 4*255) / 10;
+lighter.a = normal->a;
 
 lightest.r = (1*normal->r + 2*255) / 3;
 lightest.g = (1*normal->g + 2*255) / 3;
 lightest.b = (1*normal->b + 2*255) / 3;
+lightest.a = normal->a;
 
 
 struct sqlConnection *conn = hAllocConn(database);
 
 class1Clr = hvGfxFindColorIx(hvg, lightest.r, lightest.g, lightest.b);
 class2Clr = hvGfxFindColorIx(hvg, lighter.r, lighter.g, lighter.b);
 class3Clr = hvGfxFindColorIx(hvg, normal->r, normal->g, normal->b);
 class4Clr = hvGfxFindColorIx(hvg, 105,50,155);
 classOtherClr = hvGfxFindColorIx(hvg, 190, 190, 190);   // light gray
 
 sqlSafef(query, sizeof(query),
       "select omimId, %s from omimPhenotype where omimId=%s order by %s desc",
       omimPhenotypeClassColName, el->name, omimPhenotypeClassColName);
 
 sr = sqlMustGetResult(conn, query);
@@ -13343,34 +13340,36 @@
     Lighter Green:
         for Class 1 OMIM records
     Light Green:
         for Class 2 OMIM records
     Dark Green:
         for Class 3 OMIM records
     Purple:
         for Class 4 OMIM records
     Light Gray:
         for Others
 */
 
 lighter.r = (6*normal->r + 4*255) / 10;
 lighter.g = (6*normal->g + 4*255) / 10;
 lighter.b = (6*normal->b + 4*255) / 10;
+lighter.a = normal->a;
 
 lightest.r = (1*normal->r + 2*255) / 3;
 lightest.g = (1*normal->g + 2*255) / 3;
 lightest.b = (1*normal->b + 2*255) / 3;
+lightest.a = normal->a;
 
 class1Clr = hvGfxFindColorIx(hvg, lightest.r, lightest.g, lightest.b);
 class2Clr = hvGfxFindColorIx(hvg, lighter.r, lighter.g, lighter.b);
 class3Clr = hvGfxFindColorIx(hvg, normal->r, normal->g, normal->b);
 class4Clr = hvGfxFindColorIx(hvg, 105,50,155);
 classOtherClr = hvGfxFindColorIx(hvg, 190, 190, 190);   // light gray
 
 struct sqlConnection *conn = hAllocConn(database);
 
 sqlSafef(query, sizeof(query),
       "select omimId, %s from omimPhenotype where omimId=%s", omimPhenotypeClassColName, el->name);
 sr = sqlMustGetResult(conn, query);
 row = sqlNextRow(sr);
 
 hFreeConn(&conn);
@@ -14560,34 +14559,34 @@
         if (sameString(type, "mathWig"))
             {
             buildMathWig(subTdb);
             }
         }
     }
 }
 #endif
 
 void makeCompositeTrack(struct track *track, struct trackDb *tdb)
 /* Construct track subtrack list from trackDb entry.
  * Sets up color gradient in subtracks if requested */
 {
 buildMathWig(tdb);
 unsigned char finalR = track->color.r, finalG = track->color.g,
-                            finalB = track->color.b;
+                            finalB = track->color.b, finalA = track->color.a;
 unsigned char altR = track->altColor.r, altG = track->altColor.g,
-                            altB = track->altColor.b;
-unsigned char deltaR = 0, deltaG = 0, deltaB = 0;
+                            altB = track->altColor.b, altA = track->altColor.a;
+unsigned char deltaR = 0, deltaG = 0, deltaB = 0, deltaA = 0;
 
 struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendantLeaves(tdb->subtracks);
 
 struct trackDb *subTdb;
 int subCount = slCount(tdbRefList);
 int altColors = subCount - 1;
 struct track *subtrack = NULL;
 TrackHandler handler;
 boolean smart = FALSE;
 
 /* ignore if no subtracks */
 if (!subCount)
     return;
 
 char *compositeTrack = trackDbLocalSetting(tdb, "compositeTrack");
@@ -14602,30 +14601,33 @@
     /* handles it's own load and height */
     handler(track);
 else
     {
     track->loadItems = compositeLoad;
     track->totalHeight = compositeTotalHeight;
     }
 
 if (altColors && (finalR || finalG || finalB))
     {
     /* not black -- make a color gradient for the subtracks,
                 from black, to the specified color */
     deltaR = (finalR - altR) / altColors;
     deltaG = (finalG - altG) / altColors;
     deltaB = (finalB - altB) / altColors;
+    // speculative - no harm, but there's no current way for a track to set its alpha,
+    // so both final and altA should be 255
+    deltaA = (finalA - altA) / altColors;
     }
 
 /* fill in subtracks of composite track */
 for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
     {
     subTdb = tdbRef->val;
 
     subtrack = trackFromTrackDb(subTdb);
     handler = lookupTrackHandlerClosestToHome(subTdb);
     if (handler != NULL)
         handler(subtrack);
 
     /* Add subtrack settings (table, colors, labels, vis & pri).  This is only
      * needed in the "not noInherit" case that hopefully will go away soon. */
     subtrack->track = subTdb->track;
@@ -14635,39 +14637,44 @@
     subtrack->priority = subTdb->priority;
     subtrack->parent = track;
 
     /* Add color gradient. */
     if (finalR || finalG || finalB)
 	{
 	subtrack->color.r = altR;
 	subtrack->altColor.r = (255+altR)/2;
 	altR += deltaR;
 	subtrack->color.g = altG;
 	subtrack->altColor.g = (255+altG)/2;
 	altG += deltaG;
 	subtrack->color.b = altB;
 	subtrack->altColor.b = (255+altB)/2;
 	altB += deltaB;
+	subtrack->color.a = altA;
+	subtrack->altColor.a = altA;
+	altA += deltaA;
 	}
     else
 	{
 	subtrack->color.r = subTdb->colorR;
 	subtrack->color.g = subTdb->colorG;
 	subtrack->color.b = subTdb->colorB;
+        subtrack->color.a = 255;
 	subtrack->altColor.r = subTdb->altColorR;
 	subtrack->altColor.g = subTdb->altColorG;
 	subtrack->altColor.b = subTdb->altColorB;
+        subtrack->altColor.a = 255;
 	}
     slAddHead(&track->subtracks, subtrack);
     }
 slSort(&track->subtracks, trackPriCmp);
 }
 
 struct track *trackFromTrackDb(struct trackDb *tdb)
 /* Create a track based on the tdb */
 {
 struct track *track = NULL;
 char *exonArrows;
 char *nextItem;
 
 if (!tdb)
     return NULL;
@@ -14707,33 +14714,35 @@
     if (version)
 	{
 	char longLabel[1024];
 	safef(longLabel, sizeof(longLabel), "%s - Annotation Release %s", tdb->longLabel, version);
 	track->longLabel = cloneString(longLabel);
 	tdb->longLabel = cloneString(longLabel);
 	}
     else
 	track->longLabel = cloneString(tdb->longLabel);
     }
 else
     track->longLabel = cloneString(tdb->longLabel);
 track->color.r = tdb->colorR;
 track->color.g = tdb->colorG;
 track->color.b = tdb->colorB;
+track->color.a = 255; // No way to specify alpha in tdb currently - assume it's fully opaque
 track->altColor.r = tdb->altColorR;
 track->altColor.g = tdb->altColorG;
 track->altColor.b = tdb->altColorB;
+track->altColor.a = 255;
 track->lineHeight = tl.fontHeight+1;
 track->heightPer = track->lineHeight - 1;
 track->private = tdb->private;
 track->defaultPriority = tdb->priority;
 char lookUpName[256];
 safef(lookUpName, sizeof(lookUpName), "%s.priority", tdb->track);
 tdb->priority = cartUsualDouble(cart, lookUpName, tdb->priority);
 track->priority = tdb->priority;
 track->groupName = cloneString(tdb->grp);
 /* save default priority and group so we can reset it later */
 track->defaultGroupName = cloneString(tdb->grp);
 track->canPack = tdb->canPack;
 if (tdb->useScore)
     {
     /* Todo: expand spectrum opportunities. */