internal static string GenerateUSS(this StyleSheet styleSheet) { string result = null; try { result = StyleSheetToUss.ToUssString(styleSheet); } catch (Exception ex) { if (!styleSheet.name.Contains(BuilderConstants.InvalidUXMLOrUSSAssetNameSuffix)) { var message = string.Format(BuilderConstants.InvalidUSSDialogMessage, styleSheet.name); BuilderDialogsUtility.DisplayDialog(BuilderConstants.InvalidUSSDialogTitle, message); styleSheet.name = styleSheet.name + BuilderConstants.InvalidUXMLOrUSSAssetNameSuffix; } else { var name = styleSheet.name.Replace(BuilderConstants.InvalidUXMLOrUSSAssetNameSuffix, string.Empty); var message = string.Format(BuilderConstants.InvalidUSSDialogMessage, name); Builder.ShowWarning(message); } Debug.LogError(ex.Message + "\n" + ex.StackTrace); } return(result); }
internal static string GenerateUXML(this VisualTreeAsset vta, string vtaPath, bool writingToFile = false) { string result = null; try { result = VisualTreeAssetToUXML.GenerateUXML(vta, vtaPath, writingToFile); } catch (Exception ex) { if (!vta.name.Contains(BuilderConstants.InvalidUXMLOrUSSAssetNameSuffix)) { var message = string.Format(BuilderConstants.InvalidUXMLDialogMessage, vta.name); BuilderDialogsUtility.DisplayDialog(BuilderConstants.InvalidUXMLDialogTitle, message); vta.name = vta.name + BuilderConstants.InvalidUXMLOrUSSAssetNameSuffix; } else { var name = vta.name.Replace(BuilderConstants.InvalidUXMLOrUSSAssetNameSuffix, string.Empty); var message = string.Format(BuilderConstants.InvalidUXMLDialogMessage, name); Builder.ShowWarning(message); } Debug.LogError(ex.Message + "\n" + ex.StackTrace); } return(result); }
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, null); return; } destination.RemoveMinSizeSpecialElement(); // 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(); } }
internal bool SaveNewTemplateFileFromHierarchy(string newTemplatePath, string uxml) { var isReplacingFile = File.Exists(newTemplatePath); bool isReplacingFileInHierarchy = false; if (isReplacingFile) { var replacedVTA = EditorGUIUtility.Load(newTemplatePath) as VisualTreeAsset; isReplacingFileInHierarchy = replacedVTA.TemplateExists(m_VisualTreeAsset); if (isReplacingFileInHierarchy && hasUnsavedChanges) { // If we are replacing an element in the hierarchy and there is unsaved changes, // we need to save to make sure we don't lose any elements var saveUnsavedChanges = BuilderDialogsUtility.DisplayDialog( BuilderConstants.SaveDialogSaveChangesPromptTitle, BuilderConstants.SaveDialogReplaceWithNewTemplateMessage, BuilderConstants.DialogSaveActionOption, BuilderConstants.DialogCancelOption); if (saveUnsavedChanges) { var wasDocumentSaved = SaveUnsavedChanges(); if (!wasDocumentSaved) { // Save failed Debug.LogError("Saving the current template failed. New template will not be created."); return(false); } } else { // Save cancelled return(false); } } } if (isReplacingFileInHierarchy) { // This is necessary to make sure we don't show the external changes popup // since we are creating a new template m_DocumentBeingSavedExplicitly = true; } File.WriteAllText(newTemplatePath, uxml); AssetDatabase.Refresh(); if (isReplacingFileInHierarchy) { m_DocumentBeingSavedExplicitly = false; } 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; } if (m_PaneWindow.document.WillCauseCircularDependency(item.sourceAsset)) { BuilderDialogsUtility.DisplayDialog(BuilderConstants.InvalidWouldCauseCircularDependencyMessage, BuilderConstants.InvalidWouldCauseCircularDependencyMessageDescription, null); return; } var newElement = item.makeVisualElementCallback?.Invoke(); if (newElement == null) { return; } if (item.makeElementAssetCallback != null && newElement is TemplateContainer tempContainer) { if (!BuilderAssetUtilities.ValidateAsset(item.sourceAsset, item.sourceAssetPath)) { 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); } m_Selection.NotifyOfHierarchyChange(); m_Selection.Select(null, newElement); }
static public bool WriteTextFileToDisk(string path, string content) { bool success = FileUtil.WriteTextFileToDisk(path, content, out string message); if (!success) { Debug.LogError(message); BuilderDialogsUtility.DisplayDialog("Save - " + path, message, "Ok"); } return(success); }
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 bool CheckForUnsavedChanges(bool assetModifiedExternally = false) { if (!hasUnsavedChanges) { return(true); } if (assetModifiedExternally) { // TODO: Nothing can be done here yet, other than telling the user // what just happened. Adding the ability to save unsaved changes // after a file has been modified externally will require some // major changes to the document flow. var promptTitle = string.Format(BuilderConstants.SaveDialogExternalChangesPromptTitle, m_Document.uxmlPath); BuilderDialogsUtility.DisplayDialog( promptTitle, BuilderConstants.SaveDialogExternalChangesPromptMessage); return(true); } else { var option = BuilderDialogsUtility.DisplayDialogComplex( BuilderConstants.SaveDialogSaveChangesPromptTitle, BuilderConstants.SaveDialogSaveChangesPromptMessage, BuilderConstants.DialogSaveActionOption, BuilderConstants.DialogCancelOption, BuilderConstants.DialogDontSaveActionOption); switch (option) { // Save case 0: return(SaveUnsavedChanges()); // Cancel case 1: return(false); // Don't Save case 2: RestoreAssetsFromBackup(); return(true); } } return(true); }
public static bool ValidateAsset(VisualTreeAsset asset, string path) { string errorMessage = null; string errorTitle = null; if (asset == null) { if (string.IsNullOrEmpty(path)) { path = "<unspecified>"; } if (path.StartsWith("Packages/")) { errorMessage = $"The asset at path {path} is not a UXML Document.\nNote, for assets inside Packages folder, the folder name for the package needs to match the actual official package name (ie. com.example instead of Example)."; } else { errorMessage = $"The asset at path {path} is not a UXML Document."; } errorTitle = "Invalid Asset Type"; } else if (asset.importedWithErrors) { if (string.IsNullOrEmpty(path)) { path = AssetDatabase.GetAssetPath(asset); } if (string.IsNullOrEmpty(path)) { path = "<unspecified>"; } errorMessage = string.Format(BuilderConstants.InvalidUXMLDialogMessage, path); errorTitle = BuilderConstants.InvalidUXMLDialogTitle; } if (errorMessage != null) { BuilderDialogsUtility.DisplayDialog(errorTitle, errorMessage, "Ok"); Debug.LogError(errorMessage); return(false); } return(true); }
public static void AddStyleSheetToAsset( BuilderDocument document, string ussPath) { var styleSheet = AssetDatabase.LoadAssetAtPath <StyleSheet>(ussPath); if (styleSheet == null) { BuilderDialogsUtility.DisplayDialog("Invalid Asset Type", @"Asset at path {ussPath} is not a StyleSheet."); return; } Undo.RegisterCompleteObjectUndo( document.visualTreeAsset, "Add StyleSheet to UXML"); document.AddStyleSheetToDocument(styleSheet, ussPath); }
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); }
bool IsFileActionCompatible(string assetPath, string actionName) { if (assetPath.Equals(document.uxmlPath) || document.ussPaths.Contains(assetPath)) { var fileName = Path.GetFileName(assetPath); var acceptAction = BuilderDialogsUtility.DisplayDialog(BuilderConstants.ErrorDialogNotice, string.Format(BuilderConstants.ErrorIncompatibleFileActionMessage, actionName, fileName), BuilderConstants.DialogDiscardOption, string.Format(BuilderConstants.DialogAbortActionOption, actionName.ToPascalCase())); if (acceptAction) { NewDocument(false); } return(acceptAction); } return(true); }
bool IsFileActionCompatible(string assetPath, string actionName) { if (IsAssetUsedInDocument(document, assetPath)) { var fileName = Path.GetFileName(assetPath); var acceptAction = BuilderDialogsUtility.DisplayDialog(BuilderConstants.ErrorDialogNotice, string.Format(BuilderConstants.ErrorIncompatibleFileActionMessage, actionName, fileName), string.Format(BuilderConstants.DialogDiscardOption, actionName.ToPascalCase()), string.Format(BuilderConstants.DialogAbortActionOption, actionName.ToPascalCase())); if (acceptAction) { // Open a new, empty document NewDocument(false); } return(acceptAction); } return(true); }
public static bool AddStyleSheetToAsset( BuilderDocument document, string ussPath) { var styleSheet = BuilderPackageUtilities.LoadAssetAtPath <StyleSheet>(ussPath); string errorMessage = null; string errorTitle = null; if (styleSheet == null) { if (ussPath.StartsWith("Packages/")) { errorMessage = $"Asset at path {ussPath} is not a StyleSheet.\nNote, for assets inside Packages folder, the folder name for the package needs to match the actual official package name (ie. com.example instead of Example)."; } else { errorMessage = $"Asset at path {ussPath} is not a StyleSheet."; } errorTitle = "Invalid Asset Type"; } else if (styleSheet.importedWithErrors) { errorMessage = string.Format(BuilderConstants.InvalidUSSDialogMessage, ussPath); errorTitle = BuilderConstants.InvalidUSSDialogTitle; } if (errorMessage != null) { BuilderDialogsUtility.DisplayDialog(errorTitle, errorMessage, "Ok"); Debug.LogError(errorMessage); return(false); } Undo.RegisterCompleteObjectUndo( document.visualTreeAsset, "Add StyleSheet to UXML"); document.AddStyleSheetToDocument(styleSheet, ussPath); return(true); }
private void OnEditButton() { if (BuilderExternalPackages.is2DSpriteEditorInstalled) { // Open 2D Sprite Editor with current image loaded BuilderExternalPackages.Open2DSpriteEditor((Object)value); return; } // Handle the missing 2D Sprite Editor package case. if (BuilderDialogsUtility.DisplayDialog( k_No2DSpriteEditorPackageInstalledTitle, k_No2DSpriteEditorPackageInstalledMessage, "Install", "Cancel")) { if (!Install2DSpriteEditorPackage()) { Application.OpenURL(k_2DSpriteEditorInstallationURL); } } }
public static void AddStyleSheetToAsset( BuilderDocument document, string ussPath) { var styleSheet = BuilderPackageUtilities.LoadAssetAtPath <StyleSheet>(ussPath); if (styleSheet == null) { if (ussPath.StartsWith("Packages/")) { BuilderDialogsUtility.DisplayDialog("Invalid Asset Type", $"Asset at path {ussPath} is not a StyleSheet.\nNote, for assets inside Packages folder, the folder name for the package needs to match the actual official package name (ie. com.example instead of Example)."); } else { BuilderDialogsUtility.DisplayDialog("Invalid Asset Type", $"Asset at path {ussPath} is not a StyleSheet."); } return; } Undo.RegisterCompleteObjectUndo( document.visualTreeAsset, "Add StyleSheet to UXML"); document.AddStyleSheetToDocument(styleSheet, ussPath); }
public bool CheckForUnsavedChanges(bool assetModifiedExternally = false) { if (!hasUnsavedChanges) { return(true); } int option = -1; if (assetModifiedExternally) { // TODO: Nothing can be done here yet, other than telling the user // what just happened. Adding the ability to save unsaved changes // after a file has been modified externally will require some // major changes to the document flow. BuilderDialogsUtility.DisplayDialog( BuilderConstants.SaveDialogExternalChangesPromptTitle, BuilderConstants.SaveDialogExternalChangesPromptMessage); return(true); } else { option = BuilderDialogsUtility.DisplayDialogComplex( BuilderConstants.SaveDialogSaveChangesPromptTitle, BuilderConstants.SaveDialogSaveChangesPromptMessage, BuilderConstants.DialogSaveActionOption, BuilderConstants.DialogCancelOption, BuilderConstants.DialogDontSaveActionOption); switch (option) { // Save case 0: if (!string.IsNullOrEmpty(uxmlPath) && !string.IsNullOrEmpty(ussPath)) { SaveNewDocument(uxmlPath, ussPath, null, false); return(true); } else { var builderWindow = Builder.ActiveWindow; if (builderWindow == null) { builderWindow = Builder.ShowWindow(); } builderWindow.toolbar.PromptSaveDocumentDialog(); return(false); } // Cancel case 1: return(false); // Don't Save case 2: RestoreAssetsFromBackup(); return(true); } } return(true); }
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(); }