diff --git a/Editor/Favorites/Utilities/Favorites.cs b/Editor/Favorites/Utilities/Favorites.cs index be1d6e0..9567d90 100644 --- a/Editor/Favorites/Utilities/Favorites.cs +++ b/Editor/Favorites/Utilities/Favorites.cs @@ -59,6 +59,14 @@ namespace Game.NavigationTool.Editor } } } + + for (var i = 0; i < entries.Count; i++) + { + Entry e = entries[i]; + + if (e.indentLevel != 0 && e.parent == null) + e.indentLevel = 0; + } } public void Add(string guid, Entry toParent = null) @@ -82,6 +90,9 @@ namespace Game.NavigationTool.Editor entries.Add(e); + if (toParent != null && toParent.isAsset) + toParent = toParent.parent; + if (toParent != null) { e.parent = toParent; @@ -137,7 +148,7 @@ namespace Game.NavigationTool.Editor if (!e.isAsset) { - for (var i = 0; i < e.children.Count; i++) + for (int i = e.children.Count - 1; i >= 0; i--) { InternalRemove(e.children[i].entry); } @@ -191,9 +202,23 @@ namespace Game.NavigationTool.Editor string path = AssetDatabase.GUIDToAssetPath(entry.assetGuid); return AssetDatabase.LoadMainAssetAtPath(path); } + + private void Sort() + { + entries.Sort((e0, e1) => + { + int compare = e0.isAsset.CompareTo(e1.isAsset); + + if (compare == 0) + compare = string.Compare(e0.lowerName, e1.lowerName, StringComparison.Ordinal); + + return compare; + }); + } public void Save() { + Sort(); string json = EditorJsonUtility.ToJson(this, false); EditorPrefs.SetString(PREF_ID, json); } @@ -254,7 +279,7 @@ namespace Game.NavigationTool.Editor string path = AssetDatabase.GUIDToAssetPath(assetGuid); name = Path.GetFileNameWithoutExtension(path); lowerName = name.ToLower(); - valid = !string.IsNullOrEmpty(path); + valid = AssetDatabase.LoadMainAssetAtPath(path) != null; content = new GUIContent(name, FavoritesGUIUtility.GetIcon(path), path); } else @@ -267,6 +292,15 @@ namespace Game.NavigationTool.Editor public void AddChild(Entry entry) { children.Add(new Child(entry)); + children.Sort((c0, c1) => + { + int compare = c0.entry.isAsset.CompareTo(c1.entry.isAsset); + + if (compare == 0) + compare = string.Compare(c0.entry.lowerName, c1.entry.lowerName, StringComparison.Ordinal); + + return compare; + }); } public void RemoveChild(Entry entry) diff --git a/Editor/Favorites/Utilities/FavoritesGUIUtility.cs b/Editor/Favorites/Utilities/FavoritesGUIUtility.cs index f877904..43c05c7 100644 --- a/Editor/Favorites/Utilities/FavoritesGUIUtility.cs +++ b/Editor/Favorites/Utilities/FavoritesGUIUtility.cs @@ -10,8 +10,11 @@ namespace Game.NavigationTool.Editor public static Favorites.Entry manipulatingEntry; public static EManipulatingState manipulatingState; - public static Favorites.Entry hoverEntry; + public static Vector2 manipulatingMouseOffset; + public static Rect manipulatingRect; + public static Favorites.Entry hoverEntry; + public static void DrawEntry(Rect rect, Favorites.Entry entry, Styles styles, bool ignoreIndentLevel = false) { int id = GUIUtility.GetControlID(ENTRY_HASH, FocusType.Passive, rect); @@ -20,15 +23,14 @@ namespace Game.NavigationTool.Editor if (intersects) hoverEntry = entry; - else if (hoverEntry == entry) - hoverEntry = null; switch (Event.current.type) { case EventType.MouseDown: if (intersects) { - SetManipulating(entry, Event.current.button == 0 ? EManipulatingState.BeginClick : EManipulatingState.BeginContextClick); + SetManipulating(rect, entry, Event.current.button == 0 ? EManipulatingState.BeginClick : EManipulatingState.BeginContextClick); + manipulatingMouseOffset = Event.current.mousePosition - rect.position; Event.current.Use(); } break; @@ -38,16 +40,23 @@ namespace Game.NavigationTool.Editor if (manipulatingState == EManipulatingState.BeginClick) { if (intersects && Event.current.button == 0) - SetManipulating(entry, EManipulatingState.PerformedClick); + SetManipulating(rect, entry, EManipulatingState.PerformedClick); else - SetManipulating(entry, EManipulatingState.EndClick); + SetManipulating(rect, entry, EManipulatingState.EndClick); } else if (manipulatingState == EManipulatingState.BeginContextClick) { if (intersects && Event.current.button == 1) - SetManipulating(entry, EManipulatingState.PerformedContextClick); + SetManipulating(rect, entry, EManipulatingState.PerformedContextClick); else - SetManipulating(entry, EManipulatingState.EndContextClick); + SetManipulating(rect, entry, EManipulatingState.EndContextClick); + } + else if (manipulatingState == EManipulatingState.BeginDrag) + { + if (intersects) + SetManipulating(rect, entry, EManipulatingState.EndDrag); + else + SetManipulating(rect, entry, EManipulatingState.PerformedDrag); } Event.current.Use(); @@ -55,11 +64,10 @@ namespace Game.NavigationTool.Editor break; case EventType.MouseDrag: if (manipulatingEntry == entry) + { + SetManipulating(rect, entry, EManipulatingState.BeginDrag); Event.current.Use(); - break; - case EventType.KeyDown: - break; - case EventType.KeyUp: + } break; case EventType.Repaint: if (!ignoreIndentLevel) @@ -67,20 +75,36 @@ namespace Game.NavigationTool.Editor rect.x += entry.indentLevel * 15.0f; rect.width -= entry.indentLevel * 15.0f; } - + if (!entry.isAsset) entry.content.image = entry.expanded ? styles.foldoutOut : styles.foldoutIn; - styles.entry.Draw(rect, entry.content, id, on, intersects); - break; - case EventType.DragUpdated: - break; - case EventType.DragPerform: - break; - case EventType.DragExited: + GUIStyle style = entry.valid ? styles.entry : styles.invalidEntry; + style.Draw(rect, entry.content, id, on, intersects); break; } } + + public static void DrawShadowEntry(Rect rect, Favorites.Entry entry, Styles styles) + { + if (Event.current.type != EventType.Repaint) + return; + + if (!entry.isAsset) + entry.content.image = entry.expanded ? styles.foldoutOut : styles.foldoutIn; + + int id = GUIUtility.GetControlID(ENTRY_HASH, FocusType.Passive, rect); + GUIStyle style = entry.valid ? styles.entry : styles.invalidEntry; + + GUI.enabled = false; + style.Draw(rect, entry.content, id, false, false); + GUI.enabled = true; + } + + public static void EndDraw() + { + hoverEntry = null; + } public static Texture2D GetIcon(string path) { @@ -97,15 +121,16 @@ namespace Game.NavigationTool.Editor return AssetDatabase.GetCachedIcon("Assets") as Texture2D; } - private static void SetManipulating(Favorites.Entry entry, EManipulatingState state) + private static void SetManipulating(Rect rect, Favorites.Entry entry, EManipulatingState state) { + manipulatingRect = rect; manipulatingEntry = entry; manipulatingState = state; } public static void ClearManipulating() { - SetManipulating(null, EManipulatingState.None); + SetManipulating(Rect.zero, null, EManipulatingState.None); hoverEntry = null; } } diff --git a/Editor/Favorites/Utilities/FavoritesPostProcess.cs b/Editor/Favorites/Utilities/FavoritesPostProcess.cs new file mode 100644 index 0000000..8a6d4cb --- /dev/null +++ b/Editor/Favorites/Utilities/FavoritesPostProcess.cs @@ -0,0 +1,17 @@ +using UnityEditor; + +namespace Game.NavigationTool.Editor +{ + internal sealed class FavoritesPostProcess : AssetPostprocessor + { + private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) + { + bool isDirty = deletedAssets.Length != 0 || + movedAssets.Length != 0 || + movedFromAssetPaths.Length != 0; + + if (isDirty && FavoritesUtility.IsLoaded()) + FavoritesUtility.RefreshAll(); + } + } +} \ No newline at end of file diff --git a/Editor/Favorites/Utilities/FavoritesPostProcess.cs.meta b/Editor/Favorites/Utilities/FavoritesPostProcess.cs.meta new file mode 100644 index 0000000..25f7df7 --- /dev/null +++ b/Editor/Favorites/Utilities/FavoritesPostProcess.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 522178e7e28db4e4b8bad3b9ae7d1ff4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Favorites/Utilities/FavoritesUtility.cs b/Editor/Favorites/Utilities/FavoritesUtility.cs index b807d6f..1758957 100644 --- a/Editor/Favorites/Utilities/FavoritesUtility.cs +++ b/Editor/Favorites/Utilities/FavoritesUtility.cs @@ -1,4 +1,5 @@ -using UnityEditor; +using System.Collections.Generic; +using UnityEditor; namespace Game.NavigationTool.Editor { @@ -16,6 +17,24 @@ namespace Game.NavigationTool.Editor return FAVORITES ?? (FAVORITES = new Favorites()); } + public static bool IsLoaded() + { + return FAVORITES != null; + } + + public static void RefreshAll() + { + if (FAVORITES == null) + return; + + List entries = FAVORITES.entries; + + for (var i = 0; i < entries.Count; i++) + { + entries[i].Refresh(); + } + } + [MenuItem("Tools/Utilities/Favorites/Delete")] public static void DeleteAll() { diff --git a/Editor/Favorites/Window/EditorFavoritesWindow.cs b/Editor/Favorites/Window/EditorFavoritesWindow.cs index 4d26e34..fad5551 100644 --- a/Editor/Favorites/Window/EditorFavoritesWindow.cs +++ b/Editor/Favorites/Window/EditorFavoritesWindow.cs @@ -59,9 +59,10 @@ namespace Game.NavigationTool.Editor } HandleDragAndDropEvents(); - HandleManipulatedEntry(); + HandleManipulatedEntry(styles); + FavoritesGUIUtility.EndDraw(); } - + private void HandleDragAndDropEvents() { Favorites favorites = FavoritesUtility.GetFavorites(); @@ -76,20 +77,18 @@ namespace Game.NavigationTool.Editor if (!viewTools.IsSearching()) toParent = FavoritesGUIUtility.hoverEntry; - + favorites.AddRangeByPath(DragAndDrop.paths, toParent); } } - private static void HandleManipulatedEntry() + private static void HandleManipulatedEntry(Styles styles) { Favorites favorites = FavoritesUtility.GetFavorites(); Favorites.Entry entry = FavoritesGUIUtility.manipulatingEntry; switch (FavoritesGUIUtility.manipulatingState) { - case EManipulatingState.BeginClick: - break; case EManipulatingState.PerformedClick: if (entry.isAsset) { @@ -102,23 +101,23 @@ namespace Game.NavigationTool.Editor favorites.Save(); } - FavoritesGUIUtility.ClearManipulating(); - break; - case EManipulatingState.EndClick: FavoritesGUIUtility.ClearManipulating(); break; case EManipulatingState.BeginDrag: + Rect rect = FavoritesGUIUtility.manipulatingRect; + rect.position = Event.current.mousePosition - FavoritesGUIUtility.manipulatingMouseOffset; + FavoritesGUIUtility.DrawShadowEntry(rect, entry, styles); break; case EManipulatingState.PerformedDrag: - FavoritesGUIUtility.ClearManipulating(); - break; - case EManipulatingState.EndDrag: + favorites.Move(entry, FavoritesGUIUtility.hoverEntry); FavoritesGUIUtility.ClearManipulating(); break; case EManipulatingState.PerformedContextClick: FavoritesGUIUtility.ClearManipulating(); EditorFavoritesPopupWindowContextMenu.Show(Event.current.mousePosition, entry); break; + case EManipulatingState.EndClick: + case EManipulatingState.EndDrag: case EManipulatingState.EndContextClick: FavoritesGUIUtility.ClearManipulating(); break; diff --git a/Editor/Favorites/Window/Styles/Styles.cs b/Editor/Favorites/Window/Styles/Styles.cs index 7eea0e2..c9e726f 100644 --- a/Editor/Favorites/Window/Styles/Styles.cs +++ b/Editor/Favorites/Window/Styles/Styles.cs @@ -8,6 +8,7 @@ namespace Game.NavigationTool.Editor public GUIStyle buttonAddFolder; public GUIStyle entry; + public GUIStyle invalidEntry; public Texture2D foldoutIn; public Texture2D foldoutOut; @@ -20,6 +21,7 @@ namespace Game.NavigationTool.Editor if (this.skin == skin) return; + this.skin = skin; toolbox = new GUIStyle(skin.box); buttonAddFolder = new GUIStyle(skin.button); @@ -29,6 +31,11 @@ namespace Game.NavigationTool.Editor entry.hover.textColor = entry.onHover.textColor = Color.white; entry.active.textColor = entry.onActive.textColor = Color.yellow; + invalidEntry = new GUIStyle(entry); + invalidEntry.normal.textColor = Color.red; + invalidEntry.hover.textColor = invalidEntry.onHover.textColor = new Color(1.0f, 0.3f, 0.3f); + invalidEntry.active.textColor = invalidEntry.onActive.textColor = new Color(1.0f, 0.0f, 0.5f); + GUIStyle style = skin.FindStyle("Foldout"); if (style != null) diff --git a/package.json b/package.json index a72dda0..0d24a71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.module.navigationtool", - "version": "0.1.0", + "version": "0.2.0", "displayName": "Module.NavigationTool", "description": "Support for navigation tools", "unity": "2019.2",