1876 lines
72 KiB
C#
1876 lines
72 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using UnityEditor;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEditor.Experimental.SceneManagement;
|
|
using UnityEditorInternal;
|
|
using UnityEditor.Callbacks;
|
|
using UnityEditor.UIElements;
|
|
using UnityEditor.IMGUI.Controls;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace Hierarchy2
|
|
{
|
|
[InitializeOnLoad]
|
|
public sealed class HierarchyEditor
|
|
{
|
|
internal const int GLOBAL_SPACE_OFFSET_LEFT = 16 * 2;
|
|
|
|
static HierarchyEditor instance;
|
|
|
|
public static HierarchyEditor Instance
|
|
{
|
|
get
|
|
{
|
|
if (instance == null)
|
|
instance = new HierarchyEditor();
|
|
return instance;
|
|
}
|
|
private set { instance = value; }
|
|
}
|
|
|
|
Dictionary<int, UnityEngine.Object> selectedComponents = new Dictionary<int, UnityEngine.Object>();
|
|
Dictionary<string, string> dicComponents = new Dictionary<string, string>(StringComparer.Ordinal);
|
|
UnityEngine.Object activeComponent;
|
|
|
|
GUIContent tooltipContent = new GUIContent();
|
|
|
|
HierarchySettings settings;
|
|
HierarchyResources resources;
|
|
|
|
HierarchySettings.ThemeData ThemeData
|
|
{
|
|
get { return settings.usedTheme; }
|
|
}
|
|
|
|
int deepestRow = int.MinValue;
|
|
int previousRowIndex = int.MinValue;
|
|
|
|
int sceneIndex = 0;
|
|
Scene currentScene;
|
|
Scene previousScene;
|
|
|
|
public static bool IsMultiScene
|
|
{
|
|
get { return SceneManager.sceneCount > 1; }
|
|
}
|
|
|
|
bool selectionStyleAfterInvoke = false;
|
|
bool checkingAllHierarchy = false;
|
|
|
|
Event currentEvent;
|
|
|
|
RowItem rowItem = new RowItem();
|
|
RowItem previousElement = null;
|
|
WidthUse widthUse = WidthUse.zero;
|
|
|
|
static HierarchyEditor()
|
|
{
|
|
if (instance == null)
|
|
instance = new HierarchyEditor();
|
|
}
|
|
|
|
public HierarchyEditor()
|
|
{
|
|
InternalReflection();
|
|
EditorApplication.update += EditorAwake;
|
|
AssetDatabase.importPackageCompleted += ImportPackageCompleted;
|
|
}
|
|
|
|
static List<Type> InternalEditorType = new List<Type>();
|
|
static Dictionary<string, Type> dicInternalEditorType = new Dictionary<string, Type>();
|
|
static List<Type> DisplayOnHierarchyScriptType = new List<Type>();
|
|
static Dictionary<string, Type> dicDisplayOnHierarchyScriptType = new Dictionary<string, Type>();
|
|
|
|
static Type SceneHierarchyWindow;
|
|
static Type SceneHierarchy;
|
|
static Type GameObjectTreeViewGUI;
|
|
|
|
static FieldInfo m_SceneHierarchy;
|
|
static FieldInfo m_TreeView;
|
|
static PropertyInfo gui;
|
|
static FieldInfo k_IconWidth;
|
|
|
|
static Func<SearchableEditorWindow> lastInteractedHierarchyWindowDelegate;
|
|
static Func<IEnumerable> GetAllSceneHierarchyWindowsDelegate;
|
|
static Func<GameObject, Rect, bool, bool> IconSelectorShowAtPositionDelegate;
|
|
static Action<Rect, UnityEngine.Object, int> DisplayObjectContextMenuDelegate;
|
|
|
|
public static Action OnRepaintHierarchyWindowCallback;
|
|
public static Action OnWindowsReorderedCallback;
|
|
|
|
static void InternalReflection()
|
|
{
|
|
var arrayInteralEditorType = typeof(Editor).Assembly.GetTypes();
|
|
InternalEditorType = arrayInteralEditorType.ToList();
|
|
dicInternalEditorType = arrayInteralEditorType.ToDictionary(type => type.FullName);
|
|
|
|
FieldInfo refreshHierarchy = typeof(EditorApplication).GetField(nameof(refreshHierarchy), BindingFlags.Static | BindingFlags.NonPublic);
|
|
MethodInfo OnRepaintHierarchyWindow = typeof(HierarchyEditor).GetMethod(nameof(OnRepaintHierarchyWindow), BindingFlags.NonPublic | BindingFlags.Static);
|
|
Delegate refreshHierarchyDelegate = Delegate.CreateDelegate(typeof(EditorApplication.CallbackFunction), OnRepaintHierarchyWindow);
|
|
refreshHierarchy.SetValue(null, refreshHierarchyDelegate);
|
|
|
|
|
|
FieldInfo windowsReordered = typeof(EditorApplication).GetField(nameof(windowsReordered), BindingFlags.Static | BindingFlags.NonPublic);
|
|
MethodInfo OnWindowsReordered = typeof(HierarchyEditor).GetMethod(nameof(OnWindowsReordered), BindingFlags.NonPublic | BindingFlags.Static);
|
|
Delegate windowsReorderedDelegate = Delegate.CreateDelegate(typeof(EditorApplication.CallbackFunction), OnWindowsReordered);
|
|
windowsReordered.SetValue(null, windowsReorderedDelegate);
|
|
|
|
{
|
|
dicInternalEditorType.TryGetValue(nameof(UnityEditor) + "." + nameof(SceneHierarchyWindow), out SceneHierarchyWindow);
|
|
dicInternalEditorType.TryGetValue(nameof(UnityEditor) + "." + nameof(GameObjectTreeViewGUI), out GameObjectTreeViewGUI); //GameObjectTreeViewGUI : TreeViewGUI
|
|
dicInternalEditorType.TryGetValue(nameof(UnityEditor) + "." + nameof(SceneHierarchy), out SceneHierarchy);
|
|
}
|
|
|
|
FieldInfo s_LastInteractedHierarchy = SceneHierarchyWindow.GetField(nameof(s_LastInteractedHierarchy), BindingFlags.NonPublic | BindingFlags.Static);
|
|
|
|
MethodInfo lastInteractedHierarchyWindow = SceneHierarchyWindow.GetProperty(nameof(lastInteractedHierarchyWindow), BindingFlags.Static | BindingFlags.Public).GetGetMethod();
|
|
lastInteractedHierarchyWindowDelegate = Delegate.CreateDelegate(typeof(Func<SearchableEditorWindow>), lastInteractedHierarchyWindow) as Func<SearchableEditorWindow>;
|
|
|
|
MethodInfo GetAllSceneHierarchyWindows = SceneHierarchyWindow.GetMethod(nameof(GetAllSceneHierarchyWindows), BindingFlags.Static | BindingFlags.Public);
|
|
GetAllSceneHierarchyWindowsDelegate = Delegate.CreateDelegate(typeof(Func<IEnumerable>), GetAllSceneHierarchyWindows) as Func<IEnumerable>;
|
|
|
|
{
|
|
m_SceneHierarchy = SceneHierarchyWindow.GetField(nameof(m_SceneHierarchy), BindingFlags.NonPublic | BindingFlags.Instance);
|
|
m_TreeView = SceneHierarchy.GetField(nameof(m_TreeView), BindingFlags.NonPublic | BindingFlags.Instance);
|
|
gui = m_TreeView.FieldType.GetProperty(nameof(gui).ToLower(), BindingFlags.Public | BindingFlags.Instance);
|
|
k_IconWidth = GameObjectTreeViewGUI.GetField(nameof(k_IconWidth), BindingFlags.Public | BindingFlags.Instance);
|
|
}
|
|
|
|
MethodInfo DisplayObjectContextMenu = typeof(EditorUtility).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Single
|
|
(
|
|
method => method.Name == nameof(DisplayObjectContextMenu) && method.GetParameters()[1].ParameterType == typeof(UnityEngine.Object)
|
|
);
|
|
DisplayObjectContextMenuDelegate = Delegate.CreateDelegate(typeof(Action<Rect, UnityEngine.Object, int>), DisplayObjectContextMenu) as Action<Rect, UnityEngine.Object, int>;
|
|
|
|
|
|
Type IconSelector = typeof(EditorWindow).Assembly.GetTypes().Single(type =>
|
|
type.BaseType == typeof(EditorWindow) && type.Name == nameof(IconSelector)) as Type;
|
|
MethodInfo ShowAtPosition = IconSelector.GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Single
|
|
(
|
|
method => method.Name == nameof(ShowAtPosition) &&
|
|
method.GetParameters()[0].ParameterType == typeof(UnityEngine.Object)
|
|
);
|
|
IconSelectorShowAtPositionDelegate = Delegate.CreateDelegate(typeof(Func<GameObject, Rect, bool, bool>), ShowAtPosition) as Func<GameObject, Rect, bool, bool>;
|
|
|
|
GetItemAndRowIndexMethod = m_TreeView.FieldType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Single(method => method.Name == "GetItemAndRowIndex");
|
|
|
|
m_TreeView_IData = m_TreeView.FieldType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Single(property => property.Name == "data");
|
|
|
|
m_Rows = InternalEditorType.Find(type => type.Name == "TreeViewDataSource").GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Single(field => field.Name.Contains(nameof(m_Rows)));
|
|
}
|
|
|
|
public static IEnumerable GetAllSceneHierarchyWindows() => GetAllSceneHierarchyWindowsDelegate();
|
|
|
|
public static void DisplayObjectContextMenu(Rect rect, UnityEngine.Object unityObject, int value) => DisplayObjectContextMenuDelegate(rect, unityObject, value);
|
|
|
|
public static bool IconSelectorShowAtPosition(GameObject gameObject, Rect rect, bool value) => IconSelectorShowAtPositionDelegate(gameObject, rect, value);
|
|
|
|
private static MethodInfo GetItemAndRowIndexMethod;
|
|
private static PropertyInfo m_TreeView_IData;
|
|
private static FieldInfo m_Rows;
|
|
|
|
static void OnRepaintHierarchyWindow()
|
|
{
|
|
OnRepaintHierarchyWindowCallback?.Invoke();
|
|
}
|
|
|
|
static void OnWindowsReordered()
|
|
{
|
|
OnWindowsReorderedCallback?.Invoke();
|
|
}
|
|
|
|
void EditorAwake()
|
|
{
|
|
settings = HierarchySettings.GetAssets();
|
|
if (settings is null) return;
|
|
OnSettingsChanged(nameof(settings.components));
|
|
settings.onSettingsChanged += OnSettingsChanged;
|
|
|
|
resources = HierarchyResources.GetAssets();
|
|
if (resources is null) return;
|
|
resources.GenerateKeyForAssets();
|
|
|
|
EditorApplication.hierarchyWindowItemOnGUI += HierarchyOnGUI;
|
|
|
|
if (settings.activeHierarchy)
|
|
Invoke();
|
|
else
|
|
Dispose();
|
|
|
|
EditorApplication.update -= EditorAwake;
|
|
}
|
|
|
|
void ImportPackageCompleted(string packageName)
|
|
{
|
|
}
|
|
|
|
void OnSettingsChanged(string param)
|
|
{
|
|
switch (param)
|
|
{
|
|
case nameof(settings.components):
|
|
dicComponents.Clear();
|
|
foreach (string componentType in settings.components)
|
|
{
|
|
if (!dicComponents.ContainsKey(componentType))
|
|
dicComponents.Add(componentType, componentType);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
EditorApplication.RepaintHierarchyWindow();
|
|
}
|
|
|
|
public void Invoke()
|
|
{
|
|
EditorSceneManager.newSceneCreated += OnNewSceneCreated;
|
|
EditorSceneManager.sceneOpened += OnSceneOpened;
|
|
EditorSceneManager.sceneClosed += OnSceneClosed;
|
|
EditorSceneManager.sceneLoaded += OnSceneLoaded;
|
|
EditorSceneManager.sceneUnloaded += OnSceneUnloaded;
|
|
EditorSceneManager.sceneSaved += OnSceneSaved;
|
|
EditorSceneManager.sceneDirtied += OnSceneDirtied;
|
|
|
|
EditorApplication.hierarchyChanged += OnHierarchyChanged;
|
|
EditorApplication.modifierKeysChanged += OnModifierKeysChanged;
|
|
|
|
PrefabUtility.prefabInstanceUpdated += OnPrefabUpdated;
|
|
PrefabStage.prefabStageOpened += OnPrefabStageOpened;
|
|
PrefabStage.prefabStageClosing += OnPrefabStageClosing;
|
|
|
|
EditorApplication.update += OnEditorUpdate;
|
|
|
|
selectionStyleAfterInvoke = false;
|
|
EditorApplication.RepaintHierarchyWindow();
|
|
EditorApplication.RepaintProjectWindow();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
EditorSceneManager.newSceneCreated -= OnNewSceneCreated;
|
|
EditorSceneManager.sceneOpened -= OnSceneOpened;
|
|
EditorSceneManager.sceneClosed -= OnSceneClosed;
|
|
EditorSceneManager.sceneLoaded -= OnSceneLoaded;
|
|
EditorSceneManager.sceneUnloaded -= OnSceneUnloaded;
|
|
EditorSceneManager.sceneSaved -= OnSceneSaved;
|
|
EditorSceneManager.sceneDirtied -= OnSceneDirtied;
|
|
|
|
EditorApplication.hierarchyChanged -= OnHierarchyChanged;
|
|
EditorApplication.modifierKeysChanged -= OnModifierKeysChanged;
|
|
|
|
PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated;
|
|
PrefabStage.prefabStageOpened -= OnPrefabStageOpened;
|
|
PrefabStage.prefabStageClosing -= OnPrefabStageClosing;
|
|
|
|
EditorApplication.update -= OnEditorUpdate;
|
|
|
|
|
|
foreach (EditorWindow window in GetAllSceneHierarchyWindowsDelegate())
|
|
{
|
|
window.titleContent.text = "Hierarchy";
|
|
}
|
|
|
|
EditorApplication.RepaintHierarchyWindow();
|
|
EditorApplication.RepaintProjectWindow();
|
|
}
|
|
|
|
double lastTimeSinceStartup = EditorApplication.timeSinceStartup;
|
|
|
|
void OnEditorUpdate()
|
|
{
|
|
if (EditorApplication.timeSinceStartup - lastTimeSinceStartup >= 1)
|
|
{
|
|
DelayCall();
|
|
lastTimeSinceStartup = EditorApplication.timeSinceStartup;
|
|
}
|
|
}
|
|
|
|
void DelayCall()
|
|
{
|
|
if (checkingAllHierarchy == true)
|
|
{
|
|
for (int i = 0; i < HierarchyWindow.windows.Count; ++i)
|
|
{
|
|
if (HierarchyWindow.windows[i].editorWindow == null)
|
|
{
|
|
HierarchyWindow.windows[i].Dispose();
|
|
--i;
|
|
}
|
|
}
|
|
|
|
foreach (EditorWindow window in GetAllSceneHierarchyWindowsDelegate())
|
|
{
|
|
if (!HierarchyWindow.instances.ContainsKey(window.GetInstanceID()))
|
|
{
|
|
var hierarchyWindow = new HierarchyWindow(window);
|
|
hierarchyWindow.SetWindowTitle("Hierarchy 2");
|
|
}
|
|
}
|
|
|
|
checkingAllHierarchy = false;
|
|
}
|
|
|
|
if (hierarchyChangedRequireUpdating == true)
|
|
{
|
|
hierarchyChangedRequireUpdating = false;
|
|
}
|
|
}
|
|
|
|
void OnModifierKeysChanged()
|
|
{
|
|
}
|
|
|
|
[DidReloadScripts]
|
|
static void OnEditorCompiled()
|
|
{
|
|
}
|
|
|
|
void OnNewSceneCreated(Scene scene, NewSceneSetup setup, NewSceneMode mode)
|
|
{
|
|
}
|
|
|
|
void OnSceneOpened(Scene scene, OpenSceneMode mode)
|
|
{
|
|
if (settings is null) return;
|
|
}
|
|
|
|
void OnSceneClosed(Scene scene)
|
|
{
|
|
}
|
|
|
|
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
|
{
|
|
}
|
|
|
|
void OnSceneUnloaded(Scene scene)
|
|
{
|
|
}
|
|
|
|
void OnSceneSaved(Scene scene)
|
|
{
|
|
}
|
|
|
|
void OnSceneDirtied(Scene scene)
|
|
{
|
|
}
|
|
|
|
bool hierarchyChangedRequireUpdating = false;
|
|
|
|
void OnHierarchyChanged()
|
|
{
|
|
hierarchyChangedRequireUpdating = true;
|
|
}
|
|
|
|
void OnPrefabUpdated(GameObject prefab)
|
|
{
|
|
}
|
|
|
|
bool prefabStageChanged = false;
|
|
|
|
void OnPrefabStageOpened(PrefabStage stage)
|
|
{
|
|
prefabStageChanged = true;
|
|
}
|
|
|
|
void OnPrefabStageClosing(PrefabStage stage)
|
|
{
|
|
prefabStageChanged = true;
|
|
|
|
for (int i = 0; i < HierarchyWindow.windows.Count; ++i)
|
|
{
|
|
HierarchyWindow.windows[i].Reflection();
|
|
}
|
|
}
|
|
|
|
void HierarchyOnGUI(int selectionID, Rect selectionRect)
|
|
{
|
|
currentEvent = Event.current;
|
|
|
|
if (currentEvent.type == EventType.KeyDown && currentEvent.keyCode == KeyCode.H && currentEvent.control)
|
|
{
|
|
if (!settings.activeHierarchy)
|
|
Invoke();
|
|
else
|
|
Dispose();
|
|
|
|
settings.activeHierarchy = !settings.activeHierarchy;
|
|
currentEvent.Use();
|
|
}
|
|
|
|
if (!settings.activeHierarchy)
|
|
return;
|
|
|
|
if (currentEvent.control && currentEvent.keyCode == KeyCode.D)
|
|
return;
|
|
|
|
if (currentEvent.type == EventType.Layout)
|
|
{
|
|
if (prefabStageChanged)
|
|
{
|
|
prefabStageChanged = false;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
checkingAllHierarchy = true;
|
|
|
|
if (selectionStyleAfterInvoke == false && currentEvent.type == EventType.MouseDown)
|
|
{
|
|
selectionStyleAfterInvoke = true;
|
|
}
|
|
|
|
rowItem.Dispose();
|
|
rowItem.ID = selectionID;
|
|
rowItem.gameObject = EditorUtility.InstanceIDToObject(rowItem.ID) as GameObject;
|
|
rowItem.rect = selectionRect;
|
|
rowItem.rowIndex = GetRowIndex(selectionRect);
|
|
rowItem.isSelected = InSelection(selectionID);
|
|
rowItem.isFirstRow = IsFirstRow(selectionRect);
|
|
rowItem.isFirstElement = IsFirstElement(selectionRect);
|
|
|
|
rowItem.isNull = rowItem.gameObject == null ? true : false;
|
|
|
|
if (!rowItem.isNull)
|
|
{
|
|
rowItem.hierarchyFolder = rowItem.gameObject.GetComponent<HierarchyFolder>();
|
|
if (!(rowItem.isFolder = rowItem.hierarchyFolder))
|
|
rowItem.isSeparator = rowItem.name.StartsWith(settings.separatorStartWith);
|
|
|
|
rowItem.isDirty = EditorUtility.IsDirty(selectionID);
|
|
|
|
if (true && !rowItem.isSeparator && rowItem.isDirty)
|
|
{
|
|
rowItem.isPrefab = PrefabUtility.IsPartOfAnyPrefab(rowItem.gameObject);
|
|
|
|
if (rowItem.isPrefab)
|
|
rowItem.isPrefabMissing = PrefabUtility.IsPrefabAssetMissing(rowItem.gameObject);
|
|
}
|
|
}
|
|
|
|
rowItem.isRootObject = rowItem.isNull || rowItem.gameObject.transform.parent == null ? true : false;
|
|
rowItem.isMouseHovering = selectionRect.Contains(currentEvent.mousePosition);
|
|
|
|
if (rowItem.isFirstRow) //Instance always null
|
|
{
|
|
sceneIndex = 0;
|
|
|
|
if (deepestRow > previousRowIndex)
|
|
deepestRow = previousRowIndex;
|
|
|
|
// if (settings.displayVersion)
|
|
// BottomRightArea(selectionRect);
|
|
|
|
// Background(selectionRect);
|
|
}
|
|
|
|
if (rowItem.isNull)
|
|
{
|
|
if (!IsMultiScene)
|
|
currentScene = SceneManager.GetActiveScene();
|
|
else
|
|
{
|
|
if (!rowItem.isFirstRow && sceneIndex < SceneManager.sceneCount - 1)
|
|
sceneIndex++;
|
|
currentScene = SceneManager.GetSceneAt(sceneIndex);
|
|
}
|
|
|
|
RenameSceneInHierarchy();
|
|
|
|
if (settings.displayRowBackground)
|
|
{
|
|
if (deepestRow != rowItem.rowIndex)
|
|
DisplayRowBackground();
|
|
}
|
|
|
|
previousElement = rowItem;
|
|
previousRowIndex = rowItem.rowIndex;
|
|
previousScene = currentScene;
|
|
|
|
if (previousRowIndex > deepestRow)
|
|
deepestRow = previousRowIndex;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (rowItem.isFirstElement)
|
|
{
|
|
if (deepestRow > previousRowIndex)
|
|
deepestRow = previousRowIndex;
|
|
deepestRow -= rowItem.rowIndex;
|
|
|
|
if (IsMultiScene)
|
|
{
|
|
if (!previousElement.isNull)
|
|
{
|
|
for (int i = 0; i < SceneManager.sceneCount; ++i)
|
|
{
|
|
if (SceneManager.GetSceneAt(i) == rowItem.gameObject.scene)
|
|
{
|
|
sceneIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsMultiScene)
|
|
{
|
|
}
|
|
|
|
rowItem.nameRect = rowItem.rect;
|
|
GUIStyle nameStyle = TreeStyleFromFont(FontStyle.Normal);
|
|
rowItem.nameRect.width = nameStyle.CalcSize(new GUIContent(rowItem.gameObject.name)).x;
|
|
|
|
rowItem.nameRect.x += 16;
|
|
|
|
var isPrefabMode = PrefabStageUtility.GetCurrentPrefabStage() != null ? true : false;
|
|
|
|
if (settings.displayRowBackground && deepestRow != rowItem.rowIndex)
|
|
{
|
|
if (isPrefabMode)
|
|
{
|
|
if (rowItem.gameObject.transform.parent == null) //Should use row index instead.
|
|
{
|
|
if (deepestRow != 0)
|
|
DisplayRowBackground();
|
|
}
|
|
}
|
|
else
|
|
DisplayRowBackground();
|
|
}
|
|
|
|
|
|
if (rowItem.isFolder)
|
|
{
|
|
var icon = rowItem.childCount > 0 ? Resources.FolderIcon : Resources.EmptyFolderIcon;
|
|
DisplayCustomObjectIcon(icon);
|
|
}
|
|
|
|
if (rowItem.isSeparator && rowItem.isRootObject)
|
|
{
|
|
ElementAsSeparator();
|
|
goto FINISH;
|
|
}
|
|
|
|
if (settings.useInstantBackground)
|
|
CustomRowBackground();
|
|
|
|
if (settings.displayTreeView && !rowItem.isRootObject)
|
|
DisplayTreeView();
|
|
|
|
if (settings.displayCustomObjectIcon)
|
|
DisplayCustomObjectIcon(null);
|
|
|
|
widthUse = WidthUse.zero;
|
|
widthUse.left += GLOBAL_SPACE_OFFSET_LEFT;
|
|
if (isPrefabMode) widthUse.left -= 2;
|
|
widthUse.afterName = rowItem.nameRect.x + rowItem.nameRect.width;
|
|
|
|
widthUse.afterName += settings.offSetIconAfterName;
|
|
|
|
DisplayEditableIcon();
|
|
|
|
// DisplayNoteIcon();
|
|
|
|
widthUse.afterName += 8;
|
|
|
|
if (settings.displayTag && !rowItem.gameObject.CompareTag("Untagged"))
|
|
{
|
|
if (!settings.onlyDisplayWhileMouseEnter ||
|
|
(settings.contentDisplay & HierarchySettings.ContentDisplay.Tag) !=
|
|
HierarchySettings.ContentDisplay.Tag ||
|
|
((settings.contentDisplay & HierarchySettings.ContentDisplay.Tag) ==
|
|
HierarchySettings.ContentDisplay.Tag && rowItem.isMouseHovering))
|
|
{
|
|
DisplayTag();
|
|
}
|
|
}
|
|
|
|
if (settings.displayLayer && rowItem.gameObject.layer != 0)
|
|
{
|
|
if (!settings.onlyDisplayWhileMouseEnter ||
|
|
(settings.contentDisplay & HierarchySettings.ContentDisplay.Layer) !=
|
|
HierarchySettings.ContentDisplay.Layer ||
|
|
((settings.contentDisplay & HierarchySettings.ContentDisplay.Layer) ==
|
|
HierarchySettings.ContentDisplay.Layer && rowItem.isMouseHovering))
|
|
{
|
|
DisplayLayer();
|
|
}
|
|
}
|
|
|
|
if (settings.displayComponents)
|
|
{
|
|
if (!settings.onlyDisplayWhileMouseEnter ||
|
|
(settings.contentDisplay & HierarchySettings.ContentDisplay.Component) !=
|
|
HierarchySettings.ContentDisplay.Component ||
|
|
((settings.contentDisplay & HierarchySettings.ContentDisplay.Component) ==
|
|
HierarchySettings.ContentDisplay.Component && rowItem.isMouseHovering))
|
|
{
|
|
DisplayComponents();
|
|
}
|
|
}
|
|
|
|
ElementEvent(rowItem);
|
|
|
|
FINISH:
|
|
if (settings.displayGrid)
|
|
DisplayGrid();
|
|
|
|
previousElement = rowItem;
|
|
previousRowIndex = rowItem.rowIndex;
|
|
previousScene = currentScene;
|
|
|
|
if (previousRowIndex > deepestRow)
|
|
{
|
|
deepestRow = previousRowIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
GUIStyle TreeStyleFromFont(FontStyle fontStyle)
|
|
{
|
|
GUIStyle style;
|
|
switch (fontStyle)
|
|
{
|
|
case FontStyle.Bold:
|
|
style = new GUIStyle(Styles.TreeBoldLabel);
|
|
break;
|
|
|
|
case FontStyle.Italic:
|
|
style = new GUIStyle(Styles.TreeLabel);
|
|
break;
|
|
|
|
case FontStyle.BoldAndItalic:
|
|
style = new GUIStyle(Styles.TreeBoldLabel);
|
|
break;
|
|
|
|
default:
|
|
style = new GUIStyle(Styles.TreeLabel);
|
|
break;
|
|
}
|
|
|
|
return style;
|
|
}
|
|
|
|
void CustomRowBackground()
|
|
{
|
|
if (currentEvent.type != EventType.Repaint)
|
|
return;
|
|
|
|
HierarchySettings.InstantBackgroundColor instantBackgroundColor = new HierarchySettings.InstantBackgroundColor();
|
|
bool contain = false;
|
|
for (int i = 0; i < settings.instantBackgroundColors.Count; ++i)
|
|
{
|
|
if (!settings.instantBackgroundColors[i].active) continue;
|
|
if
|
|
(
|
|
(settings.instantBackgroundColors[i].useTag && !string.IsNullOrEmpty(settings.instantBackgroundColors[i].tag) && rowItem.gameObject.CompareTag(settings.instantBackgroundColors[i].tag)) ||
|
|
(settings.instantBackgroundColors[i].useLayer && (1 << rowItem.gameObject.layer & settings.instantBackgroundColors[i].layer) != 0) ||
|
|
(settings.instantBackgroundColors[i].useStartWith && !string.IsNullOrEmpty(settings.instantBackgroundColors[i].startWith) && rowItem.name.StartsWith(settings.instantBackgroundColors[i].startWith))
|
|
)
|
|
{
|
|
contain = true;
|
|
instantBackgroundColor = settings.instantBackgroundColors[i];
|
|
}
|
|
}
|
|
|
|
if (!contain) return;
|
|
Color guiColor = GUI.color;
|
|
GUI.color = instantBackgroundColor.color;
|
|
Rect rect;
|
|
var texture = Resources.PixelWhite;
|
|
rect = RectFromRight(rowItem.rect, rowItem.rect.width + 16, 0);
|
|
rect.x += 16;
|
|
rect.xMin = 32;
|
|
|
|
GUI.DrawTexture(rect, texture, ScaleMode.StretchToFill);
|
|
GUI.color = guiColor;
|
|
}
|
|
|
|
void ElementAsSeparator()
|
|
{
|
|
if (currentEvent.type != EventType.Repaint)
|
|
return;
|
|
|
|
if (!rowItem.gameObject.CompareTag(settings.separatorDefaultTag))
|
|
rowItem.gameObject.tag = settings.separatorDefaultTag;
|
|
|
|
var rect = EditorGUIUtility.PixelsToPoints(RectFromLeft(rowItem.rect, Screen.width, 0));
|
|
rect.y = rowItem.rect.y;
|
|
rect.height = rowItem.rect.height;
|
|
rect.x += GLOBAL_SPACE_OFFSET_LEFT;
|
|
rect.width -= GLOBAL_SPACE_OFFSET_LEFT;
|
|
|
|
Color guiColor = GUI.color;
|
|
GUI.color = ThemeData.colorHeaderBackground;
|
|
GUI.DrawTexture(rect, Resources.PixelWhite, ScaleMode.StretchToFill);
|
|
|
|
var content = new GUIContent(rowItem.name.Remove(0, settings.separatorStartWith.Length));
|
|
rect.x += (rect.width - Styles.Header.CalcSize(content).x) / 2;
|
|
GUI.color = ThemeData.colorHeaderTitle;
|
|
GUI.Label(rect, content, Styles.Header);
|
|
GUI.color = guiColor;
|
|
}
|
|
|
|
void ElementEvent(RowItem element)
|
|
{
|
|
if (currentEvent.type == EventType.KeyDown)
|
|
{
|
|
if (currentEvent.control && currentEvent.shift && currentEvent.alt &&
|
|
currentEvent.keyCode == KeyCode.C && lastInteractedHierarchyWindowDelegate() != null)
|
|
CollapseAll();
|
|
}
|
|
|
|
if (currentEvent.type == EventType.KeyUp &&
|
|
currentEvent.keyCode == KeyCode.F2 &&
|
|
Selection.gameObjects.Length > 1)
|
|
{
|
|
var window = SelectionsRenamePopup.ShowPopup();
|
|
currentEvent.Use();
|
|
return;
|
|
}
|
|
|
|
if (element.rect.Contains(currentEvent.mousePosition) && currentEvent.type == EventType.MouseUp &&
|
|
currentEvent.button == 2)
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(element.gameObject,
|
|
element.gameObject.activeSelf ? "Inactive object" : "Active object");
|
|
element.gameObject.SetActive(!element.gameObject.activeSelf);
|
|
currentEvent.Use();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void StaticIcon(RowItem element)
|
|
{
|
|
if (!element.isStatic) return;
|
|
|
|
var rect = element.rect;
|
|
rect = RectFromRight(rect, 3, 0);
|
|
|
|
if (currentEvent.type == EventType.MouseUp &&
|
|
currentEvent.button == 1 &&
|
|
rect.Contains(currentEvent.mousePosition))
|
|
{
|
|
GenericMenu staticMenu = new GenericMenu();
|
|
staticMenu.AddItem(new GUIContent("Apply All Children"), settings.applyStaticTargetAndChild,
|
|
() => { settings.applyStaticTargetAndChild = !settings.applyStaticTargetAndChild; });
|
|
staticMenu.AddSeparator("");
|
|
staticMenu.AddItem(new GUIContent("True"), element.gameObject.isStatic ? true : false,
|
|
() => { element.gameObject.isStatic = !element.gameObject.isStatic; });
|
|
staticMenu.AddItem(new GUIContent("False"), !element.gameObject.isStatic ? true : false,
|
|
() => { element.gameObject.isStatic = !element.gameObject.isStatic; });
|
|
staticMenu.ShowAsContext();
|
|
currentEvent.Use();
|
|
}
|
|
|
|
GUISeparator(rect, Color.magenta);
|
|
}
|
|
|
|
void ApplyStaticTargetAndChild(Transform target, bool value)
|
|
{
|
|
target.gameObject.isStatic = value;
|
|
|
|
for (int i = 0; i < target.childCount; ++i)
|
|
ApplyStaticTargetAndChild(target.GetChild(i), value);
|
|
}
|
|
|
|
void DisplayCustomObjectIcon(Texture icon)
|
|
{
|
|
var rect = RectFromRight(rowItem.nameRect, 16, rowItem.nameRect.width + 1);
|
|
rect.height = 16;
|
|
|
|
if (currentEvent.type == EventType.MouseUp && currentEvent.button == 1 &&
|
|
rect.Contains(currentEvent.mousePosition))
|
|
{
|
|
IconSelectorShowAtPositionDelegate(rowItem.gameObject, rect, true);
|
|
currentEvent.Use();
|
|
}
|
|
|
|
if (currentEvent.type == EventType.Repaint)
|
|
{
|
|
if (rect.Contains(currentEvent.mousePosition))
|
|
{
|
|
}
|
|
|
|
if (icon == null)
|
|
{
|
|
icon = AssetPreview.GetMiniThumbnail(rowItem.gameObject);
|
|
if (icon.name == "GameObject Icon" || icon.name == "d_GameObject Icon" || icon.name == "Prefab Icon" ||
|
|
icon.name == "d_Prefab Icon" || icon.name == "PrefabModel Icon" ||
|
|
icon.name == "d_PrefabModel Icon")
|
|
return;
|
|
}
|
|
|
|
Color guiColor = GUI.color;
|
|
GUI.color = rowItem.rowIndex % 2 != 0 ? ThemeData.colorRowEven : ThemeData.colorRowOdd;
|
|
GUI.DrawTexture(rect, Resources.PixelWhite);
|
|
GUI.color = guiColor;
|
|
GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit);
|
|
//ReplaceObjectIcon(rowItem.ID, icon);
|
|
}
|
|
}
|
|
|
|
void DisplayEditableIcon()
|
|
{
|
|
if (rowItem.gameObject.hideFlags == HideFlags.NotEditable)
|
|
{
|
|
Rect lockRect = RectFromLeft(rowItem.nameRect, 12, ref widthUse.afterName);
|
|
|
|
if (currentEvent.type == EventType.Repaint)
|
|
{
|
|
GUI.color = ThemeData.colorLockIcon;
|
|
GUI.DrawTexture(lockRect, Resources.lockIconOn, ScaleMode.ScaleToFit);
|
|
GUI.color = Color.white;
|
|
}
|
|
|
|
if (currentEvent.type == EventType.MouseUp &&
|
|
currentEvent.button == 1 &&
|
|
lockRect.Contains(currentEvent.mousePosition))
|
|
{
|
|
GenericMenu lockMenu = new GenericMenu();
|
|
|
|
GameObject gameObject = rowItem.gameObject;
|
|
|
|
lockMenu.AddItem(new GUIContent("Unlock"), false, () =>
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(gameObject, "Unlock...");
|
|
foreach (Component component in gameObject.GetComponents<Component>())
|
|
{
|
|
if (component)
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(component, "Unlock...");
|
|
component.hideFlags = HideFlags.None;
|
|
}
|
|
}
|
|
|
|
gameObject.hideFlags = HideFlags.None;
|
|
|
|
InternalEditorUtility.RepaintAllViews();
|
|
});
|
|
lockMenu.ShowAsContext();
|
|
currentEvent.Use();
|
|
}
|
|
}
|
|
}
|
|
|
|
void DisplayNoteIcon()
|
|
{
|
|
// if (!element.hasLocalData || element.data.note == "")
|
|
// return;
|
|
|
|
// var iconRect = RectFromLeft(element.nameRect, 14, ref widthUse.afterName);
|
|
// if (currentEvent.type == EventType.Repaint)
|
|
// {
|
|
// GUIContent content = new GUIContent("", element.data.note);
|
|
// GUI.Box(iconRect, content, GUIStyle.none);
|
|
// GUI.color = Color.yellow;
|
|
// GUI.DrawTexture(iconRect, Resources.NoteIcon, ScaleMode.ScaleToFit);
|
|
// GUI.color = Color.white;
|
|
// }
|
|
|
|
// if (currentEvent.type == EventType.MouseUp && currentEvent.button == 1 && iconRect.Contains(currentEvent.mousePosition))
|
|
// {
|
|
// GenericMenu noteMenu = new GenericMenu();
|
|
// noteMenu.AddItem(new GUIContent("Remove Note"), false, () =>
|
|
// {
|
|
// element.data.note = "";
|
|
// });
|
|
// noteMenu.ShowAsContext();
|
|
// currentEvent.Use();
|
|
// }
|
|
|
|
// widthUse.afterName += 2;
|
|
}
|
|
|
|
void DisplayComponents()
|
|
{
|
|
var components = rowItem.gameObject.GetComponents(typeof(Component)).ToList<UnityEngine.Object>();
|
|
var rendererComponent = rowItem.gameObject.GetComponent<Renderer>();
|
|
bool hasMaterial = rendererComponent != null && rendererComponent.sharedMaterial != null;
|
|
|
|
if (hasMaterial)
|
|
{
|
|
for (int i = 0; i < rendererComponent.sharedMaterials.Length; ++i)
|
|
{
|
|
Material sharedMat = rendererComponent.sharedMaterials[i];
|
|
components.Add(sharedMat);
|
|
}
|
|
}
|
|
|
|
int length = components.Count;
|
|
bool separator = false;
|
|
float widthUsedCached = 0;
|
|
if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName)
|
|
{
|
|
widthUsedCached = widthUse.afterName;
|
|
widthUse.afterName += 4;
|
|
}
|
|
else
|
|
{
|
|
widthUsedCached = widthUse.right;
|
|
widthUse.right += 2;
|
|
}
|
|
|
|
for (int i = 0; i < length; ++i)
|
|
{
|
|
var component = components[i];
|
|
|
|
try
|
|
{
|
|
Type comType = component.GetType();
|
|
|
|
if (comType != null)
|
|
{
|
|
bool isMono = false;
|
|
if (comType.BaseType == typeof(MonoBehaviour)) isMono = true;
|
|
if (isMono)
|
|
{
|
|
//TODO: ???
|
|
bool shouldIgnoreThisMono = false;
|
|
if (shouldIgnoreThisMono) continue;
|
|
}
|
|
|
|
switch (settings.componentDisplayMode)
|
|
{
|
|
case HierarchySettings.ComponentDisplayMode.ScriptOnly:
|
|
if (!isMono)
|
|
continue;
|
|
break;
|
|
|
|
case HierarchySettings.ComponentDisplayMode.Specified:
|
|
if (!dicComponents.ContainsKey(comType.Name))
|
|
continue;
|
|
break;
|
|
|
|
case HierarchySettings.ComponentDisplayMode.Ignore:
|
|
if (dicComponents.ContainsKey(comType.Name))
|
|
continue;
|
|
break;
|
|
}
|
|
|
|
Rect rect = Rect.zero;
|
|
|
|
if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName)
|
|
rect = RectFromLeft(rowItem.nameRect, settings.componentSize, ref widthUse.afterName);
|
|
else
|
|
rect = RectFromRight(rowItem.rect, settings.componentSize, ref widthUse.right);
|
|
|
|
|
|
if (hasMaterial && i == length - rendererComponent.sharedMaterials.Length &&
|
|
settings.componentDisplayMode != HierarchySettings.ComponentDisplayMode.ScriptOnly)
|
|
{
|
|
for (int m = 0; m < rendererComponent.sharedMaterials.Length; ++m)
|
|
{
|
|
var sharedMaterial = rendererComponent.sharedMaterials[m];
|
|
|
|
if (sharedMaterial == null) continue;
|
|
ComponentIcon(sharedMaterial, comType, rect, true);
|
|
|
|
if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName)
|
|
rect = RectFromLeft(rowItem.nameRect, settings.componentSize,
|
|
ref widthUse.afterName);
|
|
else
|
|
rect = RectFromRight(rowItem.rect, settings.componentSize, ref widthUse.right);
|
|
}
|
|
|
|
separator = true;
|
|
break;
|
|
}
|
|
|
|
ComponentIcon(component, comType, rect);
|
|
|
|
if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName)
|
|
widthUse.afterName += settings.componentSpacing;
|
|
else
|
|
widthUse.right += settings.componentSpacing;
|
|
|
|
separator = true;
|
|
}
|
|
}
|
|
catch (System.Exception)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (separator && currentEvent.type == EventType.Repaint)
|
|
{
|
|
if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName)
|
|
GUISeparator(RectFromLeft(rowItem.nameRect, 2, widthUsedCached), ThemeData.colorGrid);
|
|
// else
|
|
// GUISeparator(RectFromRight(element.rect, 2, widthUsedCached), ThemeData.colorGrid);
|
|
}
|
|
}
|
|
|
|
void ComponentIcon(UnityEngine.Object component, Type componentType, Rect rect, bool isMaterial = false)
|
|
{
|
|
int comHash = component.GetHashCode();
|
|
|
|
if (currentEvent.type == EventType.Repaint)
|
|
{
|
|
Texture image = EditorGUIUtility.ObjectContent(component, componentType).image;
|
|
|
|
if (selectedComponents.ContainsKey(comHash))
|
|
{
|
|
Color guiColor = GUI.color;
|
|
GUI.color = ThemeData.comSelBGColor;
|
|
GUI.DrawTexture(rect, Resources.PixelWhite, ScaleMode.StretchToFill);
|
|
GUI.color = guiColor;
|
|
}
|
|
|
|
string tooltip = isMaterial ? component.name : componentType.Name;
|
|
tooltipContent.tooltip = tooltip;
|
|
GUI.Box(rect, tooltipContent, GUIStyle.none);
|
|
|
|
GUI.DrawTexture(rect, image, ScaleMode.ScaleToFit);
|
|
}
|
|
|
|
|
|
if (rect.Contains(currentEvent.mousePosition))
|
|
{
|
|
if (currentEvent.type == EventType.MouseDown)
|
|
{
|
|
if (currentEvent.button == 0)
|
|
{
|
|
if (currentEvent.control)
|
|
{
|
|
if (!selectedComponents.ContainsKey(comHash))
|
|
{
|
|
selectedComponents.Add(comHash, component);
|
|
activeComponent = component;
|
|
}
|
|
else
|
|
{
|
|
selectedComponents.Remove(comHash);
|
|
}
|
|
|
|
currentEvent.Use();
|
|
return;
|
|
}
|
|
|
|
selectedComponents.Clear();
|
|
selectedComponents.Add(comHash, component);
|
|
activeComponent = component;
|
|
currentEvent.Use();
|
|
return;
|
|
}
|
|
|
|
if (currentEvent.button == 1)
|
|
{
|
|
if (currentEvent.control)
|
|
{
|
|
GenericMenu componentGenericMenu = new GenericMenu();
|
|
|
|
componentGenericMenu.AddItem(new GUIContent("Remove All Component"), false, () =>
|
|
{
|
|
if (!selectedComponents.ContainsKey(comHash))
|
|
selectedComponents.Add(comHash, component);
|
|
|
|
foreach (var selectedComponent in selectedComponents.ToList())
|
|
{
|
|
if (selectedComponent.Value is Material)
|
|
continue;
|
|
|
|
selectedComponents.Remove(selectedComponent.Key);
|
|
Undo.DestroyObjectImmediate(selectedComponent.Value);
|
|
}
|
|
|
|
selectedComponents.Clear();
|
|
});
|
|
componentGenericMenu.ShowAsContext();
|
|
}
|
|
else
|
|
{
|
|
DisplayObjectContextMenuDelegate(rect, component, 0);
|
|
}
|
|
|
|
currentEvent.Use();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (currentEvent.type == EventType.MouseUp)
|
|
{
|
|
if (currentEvent.button == 2)
|
|
{
|
|
List<UnityEngine.Object> inspectorComponents = new List<UnityEngine.Object>();
|
|
|
|
foreach (var selectedComponent in selectedComponents)
|
|
inspectorComponents.Add(selectedComponent.Value);
|
|
|
|
if (!selectedComponents.ContainsKey(comHash))
|
|
inspectorComponents.Add(component);
|
|
|
|
var window = InstantInspector.OpenEditor();
|
|
window.Fill(inspectorComponents,
|
|
currentEvent.alt ? InstantInspector.FillMode.Add : InstantInspector.FillMode.Default);
|
|
window.Focus();
|
|
|
|
currentEvent.Use();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (selectedComponents.Count > 0 &&
|
|
currentEvent.type == EventType.MouseDown &&
|
|
currentEvent.button == 0 &&
|
|
!currentEvent.control &&
|
|
!rect.Contains(currentEvent.mousePosition))
|
|
{
|
|
selectedComponents.Clear();
|
|
activeComponent = null;
|
|
}
|
|
}
|
|
|
|
void BottomRightArea(Rect rect)
|
|
{
|
|
// var content = new GUIContent(string.Format("{0}", VERSION));
|
|
// rect = RectFromRight(rect, EditorStyles.miniBoldLabel.CalcSize(content).x, 0);
|
|
// rect.y += Screen.height - 59;
|
|
// GUI.color = new Color(.5f, .5f, .5f, .2f);
|
|
// GUI.Label(rect, content, EditorStyles.miniBoldLabel);
|
|
// GUI.color = Color.white;
|
|
}
|
|
|
|
void Background(Rect rect)
|
|
{
|
|
// rect.y += 16;
|
|
// rect.xMin = 0;
|
|
// rect.height = Screen.height;
|
|
// GUI.color = new Color(.4f, .4f, .4f, 1);
|
|
// GUI.DrawTexture(rect, Assets.PixelWhite);
|
|
// GUI.color = Color.white;
|
|
}
|
|
|
|
void DisplayTag()
|
|
{
|
|
GUIContent tagContent = new GUIContent(rowItem.gameObject.tag);
|
|
|
|
var style = Styles.Tag;
|
|
style.normal.textColor = ThemeData.tagColor;
|
|
Rect rect;
|
|
|
|
if (settings.tagAlignment == HierarchySettings.ElementAlignment.AfterName)
|
|
{
|
|
rect = RectFromLeft(rowItem.nameRect, style.CalcSize(tagContent).x, ref widthUse.afterName);
|
|
|
|
if (currentEvent.type == EventType.Repaint)
|
|
{
|
|
GUISeparator(RectFromLeft(rowItem.nameRect, 1, widthUse.afterName), ThemeData.colorGrid);
|
|
GUI.Label(rect, tagContent, style);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rect = RectFromRight(rowItem.rect, style.CalcSize(tagContent).x, ref widthUse.right);
|
|
|
|
if (currentEvent.type == EventType.Repaint)
|
|
{
|
|
GUISeparator(RectFromRight(rowItem.rect, 1, widthUse.right), ThemeData.colorGrid);
|
|
GUI.Label(rect, tagContent, style);
|
|
}
|
|
}
|
|
|
|
if (currentEvent.type == EventType.MouseUp && currentEvent.button == 1 &&
|
|
rect.Contains(currentEvent.mousePosition))
|
|
{
|
|
GenericMenu menuTags = new GenericMenu();
|
|
GameObject gameObject = rowItem.gameObject;
|
|
|
|
menuTags.AddItem(new GUIContent("Apply All Children"), settings.applyTagTargetAndChild,
|
|
() => { settings.applyTagTargetAndChild = !settings.applyTagTargetAndChild; });
|
|
menuTags.AddSeparator("");
|
|
|
|
foreach (var tag in InternalEditorUtility.tags)
|
|
{
|
|
menuTags.AddItem(new GUIContent(tag), gameObject.tag == tag ? true : false, () =>
|
|
{
|
|
if (settings.applyTagTargetAndChild)
|
|
ApplyTagTargetAndChild(gameObject.transform, tag);
|
|
else
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(gameObject, "Change Tag");
|
|
gameObject.tag = tag;
|
|
}
|
|
});
|
|
}
|
|
|
|
menuTags.ShowAsContext();
|
|
currentEvent.Use();
|
|
}
|
|
}
|
|
|
|
void ApplyTagTargetAndChild(Transform target, string tag)
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(target.gameObject, "Change Tag");
|
|
target.gameObject.tag = tag;
|
|
|
|
for (int i = 0; i < target.childCount; ++i)
|
|
ApplyTagTargetAndChild(target.GetChild(i), tag);
|
|
}
|
|
|
|
void DisplayLayer()
|
|
{
|
|
GUIContent layerContent = new GUIContent(LayerMask.LayerToName(rowItem.gameObject.layer));
|
|
var style = Styles.Layer;
|
|
style.normal.textColor = ThemeData.layerColor;
|
|
Rect rect;
|
|
|
|
if (settings.layerAlignment == HierarchySettings.ElementAlignment.AfterName)
|
|
{
|
|
rect = RectFromLeft(rowItem.nameRect, style.CalcSize(layerContent).x, ref widthUse.afterName);
|
|
|
|
if (currentEvent.type == EventType.Repaint)
|
|
{
|
|
GUISeparator(RectFromLeft(rowItem.nameRect, 1, widthUse.afterName), ThemeData.colorGrid);
|
|
GUI.Label(rect, layerContent, style);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rect = RectFromRight(rowItem.rect, style.CalcSize(layerContent).x, ref widthUse.right);
|
|
|
|
if (currentEvent.type == EventType.Repaint)
|
|
{
|
|
GUISeparator(RectFromRight(rowItem.rect, 1, widthUse.right), ThemeData.colorGrid);
|
|
GUI.Label(rect, layerContent, style);
|
|
}
|
|
}
|
|
|
|
if (currentEvent.type == EventType.MouseUp && currentEvent.button == 1 &&
|
|
rect.Contains(currentEvent.mousePosition))
|
|
{
|
|
GenericMenu menuLayers = new GenericMenu();
|
|
GameObject gameObject = rowItem.gameObject;
|
|
|
|
menuLayers.AddItem(new GUIContent("Apply All Children"), settings.applyLayerTargetAndChild,
|
|
() => { settings.applyLayerTargetAndChild = !settings.applyLayerTargetAndChild; });
|
|
menuLayers.AddSeparator("");
|
|
|
|
foreach (string layer in InternalEditorUtility.layers)
|
|
{
|
|
menuLayers.AddItem(new GUIContent(layer),
|
|
LayerMask.NameToLayer(layer) == gameObject.layer ? true : false, () =>
|
|
{
|
|
if (settings.applyLayerTargetAndChild)
|
|
ApplyLayerTargetAndChild(gameObject.transform, LayerMask.NameToLayer(layer));
|
|
else
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(gameObject, "Change Layer");
|
|
gameObject.layer = LayerMask.NameToLayer(layer);
|
|
}
|
|
});
|
|
}
|
|
|
|
menuLayers.ShowAsContext();
|
|
currentEvent.Use();
|
|
}
|
|
}
|
|
|
|
void ApplyLayerTargetAndChild(Transform target, int layer)
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(target.gameObject, "Change Layer");
|
|
target.gameObject.layer = layer;
|
|
|
|
for (int i = 0; i < target.childCount; ++i)
|
|
ApplyLayerTargetAndChild(target.GetChild(i), layer);
|
|
}
|
|
|
|
void DisplayRowBackground(bool nextRow = true)
|
|
{
|
|
if (currentEvent.type != EventType.Repaint)
|
|
return;
|
|
|
|
Rect rect = rowItem.rect;
|
|
rect.xMin = -1;
|
|
rect.width += 16;
|
|
|
|
Color color = (rect.y / rect.height) % 2 == 0 ? ThemeData.colorRowEven : ThemeData.colorRowOdd;
|
|
|
|
if (nextRow)
|
|
rect.y += rect.height;
|
|
|
|
Color guiColor = GUI.color;
|
|
GUI.color = color;
|
|
GUI.DrawTexture(rect, Resources.PixelWhite, ScaleMode.StretchToFill);
|
|
GUI.color = guiColor;
|
|
}
|
|
|
|
void DisplayGrid()
|
|
{
|
|
if (currentEvent.type != EventType.Repaint)
|
|
return;
|
|
|
|
var rect = rowItem.rect;
|
|
|
|
rect.xMin = GLOBAL_SPACE_OFFSET_LEFT;
|
|
rect.y += 15;
|
|
rect.width += 16;
|
|
rect.height = 1;
|
|
|
|
Color guiColor = GUI.color;
|
|
GUI.color = ThemeData.colorGrid;
|
|
GUI.DrawTexture(rect, Resources.PixelWhite, ScaleMode.StretchToFill);
|
|
GUI.color = guiColor;
|
|
}
|
|
|
|
void DisplayTreeView()
|
|
{
|
|
if (currentEvent.type != EventType.Repaint)
|
|
return;
|
|
|
|
Rect rect = rowItem.rect;
|
|
|
|
rect.width = 40;
|
|
rect.x -= 34;
|
|
var t = rowItem.gameObject.transform.parent;
|
|
|
|
Color guiColor = GUI.color;
|
|
GUI.color = ThemeData.colorTreeView;
|
|
|
|
if (t.childCount == 1 || t.GetChild(t.childCount - 1) == rowItem.gameObject.transform)
|
|
{
|
|
GUI.DrawTexture(rect, resources.GetIcon("icon_branch_L"), ScaleMode.ScaleToFit);
|
|
}
|
|
else
|
|
{
|
|
GUI.DrawTexture(rect, resources.GetIcon("icon_branch_T"), ScaleMode.ScaleToFit);
|
|
}
|
|
|
|
while (t != null)
|
|
{
|
|
if (t.parent == null)
|
|
break;
|
|
|
|
if (t == t.parent.GetChild(t.parent.childCount - 1))
|
|
{
|
|
t = t.parent;
|
|
rect.x -= 14;
|
|
continue;
|
|
}
|
|
|
|
rect.x -= 14;
|
|
GUI.DrawTexture(rect, resources.GetIcon("icon_branch_I"), ScaleMode.ScaleToFit);
|
|
t = t.parent;
|
|
}
|
|
|
|
GUI.color = guiColor;
|
|
}
|
|
|
|
GUIContent tmpSceneContent = new GUIContent();
|
|
|
|
void RenameSceneInHierarchy()
|
|
{
|
|
string name = currentScene.name;
|
|
if (name == "")
|
|
return;
|
|
|
|
var leftTitleWidthUsed = 48f;
|
|
#if UNITY_2019_1_OR_NEWER
|
|
leftTitleWidthUsed += 24f;
|
|
#endif
|
|
|
|
if (!currentScene.isLoaded)
|
|
name = string.Format("{0} (not loaded", name);
|
|
|
|
tmpSceneContent.text = name == "" ? "Untitled" : name;
|
|
Vector2 size = Styles.TreeBoldLabel.CalcSize(tmpSceneContent);
|
|
leftTitleWidthUsed += size.x;
|
|
|
|
|
|
if (currentEvent.type == EventType.KeyDown &&
|
|
currentEvent.keyCode == KeyCode.F2 &&
|
|
rowItem.rect.Contains(currentEvent.mousePosition))
|
|
{
|
|
SceneRenamePopup.ShowPopup(currentScene);
|
|
}
|
|
}
|
|
|
|
void CollapseAll()
|
|
{
|
|
}
|
|
|
|
void DirtyScene(Scene scene)
|
|
{
|
|
if (EditorApplication.isPlaying)
|
|
return;
|
|
|
|
EditorSceneManager.MarkSceneDirty(scene);
|
|
}
|
|
|
|
bool IsFirstElement(Rect rect) => previousRowIndex > rect.y / rect.height;
|
|
|
|
bool IsFirstRow(Rect rect) => rect.y / rect.height == 0;
|
|
|
|
int GetRowIndex(Rect rect) => (int) (rect.y / rect.height);
|
|
|
|
bool InSelection(int ID) => Selection.Contains(ID) ? true : false;
|
|
|
|
bool IsElementDirty(int ID) => EditorUtility.IsDirty(ID);
|
|
|
|
Rect RectFromRight(Rect rect, float width, float usedWidth)
|
|
{
|
|
usedWidth += width;
|
|
rect.x = rect.x + rect.width - usedWidth;
|
|
rect.width = width;
|
|
return rect;
|
|
}
|
|
|
|
Rect RectFromRight(Rect rect, float width, ref float usedWidth)
|
|
{
|
|
usedWidth += width;
|
|
rect.x = rect.x + rect.width - usedWidth;
|
|
rect.width = width;
|
|
return rect;
|
|
}
|
|
|
|
Rect RectFromRight(Rect rect, Vector2 offset, float width, ref float usedWidth)
|
|
{
|
|
usedWidth += width;
|
|
rect.position += offset;
|
|
rect.x = rect.x + rect.width - usedWidth;
|
|
rect.width = width;
|
|
return rect;
|
|
}
|
|
|
|
Rect RectFromLeft(Rect rect, float width, float usedWidth, bool usexmin = true)
|
|
{
|
|
if (usexmin)
|
|
rect.xMin = 0;
|
|
rect.x += usedWidth;
|
|
rect.width = width;
|
|
usedWidth += width;
|
|
return rect;
|
|
}
|
|
|
|
Rect RectFromLeft(Rect rect, float width, ref float usedWidth, bool usexmin = true)
|
|
{
|
|
if (usexmin)
|
|
rect.xMin = 0;
|
|
rect.x += usedWidth;
|
|
rect.width = width;
|
|
usedWidth += width;
|
|
return rect;
|
|
}
|
|
|
|
Rect RectFromLeft(Rect rect, Vector2 offset, float width, ref float usedWidth, bool usexmin = true)
|
|
{
|
|
if (usexmin)
|
|
rect.xMin = 0;
|
|
rect.position += offset;
|
|
rect.x += usedWidth;
|
|
rect.width = width;
|
|
usedWidth += width;
|
|
return rect;
|
|
}
|
|
|
|
void GUISeparator(Rect rect, Color color)
|
|
{
|
|
Color guiColor = GUI.color;
|
|
GUI.color = color;
|
|
GUI.DrawTexture(rect, Resources.PixelWhite, ScaleMode.StretchToFill);
|
|
GUI.color = guiColor;
|
|
}
|
|
|
|
struct WidthUse
|
|
{
|
|
public float left;
|
|
public float right;
|
|
public float afterName;
|
|
|
|
public WidthUse(float left, float right, float afterName)
|
|
{
|
|
this.left = left;
|
|
this.right = right;
|
|
this.afterName = afterName;
|
|
}
|
|
|
|
public static WidthUse zero
|
|
{
|
|
get { return new WidthUse(0, 0, 0); }
|
|
}
|
|
}
|
|
|
|
sealed class HierarchyWindow
|
|
{
|
|
public static Dictionary<int, EditorWindow> instances = new Dictionary<int, EditorWindow>();
|
|
public static List<HierarchyWindow> windows = new List<HierarchyWindow>();
|
|
|
|
public int instanceID = Int32.MinValue;
|
|
public EditorWindow editorWindow;
|
|
public object treeview;
|
|
|
|
public HierarchyWindow(EditorWindow editorWindow)
|
|
{
|
|
this.editorWindow = editorWindow;
|
|
|
|
instanceID = this.editorWindow.GetInstanceID();
|
|
|
|
instances.Add(instanceID, this.editorWindow);
|
|
windows.Add(this);
|
|
|
|
// Debug.Log(string.Format("HierarchyWindow {0} Instanced.", instanceID));
|
|
|
|
Reflection();
|
|
}
|
|
|
|
public void Reflection()
|
|
{
|
|
// treeview = m_TreeView.GetValue(m_SceneHierarchy.GetValue(editorWindow));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
editorWindow = null;
|
|
treeview = null;
|
|
instances.Remove(instanceID);
|
|
windows.Remove(this);
|
|
|
|
// Debug.Log(string.Format("HierarchyWindow {0} Disposed.", instanceID));
|
|
}
|
|
|
|
public TreeViewItem GetItemAndRowIndex(int id, out int row)
|
|
{
|
|
row = -1;
|
|
// if (treeview == null) return null;
|
|
// var item = GetItemAndRowIndexMethod.Invoke(treeview, new object[] {id, row}) as TreeViewItem;
|
|
// return item;
|
|
return null;
|
|
}
|
|
|
|
public void SetWindowTitle(string value)
|
|
{
|
|
if (editorWindow == null)
|
|
return;
|
|
|
|
editorWindow.titleContent.text = value;
|
|
}
|
|
}
|
|
|
|
sealed class RowItem
|
|
{
|
|
public int ID = int.MinValue;
|
|
public Rect rect;
|
|
public Rect nameRect;
|
|
public int rowIndex = 0;
|
|
public GameObject gameObject;
|
|
public bool isNull = true;
|
|
public bool isPrefab = false;
|
|
public bool isPrefabMissing = false;
|
|
public bool isRootObject = false;
|
|
public bool isSelected = false;
|
|
public bool isFirstRow = false;
|
|
public bool isFirstElement = false;
|
|
public bool isSeparator = false;
|
|
public bool isFolder = false;
|
|
public bool isDirty = false;
|
|
public bool isMouseHovering = false;
|
|
public HierarchyFolder hierarchyFolder;
|
|
|
|
public string name
|
|
{
|
|
get { return isNull ? "Null" : gameObject.name; }
|
|
}
|
|
|
|
public int childCount
|
|
{
|
|
get { return gameObject.transform.childCount; }
|
|
}
|
|
|
|
public Scene Scene
|
|
{
|
|
get { return gameObject.scene; }
|
|
}
|
|
|
|
public bool isStatic
|
|
{
|
|
get { return isNull ? false : gameObject.isStatic; }
|
|
}
|
|
|
|
public RowItem()
|
|
{
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
ID = int.MinValue;
|
|
gameObject = null;
|
|
rect = Rect.zero;
|
|
nameRect = Rect.zero;
|
|
rowIndex = 0;
|
|
isNull = true;
|
|
isRootObject = false;
|
|
isSelected = false;
|
|
isFirstRow = false;
|
|
isFirstElement = false;
|
|
isSeparator = false;
|
|
isFolder = false;
|
|
isDirty = false;
|
|
isMouseHovering = false;
|
|
}
|
|
}
|
|
|
|
internal sealed class Resources
|
|
{
|
|
private static Texture2D pixelWhite;
|
|
|
|
public static Texture2D PixelWhite
|
|
{
|
|
get
|
|
{
|
|
if (pixelWhite == null)
|
|
{
|
|
pixelWhite = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
|
pixelWhite.SetPixel(0, 0, Color.white);
|
|
pixelWhite.Apply();
|
|
}
|
|
|
|
return pixelWhite;
|
|
}
|
|
}
|
|
|
|
private static Texture2D alphaTexture;
|
|
|
|
public static Texture2D AlphaTexture
|
|
{
|
|
get
|
|
{
|
|
if (alphaTexture == null)
|
|
{
|
|
alphaTexture = new Texture2D(16, 16, TextureFormat.RGBA32, false);
|
|
for (int x = 0; x < 16; ++x)
|
|
for (int y = 0; y < 16; ++y)
|
|
alphaTexture.SetPixel(x, y, Color.clear);
|
|
alphaTexture.Apply();
|
|
}
|
|
|
|
return alphaTexture;
|
|
}
|
|
}
|
|
|
|
private static Texture2D ramp8x8White;
|
|
|
|
public static Texture2D Ramp8x8White
|
|
{
|
|
get
|
|
{
|
|
if (ramp8x8White == null)
|
|
{
|
|
ramp8x8White = new byte[]
|
|
{
|
|
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 16,
|
|
0, 0, 0, 16, 8, 6, 0, 0, 0, 31, 243, 255, 97, 0, 0, 0, 40, 73, 68, 65, 84, 56, 17, 99, 252,
|
|
15, 4, 12, 12,
|
|
12, 31, 8, 224, 143, 184, 228, 153, 128, 18, 20, 129, 81, 3, 24, 24, 70, 195, 96, 52, 12,
|
|
64, 153, 104, 224,
|
|
211, 1, 0, 153, 171, 18, 45, 165, 62, 165, 211, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130
|
|
}.PNGImageDecode();
|
|
}
|
|
|
|
return ramp8x8White;
|
|
}
|
|
}
|
|
|
|
internal static readonly Texture lockIconOn = EditorGUIUtility.IconContent("LockIcon-On").image;
|
|
|
|
private static Texture folderIcon;
|
|
|
|
public static Texture FolderIcon
|
|
{
|
|
get
|
|
{
|
|
if (folderIcon == null)
|
|
folderIcon = EditorGUIUtility.IconContent("Folder Icon").image;
|
|
return folderIcon;
|
|
}
|
|
}
|
|
|
|
private static Texture emptyFolderIcon;
|
|
|
|
public static Texture EmptyFolderIcon
|
|
{
|
|
get
|
|
{
|
|
if (emptyFolderIcon == null)
|
|
emptyFolderIcon = EditorGUIUtility.IconContent("FolderEmpty Icon").image;
|
|
return emptyFolderIcon;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static class Styles
|
|
{
|
|
internal static GUIStyle lineStyle = new GUIStyle("TV Line");
|
|
|
|
internal static GUIStyle PR_DisabledLabel = new GUIStyle("PR DisabledLabel");
|
|
|
|
internal static GUIStyle PR_PrefabLabel = new GUIStyle("PR PrefabLabel");
|
|
|
|
internal static GUIStyle PR_DisabledPrefabLabel = new GUIStyle("PR DisabledPrefabLabel");
|
|
|
|
internal static GUIStyle PR_BrokenPrefabLabel = new GUIStyle("PR BrokenPrefabLabel");
|
|
|
|
internal static GUIStyle PR_DisabledBrokenPrefabLabel = new GUIStyle("PR DisabledBrokenPrefabLabel");
|
|
|
|
internal static GUIStyle Tag = new GUIStyle()
|
|
{
|
|
padding = new RectOffset(3, 4, 0, 0),
|
|
alignment = TextAnchor.MiddleCenter,
|
|
fontStyle = FontStyle.Italic,
|
|
fontSize = 8,
|
|
richText = true,
|
|
border = new RectOffset(12, 12, 8, 8),
|
|
};
|
|
|
|
internal static GUIStyle Layer = new GUIStyle()
|
|
{
|
|
padding = new RectOffset(3, 4, 0, 0),
|
|
alignment = TextAnchor.MiddleCenter,
|
|
fontStyle = FontStyle.Italic,
|
|
fontSize = 8,
|
|
richText = true,
|
|
border = new RectOffset(12, 12, 8, 8),
|
|
};
|
|
|
|
[System.Obsolete] internal static GUIStyle DirtyLabel = new GUIStyle(EditorStyles.label)
|
|
{
|
|
padding = new RectOffset(-1, 0, 0, 0),
|
|
margin = new RectOffset(0, 0, 0, 0),
|
|
border = new RectOffset(0, 0, 0, 0),
|
|
alignment = TextAnchor.UpperLeft,
|
|
};
|
|
|
|
internal static GUIStyle Header = new GUIStyle(TreeBoldLabel)
|
|
{
|
|
richText = true,
|
|
normal = new GUIStyleState() {textColor = Color.white}
|
|
};
|
|
|
|
internal static GUIStyle TreeBoldLabel
|
|
{
|
|
get { return TreeView.DefaultStyles.boldLabel; }
|
|
}
|
|
|
|
internal static GUIStyle TreeLabel = new GUIStyle(TreeView.DefaultStyles.label)
|
|
{
|
|
richText = true,
|
|
normal = new GUIStyleState() {textColor = Color.white}
|
|
};
|
|
}
|
|
|
|
internal sealed class MenuCommand
|
|
{
|
|
const int priority = 200;
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Lock Selection %l", false, priority)]
|
|
static void SetNotEditableObject()
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(Selection.gameObjects, "Set Selections Flag NotEditable");
|
|
foreach (GameObject gameObject in Selection.gameObjects)
|
|
{
|
|
foreach (Component component in gameObject.GetComponents<Component>())
|
|
{
|
|
if (component)
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(component, "Set Selections Flag NotEditable");
|
|
component.hideFlags = HideFlags.NotEditable;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (GameObject gameObject in Selection.gameObjects)
|
|
gameObject.hideFlags = HideFlags.NotEditable;
|
|
|
|
InternalEditorUtility.RepaintAllViews();
|
|
}
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Lock Selection %l", true, priority)]
|
|
static bool ValidateSetNotEditableObject() => Selection.gameObjects.Length > 0;
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Unlock Selection %&l", false, priority)]
|
|
static void SetEditableObject()
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(Selection.gameObjects, "Set Selections Flag Editable");
|
|
foreach (GameObject gameObject in Selection.gameObjects)
|
|
{
|
|
foreach (Component component in gameObject.GetComponents<Component>())
|
|
{
|
|
if (component)
|
|
{
|
|
Undo.RegisterCompleteObjectUndo(component, "Set Selections Flag Editable");
|
|
component.hideFlags = HideFlags.None;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (GameObject gameObject in Selection.gameObjects)
|
|
gameObject.hideFlags = HideFlags.None;
|
|
|
|
InternalEditorUtility.RepaintAllViews();
|
|
}
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Unlock Selection %&l", true, priority)]
|
|
static bool ValidateSetEditableObject() => Selection.gameObjects.Length > 0;
|
|
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Move Selection Up #w", false, priority)]
|
|
static void QuickSiblingUp()
|
|
{
|
|
var gameObject = Selection.activeGameObject;
|
|
if (gameObject == null)
|
|
return;
|
|
|
|
var index = gameObject.transform.GetSiblingIndex();
|
|
if (index > 0)
|
|
{
|
|
Undo.SetTransformParent(gameObject.transform, gameObject.transform.parent, string.Format("{0} Parenting", gameObject.name));
|
|
|
|
gameObject.transform.SetSiblingIndex(--index);
|
|
}
|
|
}
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Move Selection Up #w", true)]
|
|
static bool ValidateQuickSiblingUp() => Selection.activeTransform != null;
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Move Selection Down #s", false, priority)]
|
|
static void QuickSiblingDown()
|
|
{
|
|
var gameObject = Selection.activeGameObject;
|
|
if (gameObject == null)
|
|
return;
|
|
|
|
Undo.SetTransformParent(gameObject.transform, gameObject.transform.parent, string.Format("{0} Parenting", gameObject.name));
|
|
|
|
var index = gameObject.transform.GetSiblingIndex();
|
|
gameObject.transform.SetSiblingIndex(++index);
|
|
}
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Move Selection Down #s", true, priority)]
|
|
static bool ValidateQuickSiblingDown() => Selection.activeTransform != null;
|
|
|
|
[MenuItem("Tools/Hierarchy 2/Separator", priority = 0)]
|
|
static void CreateHeaderInstance(UnityEditor.MenuCommand command)
|
|
{
|
|
GameObject gameObject = new GameObject(string.Format("{0}Separator", HierarchyEditor.instance.settings.separatorStartWith));
|
|
|
|
Undo.RegisterCreatedObjectUndo(gameObject, "Create Separator");
|
|
// Don't create headers as children of the selected objects because only root headers are drawn with background
|
|
//if(command.context)
|
|
// Undo.SetTransformParent(gameObject.transform, ( (GameObject) command.context ).transform, "Create Header");
|
|
|
|
Selection.activeTransform = gameObject.transform;
|
|
}
|
|
}
|
|
}
|
|
} |