123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using UnityEditor;
- using UnityEngine;
- using Object = UnityEngine.Object;
- namespace EnhancedHierarchy
- {
- /// <summary>
- /// Main class, draws hierarchy items.
- /// </summary>
- [InitializeOnLoad]
- public static partial class EnhancedHierarchy
- {
- private static MiniLabelProvider[] MiniLabelProviders
- {
- get { return Preferences.miniLabelProviders; }
- }
- static EnhancedHierarchy()
- {
- if (Preferences.DebugEnabled || Preferences.ProfilingEnabled)
- {
- Utility.EnableFPSCounter();
- Utility.ForceUpdateHierarchyEveryFrame();
- }
- EditorApplication.hierarchyWindowItemOnGUI += SetItemInformation;
- EditorApplication.hierarchyWindowItemOnGUI += OnItemGUI;
- EditorApplication.RepaintHierarchyWindow();
- }
- private static void OnItemGUI(int id, Rect rect)
- {
- if (!Preferences.Enabled)
- return;
- bool isActivie = EditorPrefs.GetBool("isActiveObjectTool", false);
- if (!isActivie)
- {
- return;
- }
- using (ProfilerSample.Get("Enhanced Hierarchy"))
- try
- {
- if (IsGameObject)
- {
- for (var i = 0; i < Preferences.RightIcons.Value.Count; i++)
- Preferences.RightIcons.Value[i].SafeInit();
- for (var i = 0; i < Preferences.LeftIcons.Value.Count; i++)
- Preferences.LeftIcons.Value[i].SafeInit();
- Preferences.LeftSideButton.SafeInit();
- for (var i = 0; i < MiniLabelProviders.Length; i++)
- {
- MiniLabelProviders[i].Init();
- }
- }
- if (IsFirstVisible && Reflected.HierarchyArea.Supported)
- {
- Reflected.HierarchyArea.IndentWidth = Preferences.Indent;
- Reflected.HierarchyArea.BaseIndent = Preferences.LeftMargin;
- }
- //SetTitle("EH 2.0");
- CalculateIconsWidth();
- DoSelection(RawRect);
- IgnoreLockedSelection();
- DrawTree(RawRect);
- ChildToggle();
- var trailingWidth = DoTrailing();
- DrawHover();
- ColorSort(RawRect);
- DrawLeftSideIcons(RawRect);
- DrawTooltip(RawRect, trailingWidth);
- if (Reflected.IconWidthSupported)
- Reflected.IconWidth = Preferences.DisableNativeIcon ? 0 : 16;
- if (IsGameObject)
- {
- rect.xMax -= Preferences.RightMargin;
- rect.xMin = rect.xMax;
- rect.y++;
- for (var i = 0; i < Preferences.RightIcons.Value.Count; i++)
- using (new GUIBackgroundColor(Styles.backgroundColorEnabled))
- {
- var icon = Preferences.RightIcons.Value[i];
- rect.xMin -= icon.SafeGetWidth();
- icon.SafeDoGUI(rect);
- rect.xMax -= icon.SafeGetWidth();
- }
- var leftSideRect = RawRect;
- if (Preferences.LeftmostButton)
- leftSideRect.xMin = 0f;
- else
- leftSideRect.xMin -= 2f + CurrentGameObject.transform.childCount > 0 || Preferences.TreeOpacity > ALPHA_THRESHOLD ? 30f : 18f;
- leftSideRect.xMax = leftSideRect.xMin + Preferences.LeftSideButton.SafeGetWidth();
- using (new GUIBackgroundColor(Styles.backgroundColorEnabled))
- Preferences.LeftSideButton.SafeDoGUI(leftSideRect);
- }
- DrawMiniLabel(ref rect);
- DrawHorizontalSeparator(RawRect);
- }
- catch (Exception e)
- {
- Utility.LogException(e);
- }
- }
- private static void DrawHover()
- {
- if (Reflected.NativeHierarchyHoverTintSupported)
- {
- if (IsFirstVisible && IsRepaintEvent)
- Reflected.NativeHierarchyHoverTint = Preferences.HoverTintColor;
- return;
- }
- var tint = Preferences.HoverTintColor.Value;
- if (IsFirstVisible && Reflected.NativeHierarchyHoverTintSupported)
- Reflected.HierarchyWindowInstance.wantsMouseMove = tint.a >= ALPHA_THRESHOLD;
- if (tint.a < ALPHA_THRESHOLD)
- return;
- if (!Utility.ShouldCalculateTooltipAt(FullSizeRect))
- return;
- if (IsRepaintEvent)
- EditorGUI.DrawRect(FullSizeRect, tint);
- switch (Event.current.type)
- {
- case EventType.MouseMove:
- Event.current.Use();
- break;
- }
- }
- private static void IgnoreLockedSelection()
- {
- if (Preferences.AllowSelectingLockedObjects || !IsFirstVisible || !IsRepaintEvent)
- return;
- using (ProfilerSample.Get())
- {
- var selection = Selection.objects;
- var changed = false;
- for (var i = 0; i < selection.Length; i++)
- if (selection[i] is GameObject && (selection[i].hideFlags & HideFlags.NotEditable) != 0 && !EditorUtility.IsPersistent(selection[i]))
- {
- selection[i] = null;
- changed = true;
- }
- if (changed)
- {
- Selection.objects = selection;
- Reflected.SetHierarchySelectionNeedSync();
- EditorApplication.RepaintHierarchyWindow();
- }
- }
- }
- private static void ChildToggle()
- {
- using (ProfilerSample.Get())
- {
- if (!Preferences.NumericChildExpand || !IsRepaintEvent || !IsGameObject || CurrentGameObject.transform.childCount <= 0)
- return;
- var rect = RawRect;
- var childString = CurrentGameObject.transform.childCount.ToString("00");
- var expanded = Reflected.GetTransformIsExpanded(CurrentGameObject);
- rect.xMax = rect.xMin - 1f;
- rect.xMin -= 15f;
- if (childString.Length > 2)
- rect.xMin -= 4f;
- using (new GUIBackgroundColor(Styles.childToggleColor))
- Styles.newToggleStyle.Draw(rect, Utility.GetTempGUIContent(childString), false, false, expanded, false);
- }
- }
- private static void DrawHorizontalSeparator(Rect rect)
- {
- if (Preferences.LineSize < 1 || Preferences.LineColor.Value.a <= ALPHA_THRESHOLD || !IsRepaintEvent)
- return;
- using (ProfilerSample.Get())
- {
- rect.xMin = 0f;
- rect.xMax = rect.xMax + 50f;
- rect.yMin -= Preferences.LineSize / 2;
- rect.yMax = rect.yMin + Preferences.LineSize;
- EditorGUI.DrawRect(rect, Preferences.LineColor);
- if (!IsFirstVisible)
- return;
- rect.y = FinalRect.y - Preferences.LineSize / 2;
- var height = Reflected.HierarchyWindowInstance.position.height;
- var count = (height - FinalRect.y) / FinalRect.height;
- if (FinalRect.height <= 0f)
- count = 100f;
- for (var i = 0; i < count; i++)
- {
- rect.y += RawRect.height;
- EditorGUI.DrawRect(rect, Preferences.LineColor);
- }
- }
- }
- private static void ColorSort(Rect rect)
- {
- if (!IsRepaintEvent)
- return;
- using (ProfilerSample.Get())
- {
- rect.xMin = 0f;
- rect.xMax = rect.xMax + 50f;
- var rowTint = GetRowTint();
- var rowCustomTint = GetRowCustomTint();
- if (rowCustomTint.color.a > ALPHA_THRESHOLD)
- using (new GUIColor(rowCustomTint.color))
- {
- switch (rowCustomTint.mode)
- {
- case TintMode.Flat:
- EditorGUI.DrawRect(rect, Color.white);
- break;
- case TintMode.GradientLeftToRight:
- GUI.DrawTexture(Utility.FlipRectHorizontally(rect), Styles.fadeTexture, ScaleMode.StretchToFill);
- break;
- case TintMode.GradientRightToLeft:
- GUI.DrawTexture(rect, Styles.fadeTexture, ScaleMode.StretchToFill);
- break;
- }
- }
- if (rowTint.a > ALPHA_THRESHOLD)
- EditorGUI.DrawRect(rect, rowTint);
- if (!IsFirstVisible)
- return;
- rect.y = FinalRect.y;
- var height = Reflected.HierarchyWindowInstance.position.height;
- var count = (height - FinalRect.y) / FinalRect.height;
- if (FinalRect.height <= 0f)
- count = 100f;
- for (var i = 0; i < count; i++)
- {
- rect.y += RawRect.height;
- rowTint = GetRowTint(rect);
- if (rowTint.a > ALPHA_THRESHOLD)
- EditorGUI.DrawRect(rect, rowTint);
- }
- }
- }
- private static void DrawTree(Rect rect)
- {
- if (Preferences.TreeOpacity <= ALPHA_THRESHOLD || !IsGameObject)
- return;
- if (!IsRepaintEvent && !Preferences.SelectOnTree)
- return;
- using (ProfilerSample.Get())
- using (new GUIColor(Utility.GetHierarchyColor(CurrentGameObject.transform.parent), Preferences.TreeOpacity))
- {
- var indent = Reflected.HierarchyArea.Supported ? Reflected.HierarchyArea.IndentWidth : 16f;
- // #42 - Jules: pull back indent one level and neatly align tree lines with expansion arrow tips
- rect.x -= indent + 2f;
- rect.xMin -= 14f;
- rect.xMax = rect.xMin + 14f;
- // #42 - Jules: allow showing of stems for container objects
- if (CurrentGameObject.transform.parent)
- {
- var lastInHierarchy = Utility.TransformIsLastChild(CurrentGameObject.transform);
- GUI.DrawTexture(rect, lastInHierarchy ? Styles.treeElbowTexture : Styles.treeTeeTexture);
- /*
- #42 - Jules: add short horizontal line to extend stem if there's no expansion triangle.
- NOTE: Please make this value into a slider in the preferences, since it's arguably a bad thing to have it.
- It looks "nicer" with extended stems but is less clear since it throws off the stem alignments.
- At a value of 1 this can make things look an entire level off of where they truly are relative to other things!!!
- I think 0.5 is an okay compromise, but 0 is the most consistent, which means no extra stem line at all.
- So it's the sort of thing where people might have different ideas of what's best for them...
- */
- var extendStemProportion = CurrentGameObject.transform.childCount == 0 ? Preferences.TreeStemProportion.Value * indent : indent - 14f;
- if (extendStemProportion > 0.01f)
- {
- var extendedStemRect = new Rect(rect.x + rect.size.x, rect.y + (lastInHierarchy ? 9f : 8f), extendStemProportion, 1f);
- EditorGUI.DrawRect(extendedStemRect, Color.white);
- }
- if (Preferences.SelectOnTree && GUI.Button(rect, GUIContent.none, Styles.labelNormal))
- Selection.activeTransform = CurrentGameObject.transform.parent;
- }
- var currentTransform = CurrentGameObject.transform.parent;
- for (rect.x -= indent; rect.xMin > 0f && currentTransform && currentTransform.parent; rect.x -= indent)
- {
- if (!Utility.TransformIsLastChild(currentTransform))
- using (new GUIColor(Utility.GetHierarchyColor(currentTransform.parent), Preferences.TreeOpacity))
- {
- GUI.DrawTexture(rect, Styles.treeLineTexture);
- if (Preferences.SelectOnTree && GUI.Button(rect, GUIContent.none, Styles.labelNormal))
- Selection.activeTransform = currentTransform.parent;
- }
- currentTransform = currentTransform.parent;
- }
- }
- }
- private static void CalculateIconsWidth()
- {
- using (ProfilerSample.Get())
- {
- LeftIconsWidth = 0f;
- RightIconsWidth = 0f;
- if (!IsGameObject)
- return;
- for (var i = 0; i < Preferences.RightIcons.Value.Count; i++)
- RightIconsWidth += Preferences.RightIcons.Value[i].SafeGetWidth();
- for (var i = 0; i < Preferences.LeftIcons.Value.Count; i++)
- LeftIconsWidth += Preferences.LeftIcons.Value[i].SafeGetWidth();
- }
- }
- private static void DrawLeftSideIcons(Rect rect)
- {
- if (!IsGameObject)
- return;
- using (ProfilerSample.Get())
- {
- rect.xMin += LabelSize;
- rect.xMin = Math.Min(rect.xMax - RightIconsWidth - LeftIconsWidth - CalcMiniLabelSize() - 5f - Preferences.RightMargin, rect.xMin);
- for (var i = 0; i < Preferences.LeftIcons.Value.Count; i++)
- using (new GUIBackgroundColor(Styles.backgroundColorEnabled))
- {
- var icon = Preferences.LeftIcons.Value[i];
- rect.xMax = rect.xMin + icon.SafeGetWidth();
- icon.SafeDoGUI(rect);
- rect.xMin = rect.xMax;
- }
- }
- }
- private static float DoTrailing()
- {
- if (!IsRepaintEvent || !Preferences.Trailing || !IsGameObject)
- return RawRect.xMax;
- using (ProfilerSample.Get())
- {
- var size = LabelSize; // CurrentStyle.CalcSize(Utility.GetTempGUIContent(GameObjectName)).x;
- var iconsWidth = RightIconsWidth + LeftIconsWidth + CalcMiniLabelSize() + Preferences.RightMargin;
- var iconsMin = FullSizeRect.xMax - iconsWidth;
- var labelMax = LabelOnlyRect.xMax;
- var overlapping = iconsMin <= labelMax;
- if (!overlapping)
- return labelMax;
- var rect = FullSizeRect;
- rect.xMin = iconsMin - 18;
- rect.xMax = labelMax;
- if (Selection.gameObjects.Contains(CurrentGameObject))
- EditorGUI.DrawRect(rect, Reflected.HierarchyFocused ? Styles.selectedFocusedColor : Styles.selectedUnfocusedColor);
- else
- EditorGUI.DrawRect(rect, Styles.normalColor);
- rect.y++;
- using (new GUIColor(CurrentColor))
- EditorStyles.boldLabel.Draw(rect, trailingContent, 0);
- return iconsMin;
- }
- }
- private static void DrawMiniLabel(ref Rect rect)
- {
- if (!IsGameObject)
- return;
- rect.x -= 3f;
- using (ProfilerSample.Get())
- switch (MiniLabelProviders.Length)
- {
- case 0:
- return;
- case 1:
- if (MiniLabelProviders[0].HasValue())
- MiniLabelProviders[0].Draw(ref rect);
- break;
- default:
- var ml0 = MiniLabelProviders[0];
- var ml1 = MiniLabelProviders[1];
- var ml0HasValue = ml0.HasValue();
- var ml1HasValue = ml1.HasValue();
- if (ml0HasValue && ml1HasValue || !Preferences.CentralizeMiniLabelWhenPossible)
- {
- var topRect = rect;
- var bottomRect = rect;
- topRect.yMax = RawRect.yMax - RawRect.height / 2f;
- bottomRect.yMin = RawRect.yMin + RawRect.height / 2f;
- if (ml0HasValue)
- ml0.Draw(ref topRect);
- if (ml1HasValue)
- ml1.Draw(ref bottomRect);
- rect.xMin = Mathf.Min(topRect.xMin, bottomRect.xMin);
- }
- else if (ml1HasValue)
- ml1.Draw(ref rect);
- else if (ml0HasValue)
- ml0.Draw(ref rect);
- break;
- }
- }
- private static float CalcMiniLabelSize()
- {
- Styles.miniLabelStyle.fontSize = Preferences.SmallerMiniLabel ? 8 : 9;
- using (ProfilerSample.Get())
- {
- switch (MiniLabelProviders.Length)
- {
- case 0:
- return 0f;
- case 1:
- return MiniLabelProviders[0].Measure();
- default:
- return Math.Max(
- MiniLabelProviders[0].Measure(),
- MiniLabelProviders[1].Measure()
- );
- }
- }
- }
- private static void DrawTooltip(Rect rect, float fullTrailingWidth)
- {
- if (!Preferences.Tooltips || !IsGameObject || !IsRepaintEvent)
- return;
- using (ProfilerSample.Get())
- {
- if (DragSelection != null)
- return;
- rect.xMax = Mathf.Min(fullTrailingWidth, rect.xMin + LabelSize);
- rect.xMin = 0f;
- if (!Utility.ShouldCalculateTooltipAt(rect))
- return;
- var tooltip = new StringBuilder(100);
- tooltip.AppendLine(GameObjectName);
- tooltip.AppendFormat("\nTag: {0}", GameObjectTag);
- tooltip.AppendFormat("\nLayer: {0}", LayerMask.LayerToName(CurrentGameObject.layer));
- if (GameObjectUtility.GetStaticEditorFlags(CurrentGameObject) != 0)
- tooltip.AppendFormat("\nStatic: {0}", Utility.EnumFlagsToString(GameObjectUtility.GetStaticEditorFlags(CurrentGameObject)));
- tooltip.AppendLine();
- tooltip.AppendLine();
- foreach (var component in Components)
- if (component is Transform)
- continue;
- else if (component)
- tooltip.AppendLine(ObjectNames.GetInspectorTitle(component));
- else
- tooltip.AppendLine("Missing Component");
- EditorGUI.LabelField(rect, Utility.GetTempGUIContent(null, tooltip.ToString().TrimEnd('\n', '\r')));
- }
- }
- private static void DoSelection(Rect rect)
- {
- if (!Preferences.EnhancedSelectionSupported || !Preferences.EnhancedSelection || Event.current.button != 1)
- {
- DragSelection = null;
- return;
- }
- using (ProfilerSample.Get())
- {
- rect.xMin = 0f;
- switch (Event.current.type)
- {
- case EventType.MouseDrag:
- if (!IsFirstVisible)
- return;
- if (DragSelection == null)
- {
- DragSelection = new List<Object>();
- SelectionStart = Event.current.mousePosition;
- SelectionRect = new Rect();
- }
- SelectionRect = new Rect()
- {
- xMin = Mathf.Min(Event.current.mousePosition.x, SelectionStart.x),
- yMin = Mathf.Min(Event.current.mousePosition.y, SelectionStart.y),
- xMax = Mathf.Max(Event.current.mousePosition.x, SelectionStart.x),
- yMax = Mathf.Max(Event.current.mousePosition.y, SelectionStart.y)
- };
- if (Event.current.control || Event.current.command)
- DragSelection.AddRange(Selection.objects);
- Selection.objects = DragSelection.ToArray();
- Event.current.Use();
- break;
- case EventType.MouseUp:
- if (DragSelection != null)
- Event.current.Use();
- DragSelection = null;
- break;
- case EventType.Repaint:
- if (DragSelection == null || !IsFirstVisible)
- break;
- Rect scrollRect;
- if (Event.current.mousePosition.y > FinalRect.y)
- {
- scrollRect = FinalRect;
- scrollRect.y += scrollRect.height;
- }
- else if (Event.current.mousePosition.y < RawRect.y)
- {
- scrollRect = RawRect;
- scrollRect.y -= scrollRect.height;
- }
- else
- break;
- SelectionRect = new Rect()
- {
- xMin = Mathf.Min(scrollRect.xMax, SelectionStart.x),
- yMin = Mathf.Min(scrollRect.yMax, SelectionStart.y),
- xMax = Mathf.Max(scrollRect.xMax, SelectionStart.x),
- yMax = Mathf.Max(scrollRect.yMax, SelectionStart.y)
- };
- if (Event.current.control || Event.current.command)
- DragSelection.AddRange(Selection.objects);
- Selection.objects = DragSelection.ToArray();
- GUI.ScrollTowards(scrollRect, 9f);
- EditorApplication.RepaintHierarchyWindow();
- break;
- case EventType.Layout:
- if (DragSelection != null && IsGameObject)
- if (!SelectionRect.Overlaps(rect) && DragSelection.Contains(CurrentGameObject))
- DragSelection.Remove(CurrentGameObject);
- else if (SelectionRect.Overlaps(rect) && !DragSelection.Contains(CurrentGameObject))
- DragSelection.Add(CurrentGameObject);
- break;
- }
- }
- }
- public static Color GetRowTint()
- {
- return GetRowTint(RawRect);
- }
- public static Color GetRowTint(Rect rect)
- {
- using (ProfilerSample.Get())
- if (rect.y / RawRect.height % 2 >= 0.5f)
- return Preferences.OddRowColor;
- else
- return Preferences.EvenRowColor;
- }
- public static LayerColor GetRowCustomTint()
- {
- return GetRowCustomTint(CurrentGameObject);
- }
- public static LayerColor GetRowCustomTint(GameObject go)
- {
- using (ProfilerSample.Get())
- {
- if (!go)
- return new LayerColor();
- var layerColors = Preferences.PerLayerRowColors.Value;
- if (layerColors == null)
- return new LayerColor();
- var goLayer = go.layer;
- for (var i = 0; i < layerColors.Count; i++)
- if (layerColors[i] == goLayer)
- return layerColors[i];
- return new LayerColor();
- }
- }
- public static List<GameObject> GetSelectedObjectsAndCurrent()
- {
- if (!Preferences.ChangeAllSelected || Selection.gameObjects.Length <= 1)
- return new List<GameObject> {CurrentGameObject};
- var selection = new List<GameObject>(Selection.gameObjects);
- for (var i = 0; i < selection.Count; i++)
- if (EditorUtility.IsPersistent(selection[i]))
- selection.RemoveAt(i);
- if (!selection.Contains(CurrentGameObject))
- selection.Add(CurrentGameObject);
- selection.Remove(null);
- return selection;
- }
- }
- }
|