Last active
November 26, 2022 07:17
-
-
Save liveasnotes/2a0a1cc75fabbebaba38164f24747918 to your computer and use it in GitHub Desktop.
unity editor extension: Hierarchy Objects Alphabetical Sorter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright 2022-2023 liveanotes | |
| // Released under the MIT license. | |
| // see https://opensource.org/licenses/MIT | |
| using UnityEngine; | |
| using UnityEditor; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| namespace liveasnotes.Unity.EditorExtension.HOAS | |
| { | |
| [InitializeOnLoad] | |
| static class Preferences | |
| { | |
| const string _PREF_KEY_LIVEASNOTES_HIERARCHY_OBJECTS_ALPHABETICAL_SORTING_AUTOMATED = "liveasnotes_HierarchyObjectsAlphabeticalSorting_Automated"; | |
| // cf. https://forum.unity.com/threads/editorprefs-pre-defined-magic-strings.414017/ | |
| public static bool isSiblingIndexAlphabeticalSortingAutomated | |
| { | |
| get => EditorPrefs.GetBool(_PREF_KEY_LIVEASNOTES_HIERARCHY_OBJECTS_ALPHABETICAL_SORTING_AUTOMATED); | |
| set | |
| { | |
| EditorPrefs.SetBool(_PREF_KEY_LIVEASNOTES_HIERARCHY_OBJECTS_ALPHABETICAL_SORTING_AUTOMATED, value); | |
| if (isSiblingIndexAlphabeticalSortingAutomated) | |
| { | |
| HierarchyObjectsAlphabeticalSorter.SortAlphabetically(Resources.FindObjectsOfTypeAll<Transform>(), true); | |
| } | |
| } | |
| } | |
| [SettingsProvider] | |
| static SettingsProvider CreatePreferencesView() | |
| { | |
| SettingsProvider provider = new SettingsProvider("Preferences/あ_liveasnotes.HOAS", SettingsScope.User) | |
| // The character string that is following "Preferences/" determines the order in the item list. | |
| { | |
| label = "liveasnotes.HOAS", | |
| guiHandler = (searchText) => | |
| { | |
| isSiblingIndexAlphabeticalSortingAutomated = EditorGUILayout.ToggleLeft(" Automate HOAS(Hierarchy Objects Alphabetical Sorter).", isSiblingIndexAlphabeticalSortingAutomated); | |
| GUILayout.Space(10); | |
| EditorGUILayout.LabelField("--- README ---"); | |
| EditorGUILayout.HelpBox("Recommend: DISABLE the toggle of Preferences > General > Enable Alphanumeric Sorting if you have enabled the toggle; otherwise, you can not recognize the result of this automated sorting feature.", MessageType.Warning); | |
| EditorGUILayout.HelpBox("Manual sorting (default shortcut keys: Alt+L and Shift+Alt+L) supports the undo feature of Unity Editor.", MessageType.Info); | |
| EditorGUILayout.HelpBox("Automated sorting does NOT support the undo feature to prevent user confusion.", MessageType.Info); | |
| EditorGUILayout.HelpBox("Automated sorting does NOT handle the items of canvas to prevent unexpected modification of layer sorting order for UI.", MessageType.Info); | |
| }, | |
| keywords = new HashSet<string>(new[] { "Hierarchy", "Object", "Alphabet", "Sort", "Order" }) | |
| }; | |
| return provider; | |
| } | |
| } | |
| [InitializeOnLoad] | |
| public class HierarchyObjectsAlphabeticalSorter | |
| { | |
| // cf. https://sleepygamersmemo.blogspot.com/2018/08/unity-sort-hierarchy.html | |
| static bool isProcessOngoing = false; | |
| static bool hasSiblingIndexChanged = false; | |
| static HierarchyObjectsAlphabeticalSorter() | |
| { | |
| EditorApplication.hierarchyChanged += OnHierarchyChanged; | |
| } | |
| static void OnHierarchyChanged() | |
| { | |
| if (Preferences.isSiblingIndexAlphabeticalSortingAutomated) | |
| { | |
| if (hasSiblingIndexChanged) | |
| { | |
| hasSiblingIndexChanged = false; | |
| } | |
| else if (!isProcessOngoing) | |
| { | |
| SortAlphabetically(Resources.FindObjectsOfTypeAll<Transform>()); | |
| } | |
| } | |
| } | |
| public static void SortAlphabetically(Transform[] _transforms, bool _isCalledManually = false, bool _isCanvasIgnored = true) | |
| { | |
| isProcessOngoing = true; | |
| foreach (IGrouping<Transform, Transform> siblings in _transforms.GroupBy(_obj => _obj.parent)) | |
| { | |
| if (_isCanvasIgnored && siblings.Key && siblings.Key.TryGetComponent(out Canvas canvas)) | |
| // `siblings.Key` -> Avoid Null Reference Exception caused by that the root object has null parent. | |
| // `*.TryGetComponent(out Canvas *)` -> Check whether it is canvas to avoid sorting its item. | |
| { | |
| continue; | |
| } | |
| else | |
| { | |
| int i = 0; | |
| foreach (Transform t in siblings.OrderBy(_obj => _obj.name)) | |
| { | |
| if (_isCalledManually) | |
| { | |
| Undo.RecordObject(t, "Manual Sort"); | |
| Undo.SetTransformParent(t, t.parent, "Manual Sort"); | |
| } | |
| t.SetSiblingIndex(i); | |
| i++; | |
| } | |
| } | |
| } | |
| hasSiblingIndexChanged = true; | |
| // - The all above modifications with SetSiblingIndex() are stacked on `hierarchyChanged` | |
| // and the event seems to be called just once after exiting `EditorApplication.update`. | |
| // - This flag is set for a workaround to skip the process | |
| // that causes an endless loop of modification. | |
| isProcessOngoing = false; | |
| } | |
| [MenuItem("Edit / Sort Alphabetically &L")] | |
| // Alt + L | |
| public static void SortManually() | |
| { | |
| SortAlphabetically(Selection.transforms, true); | |
| } | |
| [MenuItem("Edit / Sort Alphabetically (also Canvas Children) #&L")] | |
| // Shift + Alt + L | |
| public static void ForceSortManually() | |
| { | |
| SortAlphabetically(Selection.transforms, true, false); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment