c9aa9c0f8bd30426080ca5a2d5546d1f05befe9b
jcasper
  Wed Jun 26 15:51:39 2024 -0700
Fix for drawing wrong exon numbers in codon mouseovers, refs #33742

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index c69493f..3b7af0a 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -2962,31 +2962,31 @@
 	{
 	int sClp = (s < winStart) ? winStart : s;
 	int eClp = (e > winEnd)   ? winEnd   : e;
 
 	int sx = round((sClp - winStart)*scale) + insideX;
 	int ex = round((eClp - winStart)*scale) + insideX;
 
         // skip regions entirely outside available picture
         // (accounts for space taken by exon arrows buttons)
 	if (sx <= picEnd && ex >= picStart)
 	    {
 	    // clip it to avail pic
 	    sx = (sx < picStart) ? picStart : sx;
     	    ex = (ex > picEnd)   ? picEnd   : ex;
 
-	    int w = ex - sx;
+	    int w = ex - sx; // w could be negative, but we'll skip drawing if it is
 
 	    int exonIntronNumber;
 	    char *exonIntronText;
 	    int numExonIntrons = numExons;
 	    if (isExon)
 		{
 		exonIntronText = exonText;
 		}
 	    else
 		{
 		exonIntronText = intronText;
 		--numExonIntrons;  // introns are one fewer than exons
 		}
 
             char strandChar;
@@ -3017,38 +3017,40 @@
                 {
                 startPhase = gp->exonFrames[exonIx-1];
                 //printf("start phase is set<br>");
                 if (!revStrand) 
                     endPhase = gp->exonFrames[exonIx];
                 else 
                     if (exonIx>1)
                         endPhase = gp->exonFrames[exonIx-2];
                 // construct a string that tells the user about the codon frame situation of this exon
                 makeExonFrameText(exonIntronNumber, numExons, startPhase, endPhase, phaseText);
                 }
 
 	    if (w > 0) // draw exon or intron if width is greater than 0
 		{
                 // draw mapBoxes for the codons if we are zoomed in far enough
+                if (isExon && lf->codons && zoomedToCdsColorLevel)
+                    {
                     struct simpleFeature *codon;
                     struct dyString *codonDy = dyStringNew(0);
                     int codonS, codonE;
-                if (isExon && lf->codons && zoomedToCdsColorLevel)
-                    {
                     for (codon = lf->codons; codon != NULL; codon = codon->next)
                         {
                         codonS = codon->start; codonE = codon->end;
+                        if (codonS > e || codonE < s)
+                            continue; // only write out mouseovers for codons in the current exon
                         if (codonS <= winEnd && codonE >= winStart)
                             {
                             int codonSClp = (codonS < winStart) ? winStart : codonS;
                             int codonEClp = (codonE > winEnd)   ? winEnd   : codonE;
 
                             int codonsx = round((codonSClp - winStart)*scale) + insideX;
                             int codonex = round((codonEClp - winStart)*scale) + insideX;
 
                             // skip regions entirely outside available picture
                             // (accounts for space taken by exon arrows buttons)
                             if (codonsx <= picEnd && codonex >= picStart)
                                 {
                                 // clip it to avail pic
                                 codonsx = (codonsx < picStart) ? picStart : codonsx;
                                 codonex = (codonex > picEnd)   ? picEnd   : codonex;
@@ -3065,68 +3067,51 @@
                                         dyStringPrintf(codonDy, "%s, ", existingText);
                                     int codonHgvsIx = (codon->codonIndex - 1) * 3;
                                     if (codonHgvsIx >= 0)
                                         dyStringPrintf(codonDy, "c.%d-%d, ", codonHgvsIx + 1, codonHgvsIx + 3);
                                     dyStringPrintf(codonDy, "strand %c, %s %d of %d%s",
                                                 strandChar, exonIntronText, exonIntronNumber, numExonIntrons, phaseText);
                                     tg->mapItem(tg, hvg, item, codonDy->string, tg->mapItemName(tg, item),
                                             sItem, eItem, codonsx, y, w, heightPer);
                                     // and restore the mouseOver
                                     lf->mouseOver = oldMouseOver;
                                     }
                                 }
                             }
                         }
                     }
-                }
-                else
-                    {
-                    // temporarily remove the mouseOver from the lf, since linkedFeatureMapItem will always 
-                    // prefer a lf->mouseOver over the itemName
-                    if (!isEmpty(existingText))
-                        safef(mouseOverText, sizeof(mouseOverText), "%s, strand %c, %s %d of %d%s",
-                                existingText, strandChar, exonIntronText, exonIntronNumber, numExonIntrons, phaseText);
-                    else
-                        safef(mouseOverText, sizeof(mouseOverText), "strand %c, %s %d of %d%s",
-                                strandChar, exonIntronText, exonIntronNumber, numExonIntrons, phaseText);
-                    char *oldMouseOver = lf->mouseOver;
-                    lf->mouseOver = NULL;
-                    tg->mapItem(tg, hvg, item, mouseOverText, tg->mapItemName(tg, item),
-                        sItem, eItem, sx, y, w, heightPer);
-                    // and restore the mouseOver
-                    lf->mouseOver = oldMouseOver;
-                    }
-
-	    if (w > 0) // draw exon or intron if width is greater than 0
+                else // either an intron, or else an exon zoomed out too far for codons (or no codons)
                     {
                     char *sep = "";
                     if (!isEmpty(existingText))
                         sep = ", ";
 
                     safef(mouseOverText, sizeof(mouseOverText), "%s%sstrand %c, %s %d of %d%s",
                             existingText, sep, strandChar, exonIntronText, exonIntronNumber, numExonIntrons, phaseText);
 
                     // temporarily remove the mouseOver from the lf, since linkedFeatureMapItem will always 
                     // prefer a lf->mouseOver over the itemName
                     char *oldMouseOver = lf->mouseOver;
                     lf->mouseOver = NULL;
                     tg->mapItem(tg, hvg, item, mouseOverText, tg->mapItemName(tg, item),
                         sItem, eItem, sx, y, w, heightPer);
                     // and restore the old mouseOver
                     lf->mouseOver = oldMouseOver;
 
                     picStart = ex;  // prevent pileups. is this right? add 1? does it work?
+                                    // JC: Why do we care about pileups?  First mapbox drawn wins.
+                    }
                 }
 	    }
 	}
 
     if (isExon)
 	{
     	eLast = e;
 	ref = ref->next;
 	if (!ref)
 	    break;
 	}
     else
 	{
 	exonIx++;
 	}