SetFlagsRecursive
Sets the specified flags recursively on the hierarchy node.
Read time 5 minutesLast updated 12 days ago
Definition
- Type: Method
- Namespace: Unity.Hierarchy
- Assembly: UnityEngine.HierarchyCoreModule
SetFlagsRecursive(HierarchyNode, HierarchyNodeFlags, HierarchyTraversalDirection)
Sets the specified flags recursively on the hierarchy node.
public void SetFlagsRecursive(in HierarchyNode node, HierarchyNodeFlags flags, HierarchyTraversalDirection direction)
Parameters
The root hierarchy node to set flags on recursively.
The flags to set on the hierarchy node and its descendants.
The direction of the recursion operation.
Remarks
Additional Resources: HierarchyViewModel.ClearFlagsRecursive
The following example draws visual connector lines in the Hierarchy window to show the parent and child relationships between GameObjects. It uses to add a hover flag to a parent node and all of its child nodes when your mouse enters a connector line in the Hierarchy window.
SetFlagsRecursiveThe example requires three USS files: for the base styles, for the Dark theme, and for the Light theme.
Connectors.ussConnectors_dark.ussConnectors_light.ussTo use this example, save the script and USS files in a folder called . Scripts in an folder can use the Hierarchy module API without additional setup. If you save the script outside of an folder, you must enable the Hierarchy built-in module in the Package Manager window, which also adds the module to your Player builds.
Assets/Editor/ConnectorsEditorEditorusing 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;}
The following example creates a context menu item that collapses all nodes in the Hierarchy window except the paths to the selected items. The action appears in the Hierarchy Samples submenu of the context menu. It uses to expand the ancestors of the selected nodes.
SetFlagsRecursiveusing System;using Unity.Hierarchy;using Unity.Hierarchy.Editor;using UnityEditor;using UnityEngine.UIElements;namespace Unity.HierarchySamples.Editor{ class CollapseOthers { [InitializeOnLoadMethod] static void Initialize() { HierarchyWindow.PopulateContextMenu += OnPopulateContextMenu; } static void OnPopulateContextMenu(HierarchyWindow window, HierarchyView view, HierarchyViewItem item, DropdownMenu menu) { menu.AppendAction("Hierarchy Samples/Collapse Others", a => { // Capture selected and expanded nodes. int selectedAndExpandedCount = view.ViewModel.HasFlagsCount(HierarchyNodeFlags.Selected | HierarchyNodeFlags.Expanded); Span<HierarchyNode> expandedAndSelectedNodes = selectedAndExpandedCount < 16 ? stackalloc HierarchyNode[selectedAndExpandedCount] : new HierarchyNode[selectedAndExpandedCount]; view.ViewModel.GetNodesWithFlags(HierarchyNodeFlags.Selected | HierarchyNodeFlags.Expanded, expandedAndSelectedNodes); // Create a flags change scope. This is an optimization to avoid triggering an update if no flags // actually changed after the operation. using (_ = new HierarchyViewModelFlagsChangeScope(view.ViewModel)) { // Collapse all nodes. view.ViewModel.ClearFlags(HierarchyNodeFlags.Expanded); // Expand parents of all selected nodes. foreach (ref readonly var node in view.ViewModel.EnumerateNodesWithFlags(HierarchyNodeFlags.Selected)) { var parent = view.ViewModel.GetParent(node); if (parent == HierarchyNode.Null || parent == view.Source.Root) continue; view.ViewModel.SetFlagsRecursive(parent, HierarchyNodeFlags.Expanded, HierarchyTraversalDirection.Parents); } // Expand all nodes that were previously expanded and selected. view.Expand(expandedAndSelectedNodes); } }, _ => item == null || (view.ViewModel.HasFlagsCount(HierarchyNodeFlags.Selected) == 0) ? DropdownMenuAction.Status.Disabled : DropdownMenuAction.Status.Normal); } }}
SetFlagsRecursive(ReadOnlySpan<HierarchyNode>, HierarchyNodeFlags, HierarchyTraversalDirection)
Sets the specified flags recursively on the hierarchy nodes.
public void SetFlagsRecursive(ReadOnlySpan<HierarchyNode> nodes, HierarchyNodeFlags flags, HierarchyTraversalDirection direction)
Parameters
The hierarchy nodes to set flags on recursively.
The flags to set on the hierarchy nodes and their descendants.
The direction of the recursion operation.