From 2e3af6c4215fba3f16bb40ef6f5d8732f2651795 Mon Sep 17 00:00:00 2001 From: Jason Ma <1312119064@qq.com> Date: Tue, 16 Jul 2024 18:14:57 +0800 Subject: [PATCH] Fix Ramp Editor Undo/Redo --- Editor/Helper/RampHelper.cs | 70 +++++++++++-------- Editor/ShaderDrawer.cs | 5 +- README.md | 4 +- README_CN.md | 3 +- Runtime/LwguiGradient/LwguiGradient.cs | 29 ++++---- .../LwguiGradientDrawer.cs | 1 - .../LwguiGradientEditorHelper.cs | 32 ++++++--- .../LwguiGradientWindow.cs | 46 +++++++----- 8 files changed, 117 insertions(+), 73 deletions(-) diff --git a/Editor/Helper/RampHelper.cs b/Editor/Helper/RampHelper.cs index 9ae39dd..4558b47 100644 --- a/Editor/Helper/RampHelper.cs +++ b/Editor/Helper/RampHelper.cs @@ -6,6 +6,7 @@ using LWGUI.Runtime.LwguiGradient; using UnityEditor; using UnityEngine; +using Object = UnityEngine.Object; namespace LWGUI { @@ -33,13 +34,16 @@ public static bool RampEditor( string rootPath, int defaultWidth, int defaultHeight, + out bool doRegisterUndo, out Texture2D newTexture, out bool doSave, - out bool doDiscard) + out bool doDiscard + ) { newTexture = null; var hasChange = false; var shouldCreate = false; + var doOpenWindow = false; var singleButtonWidth = buttonRect.width * 0.25f; var editRect = new Rect(buttonRect.x + singleButtonWidth * 0, buttonRect.y, singleButtonWidth, buttonRect.height); var saveRect = new Rect(buttonRect.x + singleButtonWidth * 1, buttonRect.y, singleButtonWidth, buttonRect.height); @@ -47,28 +51,32 @@ public static bool RampEditor( var discardRect = new Rect(buttonRect.x + singleButtonWidth * 3, buttonRect.y, singleButtonWidth, buttonRect.height); // Edit button event - EditorGUI.BeginChangeCheck(); - LwguiGradientEditorHelper.GradientEditButton(editRect, _iconEdit, gradient, colorSpace, viewChannelMask, timeRange, () => { - // if the current edited texture is null, create new one - if (prop.textureValue == null) + EditorGUI.BeginChangeCheck(); + LwguiGradientEditorHelper.GradientEditButton(editRect, _iconEdit, gradient, colorSpace, viewChannelMask, timeRange, () => { - shouldCreate = true; - Event.current.Use(); - } - else + // if the current edited texture is null, create new one + if (prop.textureValue == null) + { + shouldCreate = true; + Event.current.Use(); + return false; + } + else + { + doOpenWindow = true; + return true; + } + }); + if (EditorGUI.EndChangeCheck()) { - // Undo.RecordObject(prop.textureValue, "Edit Gradient"); + hasChange = true; + gradient = LwguiGradientWindow.instance.lwguiGradient; } - return prop.textureValue != null; - }); - if (EditorGUI.EndChangeCheck()) - { - hasChange = true; - gradient = LwguiGradientWindow.instance.lwguiGradient; + doRegisterUndo = doOpenWindow; } - + // Create button if (GUI.Button(addRect, _iconAdd) || shouldCreate) { @@ -102,11 +110,13 @@ public static bool RampEditor( } // Save button - var color = GUI.color; - if (isDirty) GUI.color = Color.yellow; - doSave = GUI.Button(saveRect, _iconSave); - GUI.color = color; - + { + var color = GUI.color; + if (isDirty) GUI.color = Color.yellow; + doSave = GUI.Button(saveRect, _iconSave); + GUI.color = color; + } + // Discard button doDiscard = GUI.Button(discardRect, _iconDiscard); @@ -115,12 +125,16 @@ public static bool RampEditor( public static bool HasGradient(AssetImporter assetImporter) { return assetImporter.userData.Contains("#");} - public static LwguiGradient GetGradientFromTexture(Texture texture, out bool isDirty, bool doDiscard = false) + public static LwguiGradient GetGradientFromTexture(Texture texture, out bool isDirty, bool doDiscard = false, bool doRegisterUndo = false) { isDirty = false; if (texture == null) return null; var assetImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)); + if (doRegisterUndo) + { + LwguiGradientWindow.RegisterRampMapUndo(texture, assetImporter); + } if (assetImporter != null && HasGradient(assetImporter)) { isDirty = DecodeGradientFromJSON(assetImporter.userData, out var savedGradient, out var editingGradient); @@ -142,19 +156,19 @@ public static void SetGradientToTexture(Texture texture, LwguiGradient gradient, if (texture == null || gradient == null) return; var texture2D = (Texture2D)texture; + var path = AssetDatabase.GetAssetPath(texture); + var assetImporter = AssetImporter.GetAtPath(path); VersionControlHelper.Checkout(texture2D); - Undo.RecordObject(texture2D, "LWGUI: Set Gradient To Texture"); + + LwguiGradientWindow.RegisterRampMapUndo(texture2D, assetImporter); // Save to texture - var path = AssetDatabase.GetAssetPath(texture); var pixels = gradient.GetPixels(texture.width, texture.height); texture2D.SetPixels(pixels); texture2D.Apply(); // Save gradient JSON to userData - var assetImporter = AssetImporter.GetAtPath(path); - LwguiGradient savedGradient, editingGradient; - DecodeGradientFromJSON(assetImporter.userData, out savedGradient, out editingGradient); + DecodeGradientFromJSON(assetImporter.userData, out var savedGradient, out _); assetImporter.userData = EncodeGradientToJSON(doSaveToDisk ? gradient : savedGradient, gradient); // Save texture to disk diff --git a/Editor/ShaderDrawer.cs b/Editor/ShaderDrawer.cs index 3d9d01c..d88c634 100644 --- a/Editor/ShaderDrawer.cs +++ b/Editor/ShaderDrawer.cs @@ -923,6 +923,7 @@ public class RampDrawer : SubDrawer protected ColorSpace _colorSpace; protected LwguiGradient.ChannelMask _viewChannelMask; protected LwguiGradient.GradientTimeRange _timeRange; + protected bool _doRegisterUndo; private static readonly GUIContent _iconMixImage = EditorGUIUtility.IconContent("darkviewbackground"); @@ -988,7 +989,7 @@ public override void DrawProp(Rect position, MaterialProperty prop, GUIContent l var labelWidth = EditorGUIUtility.labelWidth; var indentLevel = EditorGUI.indentLevel; - var gradient = RampHelper.GetGradientFromTexture(prop.textureValue, out var isDirty) ?? new LwguiGradient(); + var gradient = RampHelper.GetGradientFromTexture(prop.textureValue, out var isDirty, false, _doRegisterUndo) ?? new LwguiGradient(); OnRampPropUpdate(position, prop, label, editor); @@ -1011,7 +1012,7 @@ public override void DrawProp(Rect position, MaterialProperty prop, GUIContent l // Draw Ramp Editor var hasGradientChanges = RampHelper.RampEditor(buttonRect, prop, ref gradient, _colorSpace, _viewChannelMask, _timeRange, - isDirty, _defaultFileName, _rootPath, (int)_defaultWidth, (int)_defaultHeight, + isDirty, _defaultFileName, _rootPath, (int)_defaultWidth, (int)_defaultHeight, out _doRegisterUndo, out var newCreatedTexture, out var doSaveGradient, out var doDiscardGradient); if (newCreatedTexture != null) diff --git a/README.md b/README.md index d69a0d8..601892f 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Having been validated through numerous large-scale commercial projects, employin * [Contribution](#contribution) - + @@ -81,6 +81,8 @@ Having been validated through numerous large-scale commercial projects, employin - LWGUI 1.x: **Unity 2017.4+** - LWGUI 2.x: **Unity 2021.3+** + - **Recommended minimum version: Unity 2022.2+, lower versions can be used but may have bugs** + 2. Open your project 3. `Window > Package Manager > Add > Add package from git URL` , enter: `https://github.com/JasonMa0012/LWGUI.git` diff --git a/README_CN.md b/README_CN.md index eaf3e17..82ac2f9 100644 --- a/README_CN.md +++ b/README_CN.md @@ -68,7 +68,7 @@ * [Contribution](#contribution) - + @@ -78,6 +78,7 @@ 1. 确保你的Unity版本兼容LWGUI - LWGUI 1.x: **Unity 2017.4+** - LWGUI 2.x: **Unity 2021.3+** + - **推荐的最低版本: Unity 2022.2+, 更低版本虽然能使用但可能有BUG** 2. 打开已有工程 3. (可能需要全局代理)`Window > Package Manager > Add > Add package from git URL` 输入`https://github.com/JasonMa0012/LWGUI.git` diff --git a/Runtime/LwguiGradient/LwguiGradient.cs b/Runtime/LwguiGradient/LwguiGradient.cs index a02703a..db81f04 100644 --- a/Runtime/LwguiGradient/LwguiGradient.cs +++ b/Runtime/LwguiGradient/LwguiGradient.cs @@ -73,17 +73,7 @@ public LwguiGradient() public LwguiGradient(LwguiGradient src) { - _curves = new List(); - for (int c = 0; c < (int)Channel.Num; c++) - _curves.Add(new AnimationCurve()); - - for (int c = 0; c < src._curves.Count; c++) - { - foreach (var key in src._curves[c].keys) - { - _curves[c].AddKey(key); - } - } + DeepCopyFrom(src); } public LwguiGradient(params Keyframe[] keys) @@ -108,10 +98,25 @@ public void Clear(ChannelMask channelMask = ChannelMask.All) { if (!IsChannelIndexInMask(c, channelMask)) continue; - if (_curves.Count > c) _curves[c].keys = new Keyframe[0]; + if (_curves.Count > c) _curves[c].keys = Array.Empty(); else _curves.Add(new AnimationCurve()); } } + + public void DeepCopyFrom(LwguiGradient src) + { + _curves = new List(); + for (int c = 0; c < (int)Channel.Num; c++) + _curves.Add(new AnimationCurve()); + + for (int c = 0; c < src._curves.Count; c++) + { + foreach (var key in src._curves[c].keys) + { + _curves[c].AddKey(key); + } + } + } public void SetCurve(AnimationCurve curve, ChannelMask channelMask) { diff --git a/UnityEditorExtension/LwguiGradientEditor/LwguiGradientDrawer.cs b/UnityEditorExtension/LwguiGradientEditor/LwguiGradientDrawer.cs index e85b3c2..cba2980 100644 --- a/UnityEditorExtension/LwguiGradientEditor/LwguiGradientDrawer.cs +++ b/UnityEditorExtension/LwguiGradientEditor/LwguiGradientDrawer.cs @@ -52,7 +52,6 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten LwguiGradientEditorHelper.GradientField(position, label, property, gradient, colorSpace, viewChannelMask, timeRange); if (EditorGUI.EndChangeCheck()) { - // Debug.Log(11111111111); } } } diff --git a/UnityEditorExtension/LwguiGradientEditor/LwguiGradientEditorHelper.cs b/UnityEditorExtension/LwguiGradientEditor/LwguiGradientEditorHelper.cs index 3e5c6b1..18075b2 100644 --- a/UnityEditorExtension/LwguiGradientEditor/LwguiGradientEditorHelper.cs +++ b/UnityEditorExtension/LwguiGradientEditor/LwguiGradientEditorHelper.cs @@ -43,7 +43,8 @@ public static void DrawGradientWithBackground(Rect position, LwguiGradient gradi public static void GradientField(Rect position, GUIContent label, LwguiGradient gradient, ColorSpace colorSpace = ColorSpace.Gamma, LwguiGradient.ChannelMask viewChannelMask = LwguiGradient.ChannelMask.All, - LwguiGradient.GradientTimeRange timeRange = LwguiGradient.GradientTimeRange.One) + LwguiGradient.GradientTimeRange timeRange = LwguiGradient.GradientTimeRange.One, + Action onOpenWindow = null) { int id = GUIUtility.GetControlID(s_LwguiGradientHash, FocusType.Keyboard, position); var rect = EditorGUI.PrefixLabel(position, id, label); @@ -60,6 +61,7 @@ public static void GradientField(Rect position, GUIContent label, LwguiGradient s_LwguiGradientID = id; GUIUtility.keyboardControl = id; LwguiGradientWindow.Show(gradient, colorSpace, viewChannelMask, timeRange, GUIView.current); + onOpenWindow?.Invoke(); GUIUtility.ExitGUI(); } else if (evt.button == 1) @@ -75,27 +77,30 @@ public static void GradientField(Rect position, GUIContent label, LwguiGradient { evt.Use(); LwguiGradientWindow.Show(gradient, colorSpace, viewChannelMask, timeRange, GUIView.current); + onOpenWindow?.Invoke(); GUIUtility.ExitGUI(); } break; case EventType.Repaint: DrawGradientWithBackground(rect, gradient, colorSpace, viewChannelMask); - // var previewRect = new Rect(rect.x + 2.5f, rect.y + 2.5f, rect.width - 5.0f, rect.height - 5.0f); - // EditorGUI.DrawPreviewTexture(previewRect, gradient.GetPreviewRampTexture(256, 1, colorSpace, viewChannelMask)); - // var outlineRect = new Rect(rect.x + 0.5f, rect.y + 0.5f, rect.width - 1.0f, rect.height - 1.0f); - // EditorStyles.colorPickerBox.Draw(outlineRect, GUIContent.none, id); break; case EventType.ExecuteCommand: // When drawing the modifying Gradient Field and it has changed if ((GUIUtility.keyboardControl == id || s_LwguiGradientID == id) && evt.commandName == LwguiGradientWindow.LwguiGradientChangedCommand) { - // evt.Use(); GUI.changed = true; HandleUtility.Repaint(); } break; + case EventType.ValidateCommand: + // Sync Undo/Redo result to editor window + if (s_LwguiGradientID == id && evt.commandName == "UndoRedoPerformed") + { + LwguiGradientWindow.UpdateCurrentGradient(gradient); + } + break; } } @@ -108,14 +113,13 @@ public static void GradientField(Rect position, GUIContent label, SerializedProp label = EditorGUI.BeginProperty(position, label, property); EditorGUI.BeginChangeCheck(); - GradientField(position, label, gradient, colorSpace, viewChannelMask, timeRange); + GradientField(position, label, gradient, colorSpace, viewChannelMask, timeRange, + () => LwguiGradientWindow.RegisterSerializedObjectUndo(property.serializedObject.targetObject)); if (EditorGUI.EndChangeCheck()) { GUI.changed = true; - // TODO: Undo/Redo - // Undo.RecordObject(property.serializedObject.targetObject, "Editing Lwgui Gradient"); - property.serializedObject.UpdateIfRequiredOrScript(); + LwguiGradientWindow.RegisterSerializedObjectUndo(property.serializedObject.targetObject); } EditorGUI.EndProperty(); } @@ -138,6 +142,14 @@ public static bool GradientEditButton(Rect position, GUIContent icon, LwguiGradi HandleUtility.Repaint(); } + // Sync Undo/Redo result to editor window + if (s_LwguiGradientID == id + && evt.commandName == "UndoRedoPerformed") + { + LwguiGradientWindow.UpdateCurrentGradient(gradient); + } + + // Open editor window var clicked = ReflectionHelper.GUI_Button(position, id, icon, GUI.skin.button); if (clicked) { diff --git a/UnityEditorExtension/LwguiGradientEditor/LwguiGradientWindow.cs b/UnityEditorExtension/LwguiGradientEditor/LwguiGradientWindow.cs index d8ee08c..9772616 100644 --- a/UnityEditorExtension/LwguiGradientEditor/LwguiGradientWindow.cs +++ b/UnityEditorExtension/LwguiGradientEditor/LwguiGradientWindow.cs @@ -5,6 +5,7 @@ using UnityEditor; using LWGUI.Runtime.LwguiGradient; using UnityEngine.Serialization; +using Object = UnityEngine.Object; namespace LWGUI.LwguiGradientEditor { @@ -43,7 +44,6 @@ public class LwguiGradientWindow : EditorWindow private GUIView _viewToUpdate; private Action _onChange; - private bool _changed { get; set; } #endregion @@ -82,7 +82,7 @@ public string currentPresetLibrary public static bool visible => _lwguiGradientWindow != null; - private void Init(bool force = true, bool forceRecreate = false) + public void Init(bool force = true, bool forceRecreate = false) { if (_lwguiGradientEditor == null || force || forceRecreate) { @@ -118,14 +118,23 @@ void UpdatePresetLibraryViewSettings() _lwguiGradientLibraryEditor.viewChannelMask = _lwguiGradientEditor.viewChannelMask; } - public static void SetCurrentGradient(LwguiGradient lwguiGradient) + /// Used to modify the LwguiGradient value externally, such as: Undo/Redo/Select Preset + public static void UpdateCurrentGradient(LwguiGradient newGradient, bool doDeepCopy = false) { if (_lwguiGradientWindow == null) return; - _lwguiGradientWindow.lwguiGradient = lwguiGradient; + if (doDeepCopy) + { + _lwguiGradientWindow.lwguiGradient.DeepCopyFrom(newGradient); + } + else + { + _lwguiGradientWindow.lwguiGradient = newGradient; + } + // Debug.Log("Update"); _lwguiGradientWindow.Init(); - GUI.changed = true; + _lwguiGradientWindow.Repaint(); } private static LwguiGradientWindow GetWindow(bool focus = true) => (LwguiGradientWindow)GetWindow(typeof(LwguiGradientWindow), true, "LWGUI Gradient Editor", focus); @@ -172,6 +181,15 @@ public static void RepaintWindow() _lwguiGradientWindow.Repaint(); } + public static void RegisterSerializedObjectUndo(Object targetObject) + { + Undo.RegisterCompleteObjectUndo(targetObject, "Lwgui Gradient Editor"); + } + + public static void RegisterRampMapUndo(Object texture, Object assetImporter) + { + Undo.RecordObjects(new Object[]{ texture, assetImporter }, "Set Lwgui Gradient To Texture"); + } private void OnGUI() { @@ -187,17 +205,10 @@ private void OnGUI() EditorGUI.BeginChangeCheck(); _lwguiGradientEditor.OnGUI(_gradientEditorRect); + _lwguiGradientLibraryEditor.OnGUI(_presetLibraryRect, lwguiGradient); if (EditorGUI.EndChangeCheck()) { - _changed = true; UpdatePresetLibraryViewSettings(); - } - - _lwguiGradientLibraryEditor.OnGUI(_presetLibraryRect, lwguiGradient); - - if (_changed) - { - _changed = false; SendEvent(true); } } @@ -271,9 +282,9 @@ private void UnregisterEvents() #if UNITY_2022_2_OR_NEWER private void OnUndoPerformed(in UndoRedoInfo info) { - Init(); - // TODO: Undo/Redo - // Debug.Log(11111111111); + // Debug.Log("Init"); + _lwguiGradientWindow.Init(); + _lwguiGradientWindow.Repaint(); } #endif @@ -288,9 +299,8 @@ void PresetClickedCallback(int clickCount, object presetObject) if (gradient == null) Debug.LogError("Incorrect object passed " + presetObject); - SetCurrentGradient(gradient); + UpdateCurrentGradient(gradient, true); // UnityEditorInternal.GradientPreviewCache.ClearCache(); - _changed = true; } #endregion