public BuilderViewport(BuilderPaneWindow paneWindow, BuilderSelection selection, BuilderElementContextMenu contextMenuManipulator) { m_PaneWindow = paneWindow; m_Selection = selection; m_ContextMenuManipulator = contextMenuManipulator; AddToClassList("unity-builder-viewport"); var template = AssetDatabase.LoadAssetAtPath <VisualTreeAsset>(BuilderConstants.UIBuilderPackagePath + "/BuilderViewport.uxml"); template.CloneTree(this); m_Toolbar = this.Q("toolbar"); m_ViewportWrapper = this.Q("viewport-wrapper"); m_Viewport = this.Q("viewport"); m_Surface = this.Q("viewport-surface"); m_Surface.pickingMode = PickingMode.Ignore; m_Canvas = this.Q <BuilderCanvas>("canvas"); m_Canvas.document = paneWindow.document; m_SharedStylesAndDocumentElement = this.Q("shared-styles-and-document"); m_StyleSelectorElementContainer = this.Q(BuilderConstants.StyleSelectorElementContainerName); m_DocumentElement = this.Q("document"); m_Canvas.documentElement = m_DocumentElement; m_PickOverlay = this.Q("pick-overlay"); m_HighlightOverlay = this.Q("highlight-overlay"); m_BuilderParentTracker = this.Q <BuilderParentTracker>("parent-tracker"); m_BuilderResizer = this.Q <BuilderResizer>("resizer"); m_BuilderMover = this.Q <BuilderMover>("mover"); m_BuilderAnchorer = this.Q <BuilderAnchorer>("anchorer"); m_BuilderZoomer = new BuilderZoomer(this); m_BuilderPanner = new BuilderPanner(this); m_BuilderMover.parentTracker = m_BuilderParentTracker; m_PickOverlay.RegisterCallback <MouseDownEvent>(OnPick); m_PickOverlay.RegisterCallback <MouseMoveEvent>(OnHover); m_PickOverlay.RegisterCallback <MouseLeaveEvent>(OnMouseLeave); m_Viewport.RegisterCallback <MouseDownEvent>(OnMissPick); m_Viewport.RegisterCallback <GeometryChangedEvent>(OnGeometryChanged); m_ContextMenuManipulator?.RegisterCallbacksOnTarget(m_Viewport); // Make sure this gets focus when the pane gets focused. primaryFocusable = this; focusable = true; // Restore the zoom scale zoomScale = paneWindow.document.viewportZoomScale; contentOffset = paneWindow.document.viewportContentOffset; }
void OnPick(MouseDownEvent evt) { // Do not prevent zoom and pan if (evt.button == 2 || (evt.ctrlKey && evt.altKey || (evt.button == (int)MouseButton.RightMouse && evt.altKey))) { return; } var pickedElement = PickElement(evt.mousePosition); if (pickedElement != null) { m_Selection.Select(this, pickedElement); SetInnerSelection(pickedElement); if (evt.clickCount == 2) { var posInViewport = m_PickOverlay.ChangeCoordinatesTo(this, evt.localMousePosition); BuilderInPlaceTextEditingUtilities.OpenEditor(pickedElement, this.ChangeCoordinatesTo(pickedElement, posInViewport)); } } else { ClearInnerSelection(); m_Selection.ClearSelection(this); } if (evt.button == (int)MouseButton.RightMouse) { if (pickedElement != null && m_ContextMenuManipulator != null) { pickedElement.SetProperty(BuilderConstants.ElementLinkedDocumentVisualElementVEPropertyName, pickedElement); m_ContextMenuManipulator.RegisterCallbacksOnTarget(pickedElement); m_ContextMenuManipulator.DisplayContextMenu(evt, pickedElement); evt.StopPropagation(); } } else { evt.StopPropagation(); } }
void OnPick(MouseDownEvent evt) { // Do not prevent zoom and pan if (evt.button == 2 || (evt.ctrlKey && evt.altKey || (evt.button == (int)MouseButton.RightMouse && evt.altKey))) { return; } var pickedElement = PickElement(evt.mousePosition); if (pickedElement != null) { SetInnerSelection(pickedElement); m_Selection.Select(this, pickedElement); } else { ClearInnerSelection(); m_Selection.ClearSelection(this); } if (evt.button == (int)MouseButton.RightMouse) { if (pickedElement != null && m_ContextMenuManipulator != null) { pickedElement.SetProperty(BuilderConstants.ElementLinkedDocumentVisualElementVEPropertyName, pickedElement); m_ContextMenuManipulator.RegisterCallbacksOnTarget(pickedElement); m_ContextMenuManipulator.DisplayContextMenu(evt, pickedElement); evt.StopPropagation(); } } else { evt.StopPropagation(); } }
public BuilderViewport(BuilderPaneWindow paneWindow, BuilderSelection selection, BuilderElementContextMenu contextMenuManipulator) { m_PaneWindow = paneWindow; m_Selection = selection; m_ContextMenuManipulator = contextMenuManipulator; AddToClassList("unity-builder-viewport"); var template = AssetDatabase.LoadAssetAtPath <VisualTreeAsset>(BuilderConstants.UIBuilderPackagePath + "/BuilderViewport.uxml"); template.CloneTree(this); m_Toolbar = this.Q("toolbar"); m_ViewportWrapper = this.Q("viewport-wrapper"); m_Viewport = this.Q("viewport"); m_Surface = this.Q("viewport-surface"); m_Surface.pickingMode = PickingMode.Ignore; m_Canvas = this.Q <BuilderCanvas>("canvas"); m_Canvas.document = paneWindow.document; m_SharedStylesAndDocumentElement = this.Q("shared-styles-and-document"); m_SharedStylesAndDocumentElement.pseudoStates |= PseudoStates.Root; // To apply variables of the active theme that are defined in the :root selector m_StyleSelectorElementContainer = this.Q(BuilderConstants.StyleSelectorElementContainerName); m_DocumentElement = this.Q("document"); m_Canvas.documentElement = m_DocumentElement; m_EditorLayer = this.Q("__unity-editor-layer"); m_EditorLayer.AddToClassList(BuilderConstants.HiddenStyleClassName); m_TextEditor = this.Q <TextField>("__unity-text-editor"); m_Canvas.editorLayer = m_EditorLayer; m_PickOverlay = this.Q("pick-overlay"); m_HighlightOverlay = this.Q("highlight-overlay"); m_BuilderParentTracker = this.Q <BuilderParentTracker>("parent-tracker"); m_BuilderSelectionIndicator = this.Q <BuilderSelectionIndicator>("selection-indicator"); m_BuilderResizer = this.Q <BuilderResizer>("resizer"); m_BuilderMover = this.Q <BuilderMover>("mover"); m_BuilderAnchorer = this.Q <BuilderAnchorer>("anchorer"); m_BuilderZoomer = new BuilderZoomer(this); m_BuilderPanner = new BuilderPanner(this); m_BuilderMover.parentTracker = m_BuilderParentTracker; m_PickOverlay.RegisterCallback <MouseDownEvent>(OnPick); m_PickOverlay.RegisterCallback <MouseMoveEvent>(OnHover); m_PickOverlay.RegisterCallback <MouseLeaveEvent>(OnMouseLeave); m_Viewport.RegisterCallback <MouseDownEvent>(OnMissPick); m_Viewport.RegisterCallback <GeometryChangedEvent>(OnGeometryChanged); m_Canvas.header.AddManipulator(new Clickable(OnCanvasHeaderClick)); m_ContextMenuManipulator?.RegisterCallbacksOnTarget(m_Viewport); // Make sure this gets focus when the pane gets focused. primaryFocusable = this; focusable = true; // Restore the zoom scale zoomScale = paneWindow.document.viewportZoomScale; contentOffset = paneWindow.document.viewportContentOffset; // Repaint bug workaround. m_CheckerboardBackground = this.Q <CheckerboardBackground>(); RegisterCallback <BlurEvent>(e => { m_CheckerboardBackground.MarkDirtyRepaint(); }); RegisterCallback <FocusEvent>(e => { m_CheckerboardBackground.MarkDirtyRepaint(); }); }
public ElementHierarchyView( VisualElement documentRootElement, BuilderSelection selection, BuilderClassDragger classDragger, BuilderHierarchyDragger hierarchyDragger, BuilderElementContextMenu 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 #if UNITY_2019_3_OR_NEWER m_TreeView.RegisterCallback <MouseDownEvent>(OnLeakedMouseClick); #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.SetProperty(BuilderConstants.ElementLinkedDocumentVisualElementVEPropertyName, 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 = BuilderAssetUtilities.GetStyleSheetAssetName(styleSheetAsset); 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; } if (BuilderSharedStyles.IsDocumentElement(documentElement)) { var uxmlAsset = documentElement.GetVisualTreeAsset(); var ssLabel = new Label(BuilderAssetUtilities.GetVisualTreeAssetAssetName(uxmlAsset)); 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); }
void OnPick(MouseDownEvent evt) { // Do not prevent zoom and pan if (evt.button == 2 || (evt.ctrlKey && evt.altKey || (evt.button == (int)MouseButton.RightMouse && evt.altKey))) { return; } m_PickedElements.Clear(); var pickedElement = PickElement(evt.mousePosition, m_PickedElements); if (pickedElement != null) { var timeSinceStartup = EditorApplication.timeSinceStartup; var previousMouseRect = new Rect( m_PreviousPickMousePosition.x - BuilderConstants.PickSelectionRepeatRectHalfSize, m_PreviousPickMousePosition.y - BuilderConstants.PickSelectionRepeatRectHalfSize, BuilderConstants.PickSelectionRepeatRectSize, BuilderConstants.PickSelectionRepeatRectSize); if (timeSinceStartup - m_PreviousPickMouseTime > BuilderConstants.PickSelectionRepeatMinTimeDelay && previousMouseRect.Contains(evt.mousePosition)) { m_SameLocationPickCount++; var offset = 0; var index = m_PickedElements.IndexOf(pickedElement); // For compound controls, we don't seem to have the actual field root element // in the pickedElements list. So we get index == -1 here. We need to do // some magic to select the proper parent element from the list then. if (index < 0) { index = m_PickedElements.IndexOf(pickedElement.parent); offset = 1; } var maxIndex = m_PickedElements.Count - 1; var newIndex = index + m_SameLocationPickCount - offset; if (newIndex > maxIndex) { m_SameLocationPickCount = 0; } else { pickedElement = m_PickedElements[newIndex]; } } else { m_SameLocationPickCount = 0; } m_PreviousPickMousePosition = evt.mousePosition; m_PreviousPickMouseTime = EditorApplication.timeSinceStartup; m_Selection.Select(this, pickedElement); SetInnerSelection(pickedElement); if (evt.clickCount == 2) { var posInViewport = m_PickOverlay.ChangeCoordinatesTo(this, evt.localMousePosition); BuilderInPlaceTextEditingUtilities.OpenEditor(pickedElement, this.ChangeCoordinatesTo(pickedElement, posInViewport)); } } else { ClearInnerSelection(); m_Selection.ClearSelection(this); } if (evt.button == (int)MouseButton.RightMouse) { if (pickedElement != null && m_ContextMenuManipulator != null) { pickedElement.SetProperty(BuilderConstants.ElementLinkedDocumentVisualElementVEPropertyName, pickedElement); m_ContextMenuManipulator.RegisterCallbacksOnTarget(pickedElement); m_ContextMenuManipulator.DisplayContextMenu(evt, pickedElement); evt.StopPropagation(); } } else { evt.StopPropagation(); } }
public ElementHierarchyView( BuilderPaneWindow paneWindow, VisualElement documentRootElement, BuilderSelection selection, BuilderClassDragger classDragger, BuilderExplorerDragger explorerDragger, BuilderElementContextMenu contextMenuManipulator, Action <List <VisualElement> > selectElementCallback, HighlightOverlayPainter highlightOverlayPainter) { m_PaneWindow = paneWindow; m_DocumentRootElement = documentRootElement; m_Selection = selection; m_ClassDragger = classDragger; m_ExplorerDragger = explorerDragger; m_ContextMenuManipulator = contextMenuManipulator; this.focusable = true; m_SelectElementCallback = selectElementCallback; hierarchyHasChanged = true; hasUnsavedChanges = false; 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_ExplorerDragger.builderHierarchyRoot = m_Container; Add(m_Container); 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); #if UNITY_2020_1_OR_NEWER m_TreeView.selectionType = SelectionType.Multiple; #else m_TreeView.selectionType = SelectionType.Single; // ListView/TreeView do not support selecting mutliple items via code. #endif 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 #if UNITY_2019_3_OR_NEWER m_TreeView.RegisterCallback <MouseDownEvent>(OnLeakedMouseClick); #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); row.RemoveFromClassList(BuilderConstants.ExplorerActiveStyleSheetClassName); // Get target element (in the document). var documentElement = (item as TreeViewItem <VisualElement>).data; documentElement.SetProperty(BuilderConstants.ElementLinkedExplorerItemVEPropertyName, explorerItem); explorerItem.SetProperty(BuilderConstants.ElementLinkedDocumentVisualElementVEPropertyName, 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.IsStyleSheetElement(documentElement)) { var owningUxmlPath = documentElement.GetProperty(BuilderConstants.ExplorerItemLinkedUXMLFileName) as string; var isPartOfParentDocument = !string.IsNullOrEmpty(owningUxmlPath); var styleSheetAsset = documentElement.GetStyleSheet(); var styleSheetFileName = AssetDatabase.GetAssetPath(styleSheetAsset); var styleSheetAssetName = BuilderAssetUtilities.GetStyleSheetAssetName(styleSheetAsset, hasUnsavedChanges && !isPartOfParentDocument); var ssLabel = new Label(styleSheetAssetName); ssLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); ssLabel.AddToClassList("unity-debugger-tree-item-type"); row.AddToClassList(BuilderConstants.ExplorerHeaderRowClassName); labelCont.Add(ssLabel); // Register right-click events for context menu actions. m_ContextMenuManipulator.RegisterCallbacksOnTarget(explorerItem); // Register drag-and-drop events for reparenting. m_ExplorerDragger.RegisterCallbacksOnTarget(explorerItem); // Allow reparenting. explorerItem.SetProperty(BuilderConstants.ExplorerItemElementLinkVEPropertyName, documentElement); var assetIsActiveStyleSheet = styleSheetAsset == m_PaneWindow.document.activeStyleSheet; if (assetIsActiveStyleSheet) { row.AddToClassList(BuilderConstants.ExplorerActiveStyleSheetClassName); } if (isPartOfParentDocument) { row.AddToClassList(BuilderConstants.ExplorerItemHiddenClassName); } // Show name of UXML file that USS file 'belongs' to. if (!string.IsNullOrEmpty(owningUxmlPath)) { var pathStr = Path.GetFileName(owningUxmlPath); var label = new Label(BuilderConstants.TripleSpace + 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); } return; } else if (BuilderSharedStyles.IsSelectorElement(documentElement)) { var selectorParts = BuilderSharedStyles.GetSelectorParts(documentElement); // Register right-click events for context menu actions. m_ContextMenuManipulator.RegisterCallbacksOnTarget(explorerItem); // Register drag-and-drop events for reparenting. m_ExplorerDragger.RegisterCallbacksOnTarget(explorerItem); 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.name = "unity-builder-tree-class-pill"; 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); } } // Allow reparenting. explorerItem.SetProperty(BuilderConstants.ExplorerItemElementLinkVEPropertyName, documentElement); // Check if selector element is inside current open StyleSheets if (documentElement.IsParentSelector()) { row.AddToClassList(BuilderConstants.ExplorerItemHiddenClassName); } return; } if (BuilderSharedStyles.IsDocumentElement(documentElement)) { var uxmlAsset = documentElement.GetVisualTreeAsset(); var ssLabel = new Label(BuilderAssetUtilities.GetVisualTreeAssetAssetName(uxmlAsset, hasUnsavedChanges)); ssLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); ssLabel.AddToClassList("unity-debugger-tree-item-type"); row.AddToClassList(BuilderConstants.ExplorerHeaderRowClassName); labelCont.Add(ssLabel); // Allow reparenting. explorerItem.SetProperty(BuilderConstants.ExplorerItemElementLinkVEPropertyName, documentElement); // Register right-click events for context menu actions. m_ContextMenuManipulator.RegisterCallbacksOnTarget(explorerItem); return; } // Check if element is inside current document. if (!documentElement.IsPartOfActiveVisualTreeAsset(m_PaneWindow.document)) { row.AddToClassList(BuilderConstants.ExplorerItemHiddenClassName); } // Register drag-and-drop events for reparenting. m_ExplorerDragger.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 = BuilderConstants.UssSelectorNameSymbol + 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(BuilderConstants.UssSelectorClassNameSymbol + ussClass); classLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); classLabel.AddToClassList(BuilderConstants.ElementClassNameClassName); classLabel.AddToClassList("unity-debugger-tree-item-classlist-label"); classLabelCont.Add(classLabel); } } // Add stylesheets. if (elementInfoVisibilityState.HasFlag(BuilderExplorer.BuilderElementInfoVisibilityState.StyleSheets)) { var vea = documentElement.GetVisualElementAsset(); if (vea != null) { foreach (var ussPath in vea.GetStyleSheetPaths()) { if (string.IsNullOrEmpty(ussPath)) { continue; } var classLabelCont = new VisualElement(); classLabelCont.AddToClassList(BuilderConstants.ExplorerItemLabelContClassName); explorerItem.Add(classLabelCont); var classLabel = new Label(Path.GetFileName(ussPath)); classLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); classLabel.AddToClassList(BuilderConstants.ElementAttachedStyleSheetClassName); classLabel.AddToClassList("unity-debugger-tree-item-classlist-label"); classLabelCont.Add(classLabel); } } else { for (int i = 0; i < documentElement.styleSheets.count; ++i) { var attachedStyleSheet = documentElement.styleSheets[i]; if (attachedStyleSheet == null) { continue; } var classLabelCont = new VisualElement(); classLabelCont.AddToClassList(BuilderConstants.ExplorerItemLabelContClassName); explorerItem.Add(classLabelCont); var classLabel = new Label(attachedStyleSheet.name + BuilderConstants.UssExtension); classLabel.AddToClassList(BuilderConstants.ExplorerItemLabelClassName); classLabel.AddToClassList(BuilderConstants.ElementAttachedStyleSheetClassName); 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; Texture2D itemIcon; 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); itemIcon = BuilderLibraryContent.GetUXMLAssetIcon(path); } else { itemIcon = BuilderLibraryContent.GetTypeLibraryIcon(documentElement.GetType()); } // Element icon. var icon = new VisualElement(); icon.AddToClassList(BuilderConstants.ExplorerItemIconClassName); var styleBackgroundImage = icon.style.backgroundImage; styleBackgroundImage.value = new Background { texture = itemIcon }; icon.style.backgroundImage = styleBackgroundImage; labelCont.Insert(0, icon); // Register right-click events for context menu actions. m_ContextMenuManipulator.RegisterCallbacksOnTarget(explorerItem); }
public ElementHierarchyView( BuilderPaneWindow paneWindow, VisualElement documentRootElement, BuilderSelection selection, BuilderClassDragger classDragger, BuilderExplorerDragger explorerDragger, BuilderElementContextMenu contextMenuManipulator, Action <List <VisualElement> > selectElementCallback, HighlightOverlayPainter highlightOverlayPainter) { m_PaneWindow = paneWindow; m_DocumentRootElement = documentRootElement; m_Selection = selection; m_ClassDragger = classDragger; m_ExplorerDragger = explorerDragger; m_ContextMenuManipulator = contextMenuManipulator; this.focusable = true; m_SelectElementCallback = selectElementCallback; hierarchyHasChanged = true; hasUnsavedChanges = false; 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) { m_PaneWindow.primarySelection.ClearSelection(null); } }); m_TreeViewHoverOverlay = highlightOverlayPainter; m_Container = new VisualElement(); m_Container.name = "explorer-container"; m_Container.style.flexGrow = 1; m_ClassDragger.builderHierarchyRoot = m_Container; m_ExplorerDragger.builderHierarchyRoot = m_Container; Add(m_Container); m_ClassPillTemplate = BuilderPackageUtilities.LoadAssetAtPath <VisualTreeAsset>( BuilderConstants.UIBuilderPackagePath + "/BuilderClassPill.uxml"); // Create TreeView. m_TreeRootItems = new List <TreeViewItem>(); m_TreeView = new TreeView(20, MakeItem, FillItem); m_TreeView.SetRootItems(m_TreeRootItems); m_TreeViewController = m_TreeView.viewController as DefaultTreeViewController <VisualElement>; m_TreeView.selectionType = SelectionType.Multiple; m_TreeView.viewDataKey = "unity-builder-explorer-tree"; m_TreeView.style.flexGrow = 1; m_TreeView.onSelectedIndicesChange += OnSelectionChange; m_TreeView.RegisterCallback <MouseDownEvent>(OnLeakedMouseClick); m_Container.Add(m_TreeView); m_ContextMenuManipulator.RegisterCallbacksOnTarget(m_Container); }