| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 | using System;using System.Linq;using System.Text;using UnityEditor;using UnityEngine;namespace EnhancedHierarchy {    /// <summary>    /// Misc utilities for Enhanced Hierarchy.    /// </summary>    public static class Utility {        private const string CTRL = "Ctrl";        private const string CMD = "Cmd";        private const string MENU_ITEM_PATH = "Edit/Enhanced Hierarchy %h";        private static int errorCount;        private static readonly GUIContent tempContent = new GUIContent();        public static string CtrlKey { get { return Application.platform == RuntimePlatform.OSXEditor ? CMD : CTRL; } }        [MenuItem(MENU_ITEM_PATH, false, int.MinValue)]        private static void EnableDisableHierarchy() {            Preferences.Enabled.Value = !Preferences.Enabled;            EditorApplication.RepaintHierarchyWindow();        }        [MenuItem(MENU_ITEM_PATH, true)]        private static bool CheckHierarchyEnabled() {            Menu.SetChecked(MENU_ITEM_PATH, Preferences.Enabled);            return true;        }        public static void EnableFPSCounter() {            var frames = 0;            var fps = 0d;            var lastTime = 0d;            var content = new GUIContent();            var evt = EventType.Repaint;            EditorApplication.hierarchyWindowItemOnGUI += (id, rect) => {                using(ProfilerSample.Get("Enhanced Hierarchy"))                using(ProfilerSample.Get("FPS Counter")) {                    if (evt == Event.current.type)                        return;                    evt = Event.current.type;                    if (evt == EventType.Repaint)                        frames++;                    if (EditorApplication.timeSinceStartup - lastTime < 0.5d)                        return;                    fps = frames / (EditorApplication.timeSinceStartup - lastTime);                    lastTime = EditorApplication.timeSinceStartup;                    frames = 0;                    content.text = string.Format("{0:00.0} FPS", fps);                    content.image = Styles.warningIcon;                    SetHierarchyTitle(content);                }            };        }        public static bool ShouldCalculateTooltipAt(Rect area) {            return area.Contains(Event.current.mousePosition);        }        public static void ForceUpdateHierarchyEveryFrame() {            // EditorApplication.update += () => {            //     if(EditorWindow.mouseOverWindow)            //         EditorApplication.RepaintHierarchyWindow();            // };        }        public static void LogException(Exception e) {            Debug.LogError("Unexpected exception in Enhanced Hierarchy");            Debug.LogException(e);            if (errorCount++ >= 10) {                Debug.LogWarning("Automatically disabling Enhanced Hierarchy, if the error persists contact the developer");                Preferences.Enabled.Value = false;                errorCount = 0;                if (!EditorPrefs.GetBool("EHEmailAskDisabled", false))                    switch (EditorUtility.DisplayDialogComplex("Mail Developer", "Enhanced Hierarchy has found an exeption, would you like to report a bug to the developer? (If you choose yes your mail app will open with a few techinical information)", "Yes", "Not now", "No and don't ask again")) {                        case 0:                            Preferences.OpenSupportEmail(e);                            EditorUtility.DisplayDialog("Mail Developer", "Your mail app will open now, if it doesn't please send an email reporting the bug to " + Preferences.DEVELOPER_EMAIL, "OK");                            break;                        case 1:                            break;                        case 2:                            EditorPrefs.SetBool("EHEmailAskDisabled", true);                            EditorUtility.DisplayDialog("Mail Developer", "You won't be bothered again, sorry", "OK");                            break;                    }            }        }        public static void SetHierarchyTitle(string title) {            try {                Reflected.HierarchyWindowInstance.titleContent.text = title;            } catch (Exception e) {                Debug.LogWarning("Failed to set hierarchy title: " + e);            }        }        public static void SetHierarchyTitle(GUIContent content) {            try {                Reflected.HierarchyWindowInstance.titleContent = content;            } catch (Exception e) {                Debug.LogWarning("Failed to set hierarchy title: " + e);            }        }        public static GUIStyle CreateStyleFromTextures(Texture2D on, Texture2D off) {            return CreateStyleFromTextures(null, on, off);        }        public static GUIStyle CreateStyleFromTextures(GUIStyle reference, Texture2D on, Texture2D off) {            using(ProfilerSample.Get()) {                var style = reference != null ? new GUIStyle(reference) : new GUIStyle();                style.active.background = off;                style.focused.background = off;                style.hover.background = off;                style.normal.background = off;                style.onActive.background = on;                style.onFocused.background = on;                style.onHover.background = on;                style.onNormal.background = on;                style.imagePosition = ImagePosition.ImageOnly;                EditorApplication.update += () => {                    style.fixedHeight = Preferences.IconsSize;                    style.fixedWidth = Preferences.IconsSize;                };                return style;            }        }        public static Texture2D GetBackground(GUIStyle style, bool on) {            return on ?                style.onNormal.background :                style.normal.background;        }        public static Texture2D FindOrLoad(string base64) {            var name = string.Format("Enhanced_Hierarchy_{0}", (long)base64.GetHashCode() - int.MinValue);            return FindTextureFromName(name) ?? LoadTexture(base64, name);        }        public static Texture2D LoadTexture(string base64, string name) {            using(ProfilerSample.Get())            try {                var bytes = Convert.FromBase64String(base64);                var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false, false);                texture.name = name;                texture.hideFlags = HideFlags.HideAndDontSave;                texture.LoadImage(bytes);                return texture;            } catch (Exception e) {                Debug.LogErrorFormat("Failed to load texture \"{0}\": {1}", name, e);                return null;            }        }        public static Texture2D FindTextureFromName(string name) {            using(ProfilerSample.Get())            try {                var textures = Resources.FindObjectsOfTypeAll<Texture2D>();                for (var i = 0; i < textures.Length; i++)                    if (textures[i].name == name)                        return textures[i];                return null;            } catch (Exception e) {                Debug.LogErrorFormat("Failed to find texture \"{0}\": {1}", name, e);                return null;            }        }        public static Color GetHierarchyColor(Transform t) {            if (!t)                return Color.clear;            return GetHierarchyColor(t.gameObject);        }        public static Color GetHierarchyColor(GameObject go) {            if (!go)                return Color.black;            return GetHierarchyLabelStyle(go).normal.textColor;        }        public static GUIStyle GetHierarchyLabelStyle(GameObject go) {            using(ProfilerSample.Get()) {                if (!go)                    return EditorStyles.label;                var active = go.activeInHierarchy;                #if UNITY_2018_3_OR_NEWER                var prefabType = PrefabUtility.GetPrefabInstanceStatus(go);                switch (prefabType) {                    case PrefabInstanceStatus.Connected:                        return active ? Styles.labelPrefab : Styles.labelPrefabDisabled;                    case PrefabInstanceStatus.MissingAsset:                        return active ? Styles.labelPrefabBroken : Styles.labelPrefabBrokenDisabled;                    default:                        return active ? Styles.labelNormal : Styles.labelDisabled;                }                #else                var prefabType = PrefabUtility.GetPrefabType(PrefabUtility.FindPrefabRoot(go));                switch (prefabType) {                    case PrefabType.PrefabInstance:                    case PrefabType.ModelPrefabInstance:                        return active ? Styles.labelPrefab : Styles.labelPrefabDisabled;                    case PrefabType.MissingPrefabInstance:                        return active ? Styles.labelPrefabBroken : Styles.labelPrefabBrokenDisabled;                    default:                        return active ? Styles.labelNormal : Styles.labelDisabled;                }                #endif            }        }        public static Color OverlayColors(Color src, Color dst) {            using(ProfilerSample.Get()) {                var alpha = dst.a + src.a * (1f - dst.a);                var result = (dst * dst.a + src * src.a * (1f - dst.a)) / alpha;                result.a = alpha;                return result;            }        }        public static bool TransformIsLastChild(Transform t) {            using(ProfilerSample.Get()) {                if (!t)                    return true;                return t.GetSiblingIndex() == t.parent.childCount - 1;            }        }        public static void ApplyHideFlagsToPrefab(UnityEngine.Object obj) {            var handle = PrefabUtility.GetPrefabInstanceHandle(obj);            if (handle)                handle.hideFlags = obj.hideFlags;        }        public static void LockObject(GameObject go) {            using(ProfilerSample.Get()) {                go.hideFlags |= HideFlags.NotEditable;                ApplyHideFlagsToPrefab(go);                #if UNITY_2019_3_OR_NEWER                if (!Preferences.AllowPickingLockedObjects)                    SceneVisibilityManager.instance.DisablePicking(go, false);                #endif                EditorUtility.SetDirty(go);            }        }        public static void UnlockObject(GameObject go) {            using(ProfilerSample.Get()) {                go.hideFlags &= ~HideFlags.NotEditable;                ApplyHideFlagsToPrefab(go);                #if UNITY_2019_3_OR_NEWER                if (!Preferences.AllowPickingLockedObjects)                    SceneVisibilityManager.instance.EnablePicking(go, false);                #endif                EditorUtility.SetDirty(go);            }        }        // public static void UnlockAllObjects() {        //     using(ProfilerSample.Get())        //     foreach (var objRaw in Resources.FindObjectsOfTypeAll<GameObject>()) {        //         var obj = ObjectOrPrefabInstanceHandle(objRaw);        //         if (obj && (obj.hideFlags & HideFlags.HideInHierarchy) == 0 && !EditorUtility.IsPersistent(obj))        //             UnlockObject(obj);        //     }        // }        public static void ApplyPrefabModifications(GameObject go, bool allowCreatingNew) {            #if UNITY_2018_3_OR_NEWER            var isPrefab = PrefabUtility.IsPartOfAnyPrefab(go);            #else            var isPrefab = PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance;            #endif            if (isPrefab) {                #if UNITY_2018_3_OR_NEWER                var prefab = PrefabUtility.GetNearestPrefabInstanceRoot(go);                #elif UNITY_2018_2_OR_NEWER                var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go);                #else                var prefab = PrefabUtility.GetPrefabParent(go);                #endif                if (!prefab) {                    Debug.LogError("Prefab asset not valid!");                    return;                }                #if UNITY_2018_3_OR_NEWER                if (PrefabUtility.GetPrefabInstanceStatus(prefab) == PrefabInstanceStatus.Connected)                    PrefabUtility.ApplyPrefabInstance(prefab, InteractionMode.UserAction);                else if (EditorUtility.DisplayDialog("Apply disconnected prefab", "This is a disconnected game object, do you want to try to reconnect to the last prefab asset?", "Try to Reconnect", "Cancel"))                    PrefabUtility.RevertPrefabInstance(prefab, InteractionMode.UserAction);                EditorUtility.SetDirty(prefab);                #else                var selection = Selection.instanceIDs;                Selection.activeGameObject = go;                if (EditorApplication.ExecuteMenuItem("GameObject/Apply Changes To Prefab")) {                    EditorUtility.SetDirty(prefab);                    Selection.instanceIDs = selection;                } else                    Debug.LogError("Failed to apply prefab modifications");                #endif            } else if (allowCreatingNew) {                var path = EditorUtility.SaveFilePanelInProject("Save prefab", "New Prefab", "prefab", "Save the selected prefab");                if (!string.IsNullOrEmpty(path))                    #if UNITY_2018_3_OR_NEWER                    PrefabUtility.SaveAsPrefabAssetAndConnect(go, path, InteractionMode.UserAction);                #else                PrefabUtility.CreatePrefab(path, go, ReplacePrefabOptions.ConnectToPrefab);                #endif            }        }        public static string EnumFlagsToString(Enum value) {            using(ProfilerSample.Get())            try {                if ((int)(object)value == -1)                    return "Everything";                var str = new StringBuilder();                var separator = ", ";                foreach (var enumValue in Enum.GetValues(value.GetType())) {                    var i = (int)enumValue;                    if (i != 0 && (i & (i - 1)) == 0 && Enum.IsDefined(value.GetType(), i) && (Convert.ToInt32(value) & i) != 0) {                        str.Append(ObjectNames.NicifyVariableName(enumValue.ToString()));                        str.Append(separator);                    }                }                if (str.Length > 0)                    str.Length -= separator.Length;                return str.ToString();            } catch (Exception e) {                if (Preferences.DebugEnabled)                    Debug.LogException(e);                return string.Empty;            }        }        public static GUIContent GetTempGUIContent(string text, string tooltip = null, Texture2D image = null) {            tempContent.text = text;            tempContent.tooltip = tooltip;            tempContent.image = image;            return tempContent;        }        public static string SafeGetName(this IconBase icon) {            try {                return icon.Name;            } catch (Exception e) {                Debug.LogException(e);                Preferences.ForceDisableButton(icon);                return string.Empty;            }        }        public static float SafeGetWidth(this IconBase icon) {            try {                return icon.Width + (Preferences.IconsSize - 15) / 2;            } catch (Exception e) {                Debug.LogException(e);                Preferences.ForceDisableButton(icon);                return 0f;            }        }        public static void SafeInit(this IconBase icon) {            try {                icon.Init();            } catch (Exception e) {                Debug.LogException(e);                Preferences.ForceDisableButton(icon);            }        }        public static void SafeDoGUI(this IconBase icon, Rect rect) {            try {                rect.yMin -= (Preferences.IconsSize - 15) / 2;                rect.xMin -= (Preferences.IconsSize - 15) / 2;                icon.DoGUI(rect);            } catch (Exception e) {                Debug.LogException(e);                Preferences.ForceDisableButton(icon);            }        }        public static Rect FlipRectHorizontally(Rect rect) {            return Rect.MinMaxRect(                rect.xMax,                rect.yMin,                rect.xMin,                rect.yMax            );        }    }}
 |