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/lib/hui.c src/hg/lib/hui.c index fe59d53ff79..ad331852541 100644 --- src/hg/lib/hui.c +++ src/hg/lib/hui.c @@ -932,30 +932,49 @@ "hide", "dense", "full", NULL }; static char *pack[] = { "hide", "dense", "squish", "pack", "full", NULL }; +enum trackVisibility tvFromVisOnlySetting(char *visOnly) +/* Parse an onlyVisibility value. Deliberately mirrors hTvGetVizArr() below: matching is + * case-insensitive, and an unrecognized value falls back to dense. Do NOT use + * hTvFromString[NoAbort]() here - it is case sensitive and quietly answers tvHide for + * anything it doesn't know, which would make the track vanish while the vis dropdown + * built from the same setting still looked correct. */ +{ +if (sameWord(visOnly,"dense")) + return tvDense; +else if (sameWord(visOnly,"squish")) + return tvSquish; +else if (sameWord(visOnly,"pack")) + return tvPack; +else if (sameWord(visOnly,"full")) + return tvFull; +else + return tvDense; +} + char ** hTvGetVizArr(enum trackVisibility vis, boolean canPack, char* visOnly) /* return a NULL-terminated array of char* with possible track visibilities */ { if (visOnly != NULL) { if (sameWord(visOnly,"dense")) return denseOnly; else if (sameWord(visOnly,"squish")) return squishOnly; else if (sameWord(visOnly,"pack")) return packOnly; else if (sameWord(visOnly,"full")) return fullOnly; else /* default when not recognized */ return denseOnly; @@ -964,38 +983,43 @@ { if (canPack) return pack; else return noPack; } } void hTvDropDownClassVisOnlyAndExtraWithLabel(char *varName, enum trackVisibility vis, boolean canPack, char *class, char *visOnly, struct slPair *events, char *label) // Make track visibility drop down for varName with style class, optional aria-label, // and potentially limited to visOnly { char** vizArr = hTvGetVizArr(vis, canPack, visOnly); -char* checked = vizArr[vis]; int vizArrLen = arrNullLen(vizArr); +char* checked; // Same as hTvDropDownClassWithJavascript(): // Normal track with no special limits needs mapping to get back checked value static int packIx[] = {tvHide,tvDense,tvSquish,tvPack,tvFull}; -if (visOnly==NULL && canPack) +if (visOnly != NULL) + // Just hide and the one allowed vis, so a tv enum would index off the end of the array + checked = (vis == tvHide ? vizArr[0] : vizArr[1]); +else if (canPack) checked = vizArr[packIx[vis]]; +else + checked = vizArr[vis]; cgiMakeDropListClassWithIdStyleJavascriptAndLabel(varName, NULL, vizArr, vizArrLen, checked, class, TV_DROPDOWN_STYLE, events, label); } void hTvDropDownClassVisOnlyAndExtra(char *varName, enum trackVisibility vis, boolean canPack, char *class, char *visOnly, struct slPair *events) // Make track visibility drop down for varName with style class, and potentially limited to visOnly { hTvDropDownClassVisOnlyAndExtraWithLabel(varName, vis, canPack, class, visOnly, events, NULL); } void hideShowDropDownWithClassExtraAndLabel(char *varName, char *id, boolean show, char *class, struct slPair *events, char *ariaLabel) // Make hide/show dropdown for varName with optional aria-label { @@ -9999,39 +10023,73 @@ } return vis; } enum trackVisibility tdbVisLimitedByAncestors(struct cart *cart, struct trackDb *tdb, boolean checkBoxToo, boolean foldersToo) // returns visibility limited by ancestry. // This includes subtrack vis override and parents limit maximum. // cart may be null, in which case, only trackDb settings (default state) are examined // checkBoxToo means ensure subtrack checkbox state is visible // foldersToo means limit by folders (aka superTracks) as well. { boolean subtrackOverride = FALSE; enum trackVisibility vis = tdbLocalVisibility(cart,tdb,&subtrackOverride); +// Children of a faceted composite are heterogeneous enough that one inherited vis won't +// do, so they keep a display mode of their own and the parent's vis is only a ceiling. +boolean facetedChild = (tdbIsContainerChild(tdb) && tdbIsFacetedComposite(tdb->parent)); +char *onlyVis = (facetedChild ? trackDbLocalSetting(tdb, "onlyVisibility") : NULL); + if (tdbIsContainerChild(tdb)) { + if (facetedChild) + { + // A child of a faceted composite holds a display mode of its own rather than + // inheriting the parent's. NOTE: tdb->visibility can't tell "asked for something" + // from "inherited a default", since trackDbFieldsFromSettings() fills it through + // the inheriting trackDbSetting() - hence trackDbLocalSetting here. + boolean hasOwnVis = (subtrackOverride + || trackDbLocalSetting(tdb, "visibility") != NULL); + if (onlyVis != NULL) + { + // onlyVisibility pins the child to a single mode, but asking to hide still hides + if (!(hasOwnVis && vis == tvHide)) + vis = tvFromVisOnlySetting(onlyVis); + } + else if (!hasOwnVis) + vis = tvFull; // No mode of its own, so take whatever the parent allows + } // subtracks without explicit (cart) vis but are selected, should get inherited vis - if (!subtrackOverride) + else if (!subtrackOverride) vis = tvFull; // subtracks with checkbox that says no, are stopped cold if (checkBoxToo && !fourStateVisible(subtrackFourStateChecked(tdb,cart))) vis = tvHide; // Checkbox says no } +if (facetedChild) + { + // Note this skips the subtrackOverride shortcut below on purpose: escaping the + // parent's limit is exactly the behavior a faceted composite doesn't want. + if (vis == tvHide) + return tvHide; + enum trackVisibility maxVis = tdbVisLimitedByAncestors(cart,tdb->parent,checkBoxToo, + foldersToo); + if (onlyVis != NULL) // A pinned child either fits under the maximum or doesn't draw + return (tvCompare(vis,maxVis) >= 0 ? vis : tvHide); + return tvMin(vis,maxVis); + } if (subtrackOverride) return vis; // aka superTrack if (vis == tvHide || tdb->parent == NULL || (!foldersToo && tdbIsFolder(tdb->parent))) return vis; // end of line return tvMin(vis,tdbVisLimitedByAncestors(cart,tdb->parent,checkBoxToo,foldersToo)); } char *compositeViewControlNameFromTdb(struct trackDb *tdb) // Returns a string with the composite view control name if one exists { char *stView = NULL; char *name = NULL; char *rootName = NULL;