public ElementHierarchyView( VisualElement documentRootElement, BuilderSelection selection, BuilderClassDragger classDragger, BuilderHierarchyDragger hierarchyDragger, BuilderExplorerContextMenu contextMenuManipulator, Action <VisualElement> selectElementCallback, HighlightOverlayPainter highlightOverlayPainter) { m_DocumentRootElement = documentRootElement; m_Selection = selection; m_ClassDragger = classDragger; m_HierarchyDragger = hierarchyDragger; m_ContextMenuManipulator = contextMenuManipulator; this.focusable = true; m_SelectElementCallback = selectElementCallback; hierarchyHasChanged = true; m_SearchResultsHightlights = new List <VisualElement>(); this.RegisterCallback <FocusEvent>(e => m_TreeView?.Focus()); // HACK: ListView/TreeView need to clear their selections when clicking on nothing. this.RegisterCallback <MouseDownEvent>(e => { var leafTarget = e.leafTarget as VisualElement; if (leafTarget.parent is ScrollView) { ClearSelection(); } }); m_TreeViewHoverOverlay = highlightOverlayPainter; m_Container = new VisualElement(); m_Container.name = "explorer-container"; m_Container.style.flexGrow = 1; m_ClassDragger.builderHierarchyRoot = m_Container; m_HierarchyDragger.builderHierarchyRoot = m_Container; Add(m_Container); m_SearchBar = new ElementHierarchySearchBar(this); Add(m_SearchBar); // TODO: Hiding for now since search does not work, especially with style class pills. m_SearchBar.style.display = DisplayStyle.None; m_ClassPillTemplate = AssetDatabase.LoadAssetAtPath <VisualTreeAsset>( BuilderConstants.UIBuilderPackagePath + "/BuilderClassPill.uxml"); // Create TreeView. m_TreeRootItems = new List <ITreeViewItem>(); m_TreeView = new TreeView(m_TreeRootItems, 20, MakeItem, FillItem); m_TreeView.viewDataKey = "unity-builder-explorer-tree"; m_TreeView.style.flexGrow = 1; #if UNITY_2020_1_OR_NEWER m_TreeView.onSelectionChange += OnSelectionChange; #else m_TreeView.onSelectionChanged += OnSelectionChange; #endif m_Container.Add(m_TreeView); m_ContextMenuManipulator.RegisterCallbacksOnTarget(m_Container); }
void FillItem(VisualElement element, ITreeViewItem item) { var explorerItem = element as BuilderExplorerItem; explorerItem.Clear(); // Pre-emptive cleanup. var row = explorerItem.parent.parent; row.RemoveFromClassList(BuilderConstants.ExplorerHeaderRowClassName); row.RemoveFromClassList(BuilderConstants.ExplorerItemHiddenClassName); // Get target element (in the document). var documentElement = (item as TreeViewItem <VisualElement>).data; documentElement.SetProperty(BuilderConstants.ElementLinkedExplorerItemVEPropertyName, explorerItem); explorerItem.userData = documentElement; row.userData = documentElement; // If we have a FillItem callback (override), we call it and stop creating the rest of the item. var fillItemCallback = documentElement.GetProperty(BuilderConstants.ExplorerItemFillItemCallbackVEPropertyName) as Action <VisualElement, ITreeViewItem, BuilderSelection>; if (fillItemCallback != null) { fillItemCallback(explorerItem, item, m_Selection); return; } // Create main label container. var labelCont = new VisualElement(); labelCont.AddToClassList(BuilderConstants.ExplorerItemLabelContClassName); explorerItem.Add(labelCont); if (BuilderSharedStyles.IsSelectorsContainerElement(documentElement)) { var styleSheetAsset = documentElement.GetStyleSheet(); var styleSheetFileName = AssetDatabase.GetAssetPath(styleSheetAsset); var styleSheetAssetName = string.IsNullOrEmpty(styleSheetFileName) ? BuilderConstants.ToolbarUnsavedFileDisplayMessage + BuilderConstants.UssExtension : Path.GetFileName(styleSheetFileName); var ssLabel = new Label(styleSheetAssetName); ssLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); ssLabel.AddToClassList("unity-debugger-tree-item-type"); row.AddToClassList(BuilderConstants.ExplorerHeaderRowClassName); labelCont.Add(ssLabel); return; } else if (BuilderSharedStyles.IsSelectorElement(documentElement)) { var selectorParts = BuilderSharedStyles.GetSelectorParts(documentElement); foreach (var partStr in selectorParts) { if (partStr.StartsWith(BuilderConstants.UssSelectorClassNameSymbol)) { m_ClassPillTemplate.CloneTree(labelCont); var pill = labelCont.contentContainer.ElementAt(labelCont.childCount - 1); var pillLabel = pill.Q <Label>("class-name-label"); pill.AddToClassList("unity-debugger-tree-item-pill"); pill.SetProperty(BuilderConstants.ExplorerStyleClassPillClassNameVEPropertyName, partStr); pill.userData = documentElement; // Add ellipsis if the class name is too long. var partStrShortened = BuilderNameUtilities.CapStringLengthAndAddEllipsis(partStr, BuilderConstants.ClassNameInPillMaxLength); pillLabel.text = partStrShortened; m_ClassDragger.RegisterCallbacksOnTarget(pill); } else if (partStr.StartsWith(BuilderConstants.UssSelectorNameSymbol)) { var selectorPartLabel = new Label(partStr); selectorPartLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); selectorPartLabel.AddToClassList(BuilderConstants.ElementNameClassName); labelCont.Add(selectorPartLabel); } else if (partStr.StartsWith(BuilderConstants.UssSelectorPseudoStateSymbol)) { var selectorPartLabel = new Label(partStr); selectorPartLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); selectorPartLabel.AddToClassList(BuilderConstants.ElementPseudoStateClassName); labelCont.Add(selectorPartLabel); } else if (partStr == BuilderConstants.SingleSpace) { var selectorPartLabel = new Label(BuilderConstants.TripleSpace); selectorPartLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); selectorPartLabel.AddToClassList(BuilderConstants.ElementTypeClassName); labelCont.Add(selectorPartLabel); } else { var selectorPartLabel = new Label(partStr); selectorPartLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); selectorPartLabel.AddToClassList(BuilderConstants.ElementTypeClassName); labelCont.Add(selectorPartLabel); } } // Register right-click events for context menu actions. m_ContextMenuManipulator.RegisterCallbacksOnTarget(explorerItem); return; } else if (BuilderSharedStyles.IsDocumentElement(documentElement)) { var uxmlAsset = documentElement.GetVisualTreeAsset(); var uxmlAssetName = string.IsNullOrEmpty(uxmlAsset.name) ? BuilderConstants.ToolbarUnsavedFileDisplayMessage : uxmlAsset.name; var ssLabel = new Label(uxmlAssetName + BuilderConstants.UxmlExtension); ssLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); ssLabel.AddToClassList("unity-debugger-tree-item-type"); row.AddToClassList(BuilderConstants.ExplorerHeaderRowClassName); labelCont.Add(ssLabel); return; } // Check if element is inside current document. if (!documentElement.IsPartOfCurrentDocument()) { row.AddToClassList(BuilderConstants.ExplorerItemHiddenClassName); } // Register drag-and-drop events for reparenting. m_HierarchyDragger.RegisterCallbacksOnTarget(explorerItem); // Allow reparenting. explorerItem.SetProperty(BuilderConstants.ExplorerItemElementLinkVEPropertyName, documentElement); // Element type label. if (string.IsNullOrEmpty(documentElement.name) || elementInfoVisibilityState.HasFlag(BuilderExplorer.BuilderElementInfoVisibilityState.TypeName)) { var typeLabel = new Label(documentElement.typeName); typeLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); typeLabel.AddToClassList(BuilderConstants.ElementTypeClassName); labelCont.Add(typeLabel); } // Element name label. var nameLabel = new Label(); nameLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); nameLabel.AddToClassList("unity-debugger-tree-item-name-label"); nameLabel.AddToClassList(BuilderConstants.ExplorerItemNameLabelClassName); nameLabel.AddToClassList(BuilderConstants.ElementNameClassName); if (!string.IsNullOrEmpty(documentElement.name)) { nameLabel.text = "#" + documentElement.name; } labelCont.Add(nameLabel); // Textfield to rename element in hierarchy. var renameTextfield = explorerItem.CreateRenamingTextField(documentElement, nameLabel, m_Selection); labelCont.Add(renameTextfield); // Add class list. if (documentElement.classList.Count > 0 && elementInfoVisibilityState.HasFlag(BuilderExplorer.BuilderElementInfoVisibilityState.ClassList)) { foreach (var ussClass in documentElement.GetClasses()) { var classLabelCont = new VisualElement(); classLabelCont.AddToClassList(BuilderConstants.ExplorerItemLabelContClassName); explorerItem.Add(classLabelCont); var classLabel = new Label("." + ussClass); classLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); classLabel.AddToClassList(BuilderConstants.ElementClassNameClassName); classLabel.AddToClassList("unity-debugger-tree-item-classlist-label"); classLabelCont.Add(classLabel); } } // Show name of uxml file if this element is a TemplateContainer. var path = documentElement.GetProperty(BuilderConstants.LibraryItemLinkedTemplateContainerPathVEPropertyName) as string; if (documentElement is TemplateContainer && !string.IsNullOrEmpty(path)) { var pathStr = Path.GetFileName(path); var label = new Label(pathStr); label.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); label.AddToClassList(BuilderConstants.ElementTypeClassName); label.AddToClassList("unity-builder-explorer-tree-item-template-path"); // Just make it look a bit shaded. labelCont.Add(label); } // Register right-click events for context menu actions. m_ContextMenuManipulator.RegisterCallbacksOnTarget(explorerItem); }