d83026b7d8919bc8ad96679a98234aeb1308675e
max
  Mon Sep 7 10:55:13 2026 -0700
hgTracks: say in the track label why a track is showing item density

The density-mode labels existed but were only reachable through
labelTrackAsFilteredNumber(), which every caller guards with if (filtered),
so the note only appeared when a filter had also dropped features and the
automatic cases never said anything.

labelTrackAsDensityIfActive() now picks a message by cause: one for density
the user asked for on the configuration page, one for a window wider than
maxWindowCoverage, and one for the three paths that set limitWiggle because
there are too many features to draw. It is called once from makeActiveImage()
after every path into density mode has settled, over the tracks that will
actually be drawn, so hidden tracks keep their plain label.

refs #38279

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index dbda68b224d..f751f29258e 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -5382,30 +5382,38 @@
                  (pf->next != NULL ?
                       "\nAdditional tracks may have also been hidden at this zoom level." : ""));
         safeHeight = FALSE;
 	struct track *winTrack;
 	for(winTrack=pf;winTrack;winTrack=winTrack->nextWindow)
 	    {
 	    pf->limitedVis = tvHide;
 	    pf->limitedVisSet = TRUE;
 	    }
         }
     if (!isLimitedVisHiddenForAllWindows(pf))
         tmpPixHeight += trackPlusLabelHeight(pf, fontHeight);
     }
 pixHeight = tmpPixHeight;
 
+// All the ways into density mode have now been decided, so note it in the long labels
+// of the tracks that will actually be drawn.
+for(pfRef = preFlatTracks; pfRef; pfRef = pfRef->next)
+    {
+    if (!isLimitedVisHiddenForAllWindows(pfRef->track))
+        labelTrackAsDensityIfActive(pfRef->track);
+    }
+
 // Construct flatTracks
 for(; preFlatTracks; preFlatTracks = preFlatTracks->next)
     flatTracksAdd(&flatTracks,preFlatTracks->track,cart, orderedWiggles);
 
 flatTracksSort(&flatTracks); // Now we should have a perfectly good flat track list!
 
 if (orderedWiggles)
     {
     // save order to cart
     struct flatTracks *ft;
     char buffer[4096];
     int count = 1;
     for(ft = flatTracks; ft; ft = ft->next)
         {
         safef(buffer, sizeof buffer, "%s_imgOrd", ft->track->track);
@@ -12431,39 +12439,34 @@
     {
     char buf[5000];
     safef(buf, sizeof(buf), "A hub refresh (udcTimeout) setting is active. "
 	"This is useful when developing hubs, but it reduces "
 	"performance. To clear the setting, click "
 	"<A HREF='hgTracks?hgsid=%s|url|&udcTimeout=[]'>here</A>.",cartSessionId(cart));
     notify(buf, "udcTimeout");
     }
 #ifdef DEBUG
 if (cdsQueryCache != NULL)
     cacheTwoBitRangesPrintStats(cdsQueryCache, stderr);
 #endif /* DEBUG */
 }
 
 void labelTrackAsFilteredNumber(struct track *tg, unsigned numOut)
-/* add text to track long label to indicate filter is active. Also add doWiggle/windowsize label. */
+/* add text to track long label to indicate filter is active */
 {
 if (numOut > 0)
     tg->longLabel = labelAsFilteredNumber(tg->longLabel, numOut);
-
-if (cartOrTdbBoolean(cart, tg->tdb, "doWiggle", FALSE))
-    labelTrackAsDensity(tg);
-else if (winTooBigDoWiggle(cart, tg))
-    labelTrackAsDensityWindowSize(tg);
 }
 
 void labelTrackAsFiltered(struct track *tg)
 /* add text to track long label to indicate filter is active */
 {
 tg->longLabel = labelAsFiltered(tg->longLabel);
 
 // also label parent composite track filtered
 struct trackDb *parentTdb = tdbGetComposite(tg->tdb);
 if (parentTdb)
     parentTdb->longLabel = labelAsFiltered(parentTdb->longLabel);
 }
 
 static char *labelAddNote(char *label, char *note)
 /* add parenthesized text to label */
@@ -12477,27 +12480,48 @@
 }
 
 void labelTrackAsHideEmpty(struct track *tg)
 /* Add text to track long label to indicate empty subtracks are hidden,
  * but avoid adding to subtrack labels */
 {
 #define EMPTY_SUBTRACKS_HIDDEN "empty subtracks hidden"
 struct trackDb *parentTdb = tdbGetComposite(tg->tdb);
 if (parentTdb)
     parentTdb->longLabel = labelAddNote(parentTdb->longLabel, EMPTY_SUBTRACKS_HIDDEN);
 else
     tg->longLabel = labelAddNote(tg->longLabel, EMPTY_SUBTRACKS_HIDDEN);
 }
 
 void labelTrackAsDensity(struct track *tg)
-/* Add text to track long label to indicate density mode */
+/* Add text to track long label to indicate the user asked for density mode */
 {
-tg->longLabel = labelAddNote(tg->longLabel, "item density shown");
+tg->longLabel = labelAddNote(tg->longLabel,
+    "density mode active, configure the track to switch it off");
 }
 
 void labelTrackAsDensityWindowSize(struct track *tg)
 /* Add text to track long label to indicate density mode because window size exceeds some threshold */
 {
-tg->longLabel = labelAddNote(tg->longLabel, "item density shown - zoom in for individual items or use squish or dense mode");
+tg->longLabel = labelAddNote(tg->longLabel, "too many features, density shown - zoom in for individual items or use squish or dense mode");
+}
+
+void labelTrackAsDensityTooManyItems(struct track *tg)
+/* Add text to track long label to indicate we switched to density mode because there were
+ * too many items to draw one by one */
+{
+tg->longLabel = labelAddNote(tg->longLabel,
+    "too many features, density shown, zoom in to see details");
+}
+
+void labelTrackAsDensityIfActive(struct track *tg)
+/* If a track is showing item density instead of individual items, say so in the long label,
+ * distinguishing the density the user asked for from the density we had to impose. */
+{
+if (cartOrTdbBoolean(cart, tg->tdb, "doWiggle", FALSE))
+    labelTrackAsDensity(tg);
+else if (winTooBigDoWiggle(cart, tg))
+    labelTrackAsDensityWindowSize(tg);
+else if (tg->limitWiggle)
+    labelTrackAsDensityTooManyItems(tg);
 }