public static VisualElement CreateAbsoluteIsland(BuilderPaneWindow paneWindow, VisualElement documentRootElement, Vector2 localMousePosition) { var vta = paneWindow.document.visualTreeAsset; var selection = paneWindow.primarySelection; // Create absolute island container. var absoluteIslandContainer = new VisualElement(); absoluteIslandContainer.name = "unity-absolute-island"; documentRootElement.Add(absoluteIslandContainer); BuilderAssetUtilities.AddElementToAsset(paneWindow.document, absoluteIslandContainer); bool isTop = localMousePosition.y < documentRootElement.resolvedStyle.height / 2; bool isBottom = !isTop; bool isLeft = localMousePosition.x < documentRootElement.resolvedStyle.width / 2; bool isRight = !isLeft; // Set Absolute position. BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "position", Position.Absolute); if (isTop && isLeft) { var left = localMousePosition.x; var top = localMousePosition.y; BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "left", left); BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "top", top); } else if (isTop && isRight) { var right = documentRootElement.resolvedStyle.width - localMousePosition.x; var top = localMousePosition.y; BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "right", right); BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "top", top); } else if (isBottom && isLeft) { var left = localMousePosition.x; var bottom = documentRootElement.resolvedStyle.height - localMousePosition.y; BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "left", left); BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "bottom", bottom); } else if (isBottom && isRight) { var right = documentRootElement.resolvedStyle.width - localMousePosition.x; var bottom = documentRootElement.resolvedStyle.height - localMousePosition.y; BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "right", right); BuilderStyleUtilities.SetInlineStyleValue(vta, absoluteIslandContainer, "bottom", bottom); } // Need to explicitly update inline styles from asset. selection.NotifyOfHierarchyChange(null, absoluteIslandContainer, BuilderHierarchyChangeType.InlineStyle | BuilderHierarchyChangeType.FullRefresh); return(absoluteIslandContainer); }
protected void SetTargetAsset(ScriptableObject targetAsset, bool hasUnsavedChanges) { if (pane == null) { return; } m_TargetAsset = targetAsset; pane.subTitle = BuilderAssetUtilities.GetAssetName(targetAsset, previewAssetExtension, hasUnsavedChanges); m_OpenTargetAssetSourceButton.style.display = isTargetAssetAvailableOnDisk ? DisplayStyle.Flex : DisplayStyle.None; }
bool WriteUXMLToFile(string uxmlPath, string uxmlText) { // Make sure the folders exist. var uxmlFolder = Path.GetDirectoryName(uxmlPath); if (!Directory.Exists(uxmlFolder)) { Directory.CreateDirectory(uxmlFolder); } return(BuilderAssetUtilities.WriteTextFileToDisk(uxmlPath, uxmlText)); }
void AddStyleClass(string className) { PreAddStyleClass(className); // Update VisualTreeAsset. BuilderAssetUtilities.AddStyleClassToElementInAsset( m_PaneWindow.document, currentVisualElement, className); // We actually want to get the notification back and refresh ourselves. m_Selection.NotifyOfHierarchyChange(null); m_Selection.NotifyOfStylingChange(null); }
void PerformActionForStyleSheet(VisualElement destination, DestinationPane pane, int index = -1) { if (destination == null) { destination = BuilderSharedStyles.GetSelectorContainerElement(selection.documentRootElement); } BuilderAssetUtilities.ReorderStyleSheetsInAsset(paneWindow.document, destination); selection.NotifyOfHierarchyChange(); selection.NotifyOfStylingChange(null); selection.ForceReselection(); }
public static void RemoveUSSFromAsset(BuilderPaneWindow paneWindow, int selectedStyleSheetIndex) { // We need to save all files before we remove the USS. // If we don't do this, changes in the removed USS will be lost. var shouldContinue = s_CheckForUnsavedChanges(paneWindow); if (!shouldContinue) { return; } BuilderAssetUtilities.RemoveStyleSheetFromAsset(paneWindow.document, selectedStyleSheetIndex); paneWindow.OnEnableAfterAllSerialization(); }
protected override void PerformAction(VisualElement destination, DestinationPane pane, int index = -1) { m_DragPreviewElement.RemoveFromClassList(s_DragPreviewElementClassName); destination.RemoveMinSizeSpecialElement(); // We already have the correct index from the preview element that is // already inserted in the hierarchy. The index we get from the arguments // is actually incorrect (off by one) because it will count the // preview element. index = m_DragPreviewLastParent.IndexOf(m_DragPreviewElement); // We should have an item reference here if the OnDragStart() worked. var item = m_LibraryItem; var itemVTA = item.SourceAsset; if (!paneWindow.document.WillCauseCircularDependency(itemVTA)) { BuilderDialogsUtility.DisplayDialog(BuilderConstants.InvalidWouldCauseCircularDependencyMessage, BuilderConstants.InvalidWouldCauseCircularDependencyMessageDescription, null); return; } if (item.MakeElementAssetCallback == null) { BuilderAssetUtilities.AddElementToAsset( paneWindow.document, m_DragPreviewElement, index); } else { BuilderAssetUtilities.AddElementToAsset( paneWindow.document, m_DragPreviewElement, item.MakeElementAssetCallback, index); } selection.NotifyOfHierarchyChange(null); selection.NotifyOfStylingChange(null); selection.Select(null, m_DragPreviewElement); // Commit to the preview element as the final element. // This will stop the ResetDragPreviewElement() from calling // RemoveFromHierarchy() on it. m_DragPreviewElement = null; // If we dragged into the Viewport, focus the Viewport. if (pane == DestinationPane.Viewport) { Viewport.pane.Focus(); } }
public static void SetValue(this StyleSheet styleSheet, StyleValueHandle valueHandle, Object value) { // Undo/Redo Undo.RegisterCompleteObjectUndo(styleSheet, BuilderConstants.ChangeUIStyleValueUndoMessage); if (valueHandle.valueType == StyleValueType.ResourcePath) { var resourcesPath = BuilderAssetUtilities.GetResourcesPathForAsset(value); styleSheet.strings[valueHandle.valueIndex] = resourcesPath; } else { styleSheet.assets[valueHandle.valueIndex] = value; } }
bool DeleteElementFromVisualTreeAsset(VisualElement element) { var vea = element.GetVisualElementAsset(); if (vea == null) { return(false); } BuilderAssetUtilities.DeleteElementFromAsset(m_PaneWindow.document, element); element.RemoveFromHierarchy(); m_Selection.NotifyOfHierarchyChange(); return(true); }
void PasteUXML(string copyBuffer) { var importer = new BuilderVisualTreeAssetImporter(); // Cannot be cached because the StyleBuilder never gets reset. importer.ImportXmlFromString(copyBuffer, out var pasteVta); /* If the current parent element is linked to a VisualTreeAsset, it could mean * that our parent is the TemplateContainer belonging to our parent document and the * current open document is a sub-document opened in-place. In such a case, we don't * want to use our parent's VisualElementAsset, as that belongs to our parent document. * So instead, we just use no parent, indicating that we are adding this new element * to the root of our document. */ VisualElementAsset parent = null; if (!m_Selection.isEmpty) { var selectionParent = m_Selection.selection.First().parent; parent = selectionParent?.GetVisualElementAsset(); if (selectionParent?.GetVisualTreeAsset() == m_PaneWindow.document.visualTreeAsset) { parent = null; } m_Selection.ClearSelection(null); } // Select all pasted elements. foreach (var templateAsset in pasteVta.templateAssets) { if (pasteVta.IsRootElement(templateAsset)) { templateAsset.Select(); } } foreach (var vea in pasteVta.visualElementAssets) { if (pasteVta.IsRootElement(vea)) { vea.Select(); } } BuilderAssetUtilities.TransferAssetToAsset(m_PaneWindow.document, parent, pasteVta); m_PaneWindow.document.AddStyleSheetsToAllRootElements(); ScriptableObject.DestroyImmediate(pasteVta); }
public void AddToSelection(IBuilderSelectionNotifier source, VisualElement ve, bool undo = true) { if (ve == null) { return; } m_Selection.Add(ve); if (undo) { BuilderAssetUtilities.AddElementToSelectionInAsset(m_PaneWindow.document, ve); } NotifyOfSelectionChange(source); }
void PasteUSS(string copyBuffer) { var pasteStyleSheet = StyleSheetUtilities.CreateInstance(); var importer = new BuilderStyleSheetImporter(); // Cannot be cached because the StyleBuilder never gets reset. importer.Import(pasteStyleSheet, copyBuffer); BuilderAssetUtilities.TransferAssetToAsset(m_PaneWindow.document, pasteStyleSheet); m_Selection.ClearSelection(null); var scs = m_PaneWindow.document.mainStyleSheet.complexSelectors.Last(); BuilderAssetUtilities.AddStyleComplexSelectorToSelection(m_PaneWindow.document, scs); ScriptableObject.DestroyImmediate(pasteStyleSheet); }
bool DeleteElementFromVisualTreeAsset(VisualElement element) { var vea = element.GetVisualElementAsset(); if (vea == null) { return(false); } #if UNITY_2019_4 // Before 2020.1, the only way to attach a StyleSheet to a UXML document was via a <Style> // tag as a child of an element tag. This meant that if there were no elements in the document, // there cannot be any StyleSheets attached to it. Therefore, we need to warn the user when // deleting the last element in the document that they will lose the list of attached StyleSheets // as well. This is something that can be undone via undo so it's not terrible if they say "Yes" // accidentally. // // 2020.1 adds support for the global <Style> tag so this limitation is lifted. However, the // UI Builder does not yet support the global <Style> tag. Plus, even when support to the // UI Builder is added, we still need to maintain support for 2019.3 via this logic. if (m_PaneWindow.document.firstStyleSheet != null && m_PaneWindow.document.visualTreeAsset.WillBeEmptyIfRemovingOne(vea)) { var continueDeletion = BuilderDialogsUtility.DisplayDialog( BuilderConstants.DeleteLastElementDialogTitle, BuilderConstants.DeleteLastElementDialogMessage, "Yes", "Cancel"); if (!continueDeletion) { return(false); } BuilderAssetUtilities.DeleteElementFromAsset(m_PaneWindow.document, element); m_PaneWindow.OnEnableAfterAllSerialization(); } else #endif { BuilderAssetUtilities.DeleteElementFromAsset(m_PaneWindow.document, element); element.RemoveFromHierarchy(); m_Selection.NotifyOfHierarchyChange(); } return(true); }
internal static StyleValueHandle AddValue(this StyleSheet styleSheet, StyleProperty property, Object value) { // Undo/Redo Undo.RegisterCompleteObjectUndo(styleSheet, BuilderConstants.ChangeUIStyleValueUndoMessage); // Determine real asset type. var resourcePath = BuilderAssetUtilities.GetResourcesPathForAsset(value); var styleValueType = string.IsNullOrEmpty(resourcePath) ? StyleValueType.AssetReference : StyleValueType.ResourcePath; // Add value data to data array. var index = string.IsNullOrEmpty(resourcePath) ? styleSheet.AddValueToArray(value) : styleSheet.AddValueToArray(resourcePath); // Add value object to property. var newValue = styleSheet.AddValueHandle(property, index, styleValueType); return(newValue); }
protected void AddItemToTheDocument(BuilderLibraryTreeItem item) { // If this is the uxml file entry of the currently open file, don't allow // the user to instantiate it (infinite recursion) or re-open it. var listOfOpenDocuments = m_PaneWindow.document.openUXMLFiles; bool isCurrentDocumentOpen = listOfOpenDocuments.Any(doc => doc.uxmlFileName == item.name); if (isCurrentDocumentOpen) { return; } var newElement = item.makeVisualElementCallback?.Invoke(); if (newElement == null) { return; } var activeVTARootElement = m_DocumentRootElement.Query().Where(e => e.GetVisualTreeAsset() == m_PaneWindow.document.visualTreeAsset).First(); if (activeVTARootElement == null) { Debug.LogError("UI Builder has a bug. Could not find document root element for currently active open UXML document."); return; } activeVTARootElement.Add(newElement); if (item.makeElementAssetCallback == null) { BuilderAssetUtilities.AddElementToAsset(m_PaneWindow.document, newElement); } else { BuilderAssetUtilities.AddElementToAsset( m_PaneWindow.document, newElement, item.makeElementAssetCallback); } // TODO: ListView bug. Does not refresh selection pseudo states after a // call to Refresh(). m_Selection.NotifyOfHierarchyChange(); schedule.Execute(() => { m_Selection.Select(null, newElement); }).ExecuteLater(200); }
protected override void PerformAction(VisualElement destination, DestinationPane pane, Vector2 localMousePosition, int index = -1) { if (pane == DestinationPane.Viewport && !IsPickedElementValid(m_TargetElementToReparent)) { return; } base.PerformAction(destination, pane, localMousePosition, index); m_TargetElementToReparent.RemoveFromClassList(s_DragPreviewElementClassName); // Remove temporary min-size element. destination.RemoveMinSizeSpecialElement(); var newParent = destination; // We already have the correct index from the preview element that is // already inserted in the hierarchy. The index we get from the arguments // is actually incorrect (off by one) because it will count the // preview element. index = m_DragPreviewLastParent.IndexOf(m_TargetElementToReparent); bool undo = true; foreach (var elementToReparent in m_ElementsToReparent) { var element = elementToReparent.element; if (newParent == element || newParent.HasAncestor(element)) { continue; } BuilderAssetUtilities.ReparentElementInAsset( paneWindow.document, element, newParent, index, undo); undo = false; } BuilderAssetUtilities.SortElementsByTheirVisualElementInAsset(newParent); selection.NotifyOfHierarchyChange(null); selection.NotifyOfStylingChange(null); selection.ForceReselection(null); }
void OnStyleClassDelete(EventBase evt) { var target = evt.target as VisualElement; var className = target.userData as string; // Actually remove the style class from the element in the canvas. currentVisualElement.RemoveFromClassList(className); // Update VisualTreeAsset. BuilderAssetUtilities.RemoveStyleClassFromElementInAsset( m_PaneWindow.document, currentVisualElement, className); // We actually want to get the notification back and refresh ourselves. m_Selection.NotifyOfHierarchyChange(null); m_Selection.NotifyOfStylingChange(null); evt.StopPropagation(); }
protected override void PerformAction(VisualElement destination, DestinationPane pane, int index = -1) { if (BuilderSharedStyles.IsDocumentElement(destination)) { return; } var className = m_ClassNameBeingDragged.TrimStart('.'); destination.AddToClassList(className); // Update VisualTreeAsset. BuilderAssetUtilities.AddStyleClassToElementInAsset( paneWindow.document, destination, className); selection.NotifyOfHierarchyChange(null); selection.NotifyOfStylingChange(null); }
public void ClearSelection(IBuilderSelectionNotifier source, bool undo = true) { if (isEmpty) { return; } if (undo) { foreach (var sel in m_Selection) { BuilderAssetUtilities.RemoveElementFromSelectionInAsset(m_PaneWindow.document, sel); } } m_Selection.Clear(); NotifyOfSelectionChange(source); }
void PasteUXML(string copyBuffer) { VisualTreeAsset pasteVta = null; var importer = new BuilderVisualTreeAssetImporter(); // Cannot be cached because the StyleBuilder never gets reset. importer.ImportXmlFromString(copyBuffer, out pasteVta); VisualElementAsset parent = null; if (!m_Selection.isEmpty) { parent = m_Selection.selection.First().parent?.GetVisualElementAsset(); } BuilderAssetUtilities.TransferAssetToAsset(m_PaneWindow.document, parent, pasteVta); m_PaneWindow.document.AddStyleSheetToAllRootElements(); ScriptableObject.DestroyImmediate(pasteVta); }
protected override void PerformAction(VisualElement destination, DestinationPane pane, int index = -1) { m_TargetElementToReparent.RemoveFromClassList(s_DragPreviewElementClassName); // Remove temporary min-size element. destination.RemoveMinSizeSpecialElement(); var elementToReparent = m_TargetElementToReparent; var newParent = destination; // We already have the correct index from the preview element that is // already inserted in the hierarchy. The index we get from the arguments // is actually incorrect (off by one) because it will count the // preview element. index = m_DragPreviewLastParent.IndexOf(m_TargetElementToReparent); BuilderAssetUtilities.ReparentElementInAsset( paneWindow.document, elementToReparent, newParent, index); selection.NotifyOfHierarchyChange(null); }
public bool LoadDocument(VisualTreeAsset visualTreeAsset, bool unloadAllSubdocuments = true, bool assetModifiedExternally = false, string assetPath = null) { if (!BuilderAssetUtilities.ValidateAsset(visualTreeAsset, assetPath)) { return(false); } if (!document.CheckForUnsavedChanges(assetModifiedExternally)) { return(false); } if (unloadAllSubdocuments) { document.GoToRootDocument(m_Viewport.documentRootElement, m_PaneWindow); } LoadDocumentInternal(visualTreeAsset); return(true); }
protected void AddItemToTheDocument(BuilderLibraryTreeItem item) { // If this is the uxml file entry of the currently open file, don't allow // the user to instantiate it (infinite recursion) or re-open it. var listOfOpenDocuments = m_PaneWindow.document.openUXMLFiles; bool isCurrentDocumentOpen = listOfOpenDocuments.Any(doc => doc.uxmlFileName == item.Name); if (isCurrentDocumentOpen) { return; } var newElement = item.MakeVisualElementCallback?.Invoke(); if (newElement == null) { return; } m_DocumentElement.Add(newElement); if (item.MakeElementAssetCallback == null) { BuilderAssetUtilities.AddElementToAsset(m_PaneWindow.document, newElement); } else { BuilderAssetUtilities.AddElementToAsset( m_PaneWindow.document, newElement, item.MakeElementAssetCallback); } // TODO: ListView bug. Does not refresh selection pseudo states after a // call to Refresh(). m_Selection.NotifyOfHierarchyChange(); schedule.Execute(() => { m_Selection.Select(null, newElement); }).ExecuteLater(200); }
public void Select(IBuilderSelectionNotifier source, VisualElement ve) { if (ve == null) { return; } foreach (var sel in m_Selection) { if (sel == null) { continue; } BuilderAssetUtilities.RemoveElementFromSelectionInAsset(m_PaneWindow.document, sel); } m_Selection.Clear(); m_Selection.Add(ve); BuilderAssetUtilities.AddElementToSelectionInAsset(m_PaneWindow.document, ve); NotifyOfSelectionChange(source); }
public void UnpackTemplateContainer(VisualElement templateContainer, bool unpackCompletely = false) { if (templateContainer == null) { Debug.LogError("Template to unpack is null"); return; } var elementsToUnpack = new List <VisualElement>(); var rootVEA = templateContainer.GetVisualElementAsset(); var isRootElement = true; VisualElementAsset rootUnpackedVEA = null; elementsToUnpack.Add(templateContainer); while (elementsToUnpack.Count > 0) { var elementToUnpack = elementsToUnpack[0]; var unpackedVE = new VisualElement(); var templateContainerParent = elementToUnpack.parent; var templateContainerIndex = templateContainerParent.IndexOf(elementToUnpack); // Create new unpacked element and add it in the hierarchy templateContainerParent.Add(unpackedVE); BuilderAssetUtilities.AddElementToAsset(m_PaneWindow.document, unpackedVE, templateContainerIndex + 1); var linkedInstancedVTA = elementToUnpack.GetProperty(BuilderConstants.ElementLinkedInstancedVisualTreeAssetVEPropertyName) as VisualTreeAsset; var linkedTA = elementToUnpack.GetVisualElementAsset() as TemplateAsset; var linkedVTACopy = linkedInstancedVTA.DeepCopy(); var unpackedVEA = unpackedVE.GetVisualElementAsset(); var templateContainerVEA = elementToUnpack.GetVisualElementAsset(); var attributeOverrides = linkedTA.attributeOverrides; var attributes = elementToUnpack.GetOverriddenAttributes(); foreach (var attribute in attributes) { unpackedVEA.SetAttributeValue(attribute.Key, attribute.Value); } if (isRootElement) { rootUnpackedVEA = unpackedVEA; } // Apply attribute overrides to elements in the unpacked element BuilderAssetUtilities.ApplyAttributeOverridesToTreeAsset(attributeOverrides, linkedVTACopy); // Move attribute overrides to new template containers BuilderAssetUtilities.CopyAttributeOverridesToChildTemplateAssets(attributeOverrides, linkedVTACopy); // Apply stylesheets to new element + inline rules BuilderAssetUtilities.AddStyleSheetsFromTreeAsset(unpackedVEA, linkedInstancedVTA); unpackedVEA.ruleIndex = templateContainerVEA.ruleIndex; BuilderAssetUtilities.TransferAssetToAsset(m_PaneWindow.document, unpackedVEA, linkedVTACopy, false); elementsToUnpack.Remove(elementToUnpack); if (elementToUnpack != templateContainer) { BuilderAssetUtilities.DeleteElementFromAsset(m_PaneWindow.document, elementToUnpack, false); elementToUnpack.RemoveFromHierarchy(); } if (unpackCompletely && elementsToUnpack.Count == 0) { VisualElement tree = new VisualElement(); m_PaneWindow.document.activeOpenUXMLFile.visualTreeAsset.LinkedCloneTree(tree); var newElement = tree.Query <VisualElement>().Where(x => x.GetVisualElementAsset() == rootUnpackedVEA).First(); var newTemplates = newElement.Query <TemplateContainer>().Where(x => x.GetVisualElementAsset() != null).ToList(); elementsToUnpack.AddRange(newTemplates); isRootElement = false; } } m_Selection.NotifyOfHierarchyChange(); m_PaneWindow.OnEnableAfterAllSerialization(); // Keep hierarchy tree state in the new unpacked element var hierarchy = Builder.ActiveWindow.hierarchy; hierarchy.elementHierarchyView.CopyTreeViewItemStates(rootVEA, rootUnpackedVEA); // Delete old template element BuilderAssetUtilities.DeleteElementFromAsset(m_PaneWindow.document, templateContainer, false); templateContainer.RemoveFromHierarchy(); m_Selection.ClearSelection(null); rootUnpackedVEA.Select(); m_Selection.NotifyOfHierarchyChange(); m_PaneWindow.OnEnableAfterAllSerialization(); }
public void CreateTemplateFromHierarchy(VisualElement ve, VisualTreeAsset vta, string path = "") { var veas = new List <VisualElementAsset>(); var vea = ve.GetVisualElementAsset(); veas.Add(vea); if (string.IsNullOrEmpty(path)) { path = BuilderDialogsUtility.DisplaySaveFileDialog("Save UXML", null, ve.name, "uxml"); if (string.IsNullOrEmpty(path)) { // Save dialog cancelled return; } } if (path == m_PaneWindow.document.activeOpenUXMLFile.uxmlPath) { // Path is the same as the active open uxml file. Abort! BuilderDialogsUtility.DisplayDialog( BuilderConstants.InvalidCreateTemplatePathTitle, BuilderConstants.InvalidCreateTemplatePathMessage, BuilderConstants.DialogOkOption); return; } var uxml = VisualTreeAssetToUXML.GenerateUXML(vta, null, veas); if (!m_PaneWindow.document.SaveNewTemplateFileFromHierarchy(path, uxml)) { // New template wasn't saved return; } var parent = ve.parent; var parentVEA = parent.GetVisualElementAsset(); var index = parent.IndexOf(ve); // Delete old element BuilderAssetUtilities.DeleteElementFromAsset(m_PaneWindow.document, ve); ve.RemoveFromHierarchy(); // Replace with new template var newTemplateVTA = EditorGUIUtility.Load(path) as VisualTreeAsset; var newTemplateContainer = newTemplateVTA.CloneTree(); newTemplateContainer.SetProperty(BuilderConstants.LibraryItemLinkedTemplateContainerPathVEPropertyName, path); newTemplateContainer.name = newTemplateVTA.name; parent.Insert(index, newTemplateContainer); BuilderAssetUtilities.AddElementToAsset(m_PaneWindow.document, newTemplateContainer, (inVta, inParent, ve) => { var vea = inVta.AddTemplateInstance(inParent, path) as VisualElementAsset; vea.AddProperty("name", newTemplateVTA.name); ve.SetProperty(BuilderConstants.ElementLinkedInstancedVisualTreeAssetVEPropertyName, newTemplateVTA); return(vea); }, index); m_Selection.Select(null, newTemplateContainer); // Refresh m_Selection.NotifyOfHierarchyChange(); m_PaneWindow.OnEnableAfterAllSerialization(); }
void ExtractLocalStylesToNewClass(string className) { // Get StyleSheet. var mainStyleSheet = m_PaneWindow.document.activeStyleSheet; if (mainStyleSheet == null) { var option = BuilderDialogsUtility.DisplayDialogComplex( BuilderConstants.ExtractInlineStylesNoUSSDialogTitle, BuilderConstants.ExtractInlineStylesNoUSSDialogMessage, BuilderConstants.ExtractInlineStylesNoUSSDialogNewUSSOption, BuilderConstants.ExtractInlineStylesNoUSSDialogExistingUSSOption, BuilderConstants.DialogCancelOption); switch (option) { // New case 0: if (!BuilderStyleSheetsUtilities.CreateNewUSSAsset(m_PaneWindow)) { return; } break; // Existing case 1: if (!BuilderStyleSheetsUtilities.AddExistingUSSToAsset(m_PaneWindow)) { return; } break; // Cancel case 2: return; } mainStyleSheet = m_PaneWindow.document.activeStyleSheet; } PreAddStyleClass(className); // Create new selector in main StyleSheet. var selectorString = BuilderConstants.UssSelectorClassNameSymbol + className; var selectorsRootElement = BuilderSharedStyles.GetSelectorContainerElement(m_Selection.documentElement); var newSelector = BuilderSharedStyles.CreateNewSelector(selectorsRootElement, mainStyleSheet, selectorString); // Transfer all properties from inline styles rule to new selector. mainStyleSheet.TransferRulePropertiesToSelector( newSelector, m_Inspector.styleSheet, m_Inspector.currentRule); // Update VisualTreeAsset. BuilderAssetUtilities.AddStyleClassToElementInAsset( m_PaneWindow.document, currentVisualElement, className); // Overwrite Undo Message. Undo.RegisterCompleteObjectUndo( new Object[] { m_PaneWindow.document.visualTreeAsset, mainStyleSheet }, BuilderConstants.CreateStyleClassUndoMessage); // We actually want to get the notification back and refresh ourselves. m_Selection.NotifyOfStylingChange(null); m_Selection.NotifyOfHierarchyChange(null, currentVisualElement); }
protected override void PerformAction(VisualElement destination, DestinationPane pane, Vector2 localMousePosition, int index = -1) { // We should have an item reference here if the OnDragStart() worked. var item = m_LibraryItem; var itemVTA = item.sourceAsset; if (paneWindow.document.WillCauseCircularDependency(itemVTA)) { BuilderDialogsUtility.DisplayDialog(BuilderConstants.InvalidWouldCauseCircularDependencyMessage, BuilderConstants.InvalidWouldCauseCircularDependencyMessageDescription, BuilderConstants.DialogOkOption); return; } if (item.makeElementAssetCallback != null && m_DragPreviewElement is TemplateContainer tempContainer) { if (!BuilderAssetUtilities.ValidateAsset(item.sourceAsset, item.sourceAssetPath)) { return; } } // Determine if it applies and use Absolute Island insertion. if (BuilderProjectSettings.enableAbsolutePositionPlacement && pane == DestinationPane.Viewport && m_DragPreviewLastParent == documentRootElement && index < 0) { m_DragPreviewLastParent = BuilderPlacementUtilities.CreateAbsoluteIsland(paneWindow, documentRootElement, localMousePosition); } // Add VisualElement to Canvas. m_DragPreviewElement.RemoveFromClassList(s_DragPreviewElementClassName); if (index < 0) { m_DragPreviewLastParent.Add(m_DragPreviewElement); } else { m_DragPreviewLastParent.Insert(index, m_DragPreviewElement); } // Create equivalent VisualElementAsset. if (item.makeElementAssetCallback == null) { BuilderAssetUtilities.AddElementToAsset( paneWindow.document, m_DragPreviewElement, index); } else { BuilderAssetUtilities.AddElementToAsset( paneWindow.document, m_DragPreviewElement, item.makeElementAssetCallback, index); } selection.NotifyOfHierarchyChange(null); selection.NotifyOfStylingChange(null); selection.Select(null, m_DragPreviewElement); // Commit to the preview element as the final element. // This will stop the ResetDragPreviewElement() from calling // RemoveFromHierarchy() on it. m_DragPreviewElement = null; // If we dragged into the Viewport, focus the Viewport. if (pane == DestinationPane.Viewport) { viewport.pane.Focus(); } }
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 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); }