6d437c28a5ff82a2af59ca516559053c4bf7c3f9
max
  Thu Jun 18 01:18:34 2026 -0700
hgTracks: amino-acid name in codon + ruler mouseovers; exon-length label; ruler "Complement bases" config toggle

Three genome browser display changes around AA display:
1) amino acids shown on genePred codons and on rule codons, and making
the "complement option" easier to find.

1) The genePred/bigGenePred codon mouseover (zoomed to the codon level) now
shows the codon's amino acid on its own "Amino acid:" line, as the three-letter
abbreviation plus full name (e.g. "Ala (alanine)").  Rather than reverse-decode
the amino acid out of the codon's packed grayIx, the one-letter code is now
stored on the codon when it is translated: struct simpleFeature gains a codonAa
field, codonToGrayIx() reports the letter through a new out-param, and the codon
mouseover reads simpleFeature.codonAa directly.  The drawn codon letter and the
mouseover then derive from the same translation and cannot drift apart, without
the mouseover having to understand the grayIx encoding (the drawing path,
colorAndCodonFromGrayIx(), still decodes its own grayIx inline, unchanged).  Adds
a one-letter->full-name aaToName() in lib/dnautil.c (using the previously unused
name field of aminoAcidTable).  Stop codons show "Ter (termination)".  Also
relabels the exon "Length" field as "Exon Length" in the codon and zoomed-out
exon mouseovers; introns keep "Length".

2) The base-position ruler's three-reading-frame translation
(hgt.baseShowCodons) now gives each codon box a mouse-over with the same
three-letter abbreviation and full name, reading the stored codonAa via
aaToName()/aaToAbbr() (baseColorDrawRulerCodons in cds.c).

3) Adds a "Complement the bases" checkbox to the base position (ruler) track
configuration page (hgTrackUi rulerUi).  It toggles the same per-assembly
COMPLEMENT_BASES_VAR cart variable that was previously reachable only by clicking
the "Click to complement" arrow next to the ruler.  Also fixes the indentation
of the adjacent drawComplementArrow() text assignments.

refs #37779

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c
index 52400e705bd..fcf396d2348 100644
--- src/hg/hgTrackUi/hgTrackUi.c
+++ src/hg/hgTrackUi/hgTrackUi.c
@@ -2136,50 +2136,65 @@
 
 void quickLiftUi(struct trackDb *tdb)
 /* UI for base position (ruler) */
 {
 tdb->html = hFileContentsOrWarning(hHelpFile(trackHubSkipHubName(tdb->track)));
 }
 
 void rulerUi(struct trackDb *tdb)
 /* UI for base position (ruler) */
 {
 boolean showScaleBar = cartUsualBoolean(cart, BASE_SCALE_BAR, TRUE);
 boolean showRuler = cartUsualBoolean(cart, BASE_SHOWRULER, TRUE);
 boolean complementsToo = cartUsualBoolean(cart, MOTIF_COMPLEMENT, FALSE);
 boolean showPos = cartUsualBoolean(cart, BASE_SHOWPOS, FALSE);
 boolean showAsm = cartUsualBoolean(cart, BASE_SHOWASM, FALSE);
+/* complement-bases var is assembly-specific (same one toggled by the "Click to
+ * complement" arrow next to the ruler, see hgTracks.c drawComplementArrow) */
+boolean complementBases = cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE);
+char complementVar[256];
+safef(complementVar, sizeof(complementVar), "%s_%s", COMPLEMENT_BASES_VAR, database);
 /* title var is assembly-specific */
 char titleVar[256];
 char *title = NULL;
 /* Configure zoom when click occurs */
 char *currentZoom = cartCgiUsualString(cart, RULER_BASE_ZOOM_VAR, ZOOM_3X);
 char *motifString = cartCgiUsualString(cart, BASE_MOTIFS, "");
 safef(titleVar,sizeof(titleVar),"%s_%s",BASE_TITLE,database);
 title = cartUsualString(cart, titleVar, "");
 puts("<P>");
 cgiMakeCheckBox(BASE_SHOWRULER, showRuler);
 puts("&nbsp;<B>Show ruler</B></P>");
 puts("<P>");
 cgiMakeCheckBox(BASE_SCALE_BAR, showScaleBar);
 puts("&nbsp;<B>Show scale bar</B>");
 
 puts("<P>");
 cgiMakeCheckBox(BASE_SHOWASM_SCALEBAR, cartUsualBoolean(cart, BASE_SHOWASM_SCALEBAR, TRUE));
 puts("&nbsp;<B>Show assembly next to scale bar</B>");
 puts("</P>");
 
+puts("<P>");
+cgiMakeCheckBox(complementVar, complementBases);
+puts("&nbsp;<B>Complement the bases</B>");
+printInfoIcon("Show the complementary DNA base at each position. "
+     "Same as the &quot;Click to complement&quot; arrow next to the ruler. "
+     "Does not reverse the sequence. "
+     "To reverse-complement the entire display, sequence and annotations, "
+     "click the \"Reverse\" button under the image instead.");
+puts("</P>");
+
 puts("<P>");
 cgiMakeCheckBox(BASE_SHOWCODONS, cartUsualBoolean(cart, BASE_SHOWCODONS, FALSE));
 puts("&nbsp;<B>Show amino acids for all three possible reading frames</B>");
 puts("</P>");
 
 puts("<P><B>Zoom factor:&nbsp;</B>");
 zoomRadioButtons(RULER_BASE_ZOOM_VAR, currentZoom);
 puts("<P><B>Motifs to highlight:&nbsp;</B>");
 cgiMakeTextVar(BASE_MOTIFS, motifString, 20);
 puts("&nbsp;(Comma separated list, e.g.: GT,AG for splice sites)");
 puts("<P>");
 cgiMakeCheckBox(MOTIF_COMPLEMENT, complementsToo);
 puts("&nbsp;<B>Show reverse complements of motifs also</B>");
 puts("<P>Options for slides and presentations:");
 puts("<P><B>Title:&nbsp;</B>");