| Parameter | Description |
|---|---|
| node | The hierarchy node. |
| flags | The hierarchy node flags. |
| direction | The direction of the recursion operation. |
Clears the specified flags recursively on the hierarchy node.
Additional resources: HierarchyViewModel.SetFlagsRecursive
The following example draws visual connector lines in the Hierarchy window to show the parent and child relationships between GameObjects. It uses ClearFlagsRecursive to remove a hover flag set on a parent node and all of its child nodes when your mouse leaves a connector line in the Hierarchy window.
The example requires three USS files: Connectors.uss for the base styles, Connectors_dark.uss for the Dark theme, and Connectors_light.uss for the Light theme.
To use this example, save the script and USS files in a folder called Assets/Editor/Connectors. Scripts in an Editor folder can use the Hierarchy module API without additional setup. If you save the script outside of an Editor folder, you must enable the Hierarchy built-in module in the Package Manager window, which also adds the module to your Player builds.
using System; using System.Collections.Generic; using Unity.Hierarchy; using Unity.Hierarchy.Editor; using UnityEditor; using UnityEngine.Pool; using UnityEngine.UIElements;
namespace Unity.HierarchySamples.Editor { class Connectors { const string k_ConnectorUssClassName = "connector"; const string k_ConnectorHoverUssClassName = "connector--hovered"; const string k_ConnectorContainerClassName = "connector-container";
[InitializeOnLoadMethod] static void Initialize() { HierarchyWindow.BindView += OnBindView; HierarchyWindow.UnbindView += OnUnbindView; }
static void OnBindView(HierarchyWindow window, HierarchyView view) { view.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/Connectors/Connectors.uss")); view.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>($"Assets/Editor/Connectors/Connectors{(EditorGUIUtility.isProSkin ? "_dark" : "_light")}.uss"));
ConnectorsHandler connectorHandler = new ConnectorsHandler(view); view.BindViewItem += connectorHandler.OnBindViewItem; view.userData = connectorHandler; }
static void OnUnbindView(HierarchyWindow window, HierarchyView view) { if (view.userData is ConnectorsHandler connectorHandler) view.BindViewItem -= connectorHandler.OnBindViewItem; }
class ConnectorsHandler { static readonly List<VisualElement> s_ConnectorsCache = new(); static readonly ObjectPool<VisualElement> s_ConnectorVisualElementPool = new(() => new VisualElement(), actionOnRelease: e => e.userData = null);
readonly HierarchyView m_View;
int m_HoverDepth = -1;
internal ConnectorsHandler(HierarchyView view) => m_View = view;
internal void OnBindViewItem(HierarchyView view, HierarchyViewItem viewItem) { HierarchyViewModel viewModel = view.ViewModel; VisualElement connectorContainer = viewItem.Q(className: k_ConnectorContainerClassName); if (connectorContainer == null) { connectorContainer = new VisualElement(); connectorContainer.AddToClassList(k_ConnectorContainerClassName); viewItem.Add(connectorContainer); }
s_ConnectorsCache.Clear(); connectorContainer.Query(className: k_ConnectorUssClassName).ToList(s_ConnectorsCache);
// Depth is 0 when filtering because the tree is flattened int nodeDepth = view.Filtering ? 0 : viewModel.GetDepth(viewItem.Node); HierarchyNode nodeParent = viewModel.GetParent(viewItem.Node); bool parentHasHoveredFlag = viewModel.HasFlags(nodeParent, (HierarchyNodeFlags)HierarchyNodeFlagsExtended.ConnectorsHovered);
for (int i = 0; i < nodeDepth; i++) { VisualElement connector; if (i < s_ConnectorsCache.Count) { connector = s_ConnectorsCache[i]; } else { connector = s_ConnectorVisualElementPool.Get(); connector.AddToClassList(k_ConnectorUssClassName); connectorContainer.Add(connector); connector.RegisterCallback<MouseEnterEvent>(OnMouseEnter); connector.RegisterCallback<MouseLeaveEvent>(OnMouseLeave); connector.RegisterCallback<MouseDownEvent>(OnConnectorPressed); }
connector.userData = (viewItem, i); connector.style.left = i * 14; connector.EnableInClassList(k_ConnectorHoverUssClassName, parentHasHoveredFlag && i == m_HoverDepth); }
for (int i = nodeDepth; i < s_ConnectorsCache.Count; i++) { VisualElement connector = s_ConnectorsCache[i]; connector.RemoveFromHierarchy(); connector.UnregisterCallback<MouseEnterEvent>(OnMouseEnter); connector.UnregisterCallback<MouseLeaveEvent>(OnMouseLeave); connector.UnregisterCallback<MouseDownEvent>(OnConnectorPressed); s_ConnectorVisualElementPool.Release(connector); } }
static (HierarchyViewItem viewItem, int depth) GetConnectorData(EventBase evt) => ((HierarchyViewItem, int))((VisualElement)evt.currentTarget).userData;
void OnMouseEnter(MouseEnterEvent evt) { (HierarchyViewItem viewItem, int depth) = GetConnectorData(evt); m_HoverDepth = depth; HierarchyNode ancestor = GetAncestorAtDepth(viewItem, depth); viewItem.View.ViewModel.SetFlagsRecursive(ancestor, (HierarchyNodeFlags)HierarchyNodeFlagsExtended.ConnectorsHovered, HierarchyTraversalDirection.Children); }
void OnMouseLeave(MouseLeaveEvent evt) { m_HoverDepth = -1; m_View.ViewModel.ClearFlags((HierarchyNodeFlags)HierarchyNodeFlagsExtended.ConnectorsHovered); }
void OnConnectorPressed(MouseDownEvent evt) { (HierarchyViewItem viewItem, int depth) = GetConnectorData(evt); HierarchyNode ancestor = GetAncestorAtDepth(viewItem, depth); if (evt.altKey) viewItem.View.ViewModel.ClearFlagsRecursive(ancestor, HierarchyNodeFlags.Expanded, HierarchyTraversalDirection.Children); else viewItem.View.ViewModel.ClearFlags(ancestor, HierarchyNodeFlags.Expanded); }
HierarchyNode GetAncestorAtDepth(HierarchyViewItem viewItem, int depth) { HierarchyNode ancestor = viewItem.Node; for (int i = viewItem.View.ViewModel.GetDepth(viewItem.Node); i > depth; i--) ancestor = viewItem.View.ViewModel.GetParent(ancestor);
return ancestor; } }
// Custom flags can be defined by using unused bits in the HierarchyNodeFlags enum. // This example uses bit 4 to track hover state for connector visualization. enum HierarchyNodeFlagsExtended : uint { ConnectorsHovered = 1 << 4 } } }
The following example shows how to style Connectors.uss.
.connector {
width: 10px;
border-left-width: 1px;
height: 100%;
position: absolute;
}
.connector-container {
position: absolute;
left: 12px;
top: 0;
background-color: chartreuse;
height: 20px;
width: auto;
}
.connector.connector--hovered{
border-left-width: 1px;
}
The following example shows how to style Connectors_dark.uss.
.connector {
border-left-color: rgba(169, 169, 169, 0.42);
}
.connector.connector--hovered{
border-left-color: darkgrey;
}
The following example shows how to style Connectors_light.uss.
.connector {
border-left-color: darkgrey;
}
.connector.connector--hovered{
border-left-color: grey;
}
| Parameter | Description |
|---|---|
| nodes | The hierarchy nodes. |
| flags | The hierarchy node flags. |
| direction | The direction of the recursion operation. |
Clears the specified flags recursively on the hierarchy nodes.