diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/InputActionsEditorWindow.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/InputActionsEditorWindow.cs index e76064f195..ef2f08cfd6 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/InputActionsEditorWindow.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/InputActionsEditorWindow.cs @@ -25,6 +25,9 @@ internal class InputActionsEditorWindow : EditorWindow { private static readonly string k_FileExtension = "." + InputActionAsset.Extension; private int m_AssetId; + private string m_AssetPath; + private string m_AssetJson; + private bool m_IsDirty; [OnOpenAsset] public static bool OpenAsset(int instanceId, int line) @@ -51,6 +54,7 @@ public static bool OpenAsset(int instanceId, int line) window.Focus(); return true; } + window.m_IsDirty = false; window.m_AssetId = instanceId; window.titleContent = new GUIContent("Input Actions Editor"); window.SetAsset(asset); @@ -74,8 +78,10 @@ private static InputActionsEditorWindow GetOrCreateWindow(int id, out bool isAlr private void SetAsset(InputActionAsset asset) { + m_AssetPath = AssetDatabase.GetAssetPath(asset); var serializedAsset = new SerializedObject(asset); m_State = new InputActionsEditorState(serializedAsset); + m_AssetJson = File.ReadAllText(m_AssetPath); bool isGUIDObtained = AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out m_AssetGUID, out long _); Debug.Assert(isGUIDObtained, $"Failed to get asset {asset.name} GUID"); @@ -95,6 +101,8 @@ private void CreateGUI() if (m_State.serializedObject == null) { var asset = GetAssetFromDatabase(); + m_AssetPath = AssetDatabase.GetAssetPath(asset); + m_AssetJson = File.ReadAllText(m_AssetPath); var serializedAsset = new SerializedObject(asset); m_State = new InputActionsEditorState(m_State, serializedAsset); } @@ -119,10 +127,70 @@ private void BuildUI() private void OnStateChanged(InputActionsEditorState newState) { + DirtyInputActionsEditorWindow(newState); if (InputEditorUserSettings.autoSaveInputActionAssets) SaveAsset(m_State.serializedObject); } + private void DirtyInputActionsEditorWindow(InputActionsEditorState newState) + { + var isWindowDirty = !InputEditorUserSettings.autoSaveInputActionAssets && HasAssetChanged(newState.serializedObject); + if (m_IsDirty == isWindowDirty) + return; + m_IsDirty = isWindowDirty; + titleContent = m_IsDirty ? new GUIContent("(*) Input Actions Editor") : new GUIContent("Input Actions Editor"); + } + + private bool HasAssetChanged(SerializedObject serializedAsset) + { + var asset = (InputActionAsset)serializedAsset.targetObject; + var newAssetJson = asset.ToJson(); + return newAssetJson != m_AssetJson; + } + + private void OnDestroy() + { + ConfirmSaveChangesIfNeeded(); + } + + private void ConfirmSaveChangesIfNeeded() + { + // Do we have unsaved changes? + if (!m_IsDirty) + return; + + var result = EditorUtility.DisplayDialogComplex("Input Action Asset has been modified", $"Do you want to save the changes you made in:\n{m_AssetPath}\n\nYour changes will be lost if you don't save them.", "Save", "Cancel", "Don't Save"); + switch (result) + { + case 0: // Save + SaveAsset(m_State.serializedObject, this); + break; + case 1: // Cancel editor quit. (open new editor window with the edited asset) + ReshowEditorWindowWithUnsavedChanges(); + break; + case 2: // Don't save, quit - reload the old asset from the json to prevent the asset from being dirtied + AssetDatabase.ImportAsset(m_AssetPath); + break; + } + } + + private void ReshowEditorWindowWithUnsavedChanges() + { + var window = CreateWindow(); + CopyOldStatsToNewWindow(window); + window.BuildUI(); + window.Show(); + } + + private void CopyOldStatsToNewWindow(InputActionsEditorWindow window) + { + window.m_AssetId = m_AssetId; + window.m_State = m_State; + window.m_AssetPath = m_AssetPath; + window.m_AssetJson = m_AssetJson; + window.m_IsDirty = true; + } + private InputActionAsset GetAssetFromDatabase() { Debug.Assert(!string.IsNullOrEmpty(m_AssetGUID), "Asset GUID is empty"); @@ -133,18 +201,21 @@ private InputActionAsset GetAssetFromDatabase() [SerializeField] private InputActionsEditorState m_State; [SerializeField] private string m_AssetGUID; - public static void SaveAsset(SerializedObject serializedAsset) + public static void SaveAsset(SerializedObject serializedAsset, InputActionsEditorWindow currentWindow = null) { + if ((focusedWindow == null || focusedWindow is not InputActionsEditorWindow) && currentWindow == null) + return; + currentWindow = currentWindow ? currentWindow : (InputActionsEditorWindow)focusedWindow; var asset = (InputActionAsset)serializedAsset.targetObject; - var assetPath = AssetDatabase.GetAssetPath(asset); var assetJson = asset.ToJson(); - var existingJson = File.ReadAllText(assetPath); + var existingJson = File.ReadAllText(currentWindow.m_AssetPath); if (assetJson != existingJson) { - EditorHelpers.CheckOut(assetPath); - File.WriteAllText(assetPath, assetJson); - AssetDatabase.ImportAsset(assetPath); + EditorHelpers.CheckOut(currentWindow.m_AssetPath); + File.WriteAllText(currentWindow.m_AssetPath, assetJson); + AssetDatabase.ImportAsset(currentWindow.m_AssetPath); + currentWindow.m_AssetJson = assetJson; } } }