f04f1b9af06c823602c5e0ecd3b8c2059d7704d3
jcasper
  Thu Aug 27 14:42:31 2026 -0700
Faceted composites now have a max display mode setting instead of a full override
of child track visibilities, with accompanying support for the onlyVisibility setting.  We also
now include a filter block (applied to appropriate child tracks) when those settings are in place.
refs #37662

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index 422915607e3..4829c595b97 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -398,43 +398,47 @@
                 // if we're called on the path that has excludeHash set
                 // we also want to set the supertrack children's visbilities
                 if (!tdbIsSuperTrackChild(tdb) || (excludeHash != NULL))
                     {
                     if (changeVis == tdb->visibility)
                         /* remove if setting to default vis */
                         cartRemove(cart, track->track);
                     else
                         cartSetString(cart, track->track, hStringFromTv(changeVis));
                     track->visibility = changeVis;
                     }
 
                 // Whether super child or not, if its a composite, then handle the children
                 if (tdbIsComposite(tdb))
                     {
+                    // A faceted composite's children own their display modes and the
+                    // parent's vis is only a ceiling, so setting the parent is enough -
+                    // don't stomp the per-child preferences on the way through.
+                    boolean keepChildVis = tdbIsFacetedComposite(tdb);
                     struct track *subtrack;
                     for (subtrack=track->subtracks;subtrack!=NULL;subtrack=subtrack->next)
                         {
-                        if (changeVis == tvHide)               // Since subtrack level vis is an
-                            {
-                            cartRemove(cart, subtrack->track); // override, simply remove to hide
-                            if (excludeHash != NULL) // if we're loading an RTS, but probably we should always do this
-                                {
-                                char selName[4096];
+                        if (changeVis == tvHide && excludeHash != NULL)
+                            {   // loading an RTS should start from a clean selection,
+                            char selName[4096];             // but probably we should
                             safef(selName, sizeof(selName), "%s_sel", subtrack->track);
-                                cartRemove(cart, selName);
-                                }
+                            cartRemove(cart, selName);      // always do this
                             }
+                        if (keepChildVis)
+                            continue;
+                        if (changeVis == tvHide)               // Since subtrack level vis is an
+                            cartRemove(cart, subtrack->track); // override, simply remove to hide
                         else
                             cartSetString(cart, subtrack->track, hStringFromTv(changeVis));
                         subtrack->visibility = changeVis;
                         }
                     }
                 }
             }
         }
     }
 slSort(&groupList, gCmpPriority);
 }
 
 void changeTrackVis(struct group *groupList, char *groupTarget, int changeVis)
 /* Change track visibilities. If groupTarget is
  * NULL then set visibility for tracks in all groups.  Otherwise,
@@ -7767,51 +7771,65 @@
     if (tdbIsComposite(track->tdb) || tdbIsMultiTrack(track->tdb))
         {
         char *usedThis = buffer;
 
         // first check to see if we've been asked to hide all the subtracks
         boolean hideKids = FALSE;
         safef(buffer, sizeof buffer, "%s_hideKids", track->track);
 
         s = cartOptionalString(cart, buffer);
         if (s == NULL && startsWith("hub_", track->track))
             s = cartOptionalString(cart, usedThis = trackHubSkipHubName(buffer));
         if (s != NULL)
             hideKids = TRUE;
         cartRemove(cart, usedThis);   // we don't want these _hideKids variables in the cart
 
+        boolean facetedParent = tdbIsFacetedComposite(track->tdb);
+
         // now see if we have any specified visibilities
         struct track *subtrack;
         for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next)
             {
             boolean undecoratedVis = FALSE;
             char *s = hideTracks ? cgiOptionalString( subtrack->track) : cartOptionalString(cart, subtrack->track);
             if (s == NULL && startsWith("hub_", subtrack->track))
                 {
                 undecoratedVis = TRUE;
                 s = hideTracks ? cgiOptionalString(trackHubSkipHubName(subtrack->track)) : cartOptionalString(cart, trackHubSkipHubName(subtrack->track));
                 }
 
             safef(buffer, sizeof buffer, "%s_sel", subtrack->track);
             if (s != NULL)
                 {
                 subtrack->visibility = hTvFromString(s);
-                cartSetString(cart, subtrack->track, s);
-                if (sameString("hide", s))
+                if (facetedParent && sameString("hide", s))
+                    {
+                    // A faceted composite's child holds a standing display mode rather
+                    // than inheriting one, and a standing mode of "hide" would survive
+                    // being re-selected in the facet table and look like a bug.  So take
+                    // the child out of the selection instead of storing that.
+                    cartRemove(cart, subtrack->track);
                     cartSetString(cart, buffer, "0");
+                    }
                 else
+                    {
+                    cartSetString(cart, subtrack->track, s);
+                    // Conversely, a faceted child's stored display mode is not a request
+                    // to turn it on - the facet table owns the _sel checkbox.
+                    if (!facetedParent)
                         cartSetString(cart, buffer, "1");
+                    }
                 if (undecoratedVis)
                     cartRemove(cart, trackHubSkipHubName(subtrack->track)); // remove the undecorated version
                 }
             else if (hideKids && isSubtrackVisible(subtrack))
                 {
                 cartSetString(cart, buffer, "0");
                 subtrack->subTrackVis = tvHide;
                 subtrack->subTrackVisSet = TRUE;
                 }
             }
         }
     }
 return trackList;
 }