浏览代码

(Refactor) Advanced Hierarchy View (#12)

* Base Rename

* Added Preferences / Contextual Visibility

* Updated Changelog

* Added Attributes for registering Icons

* Added All/None/Invert Toggles in preferences
/main
GitHub 4 年前
当前提交
54ee3a0b
共有 22 个文件被更改,包括 421 次插入0 次删除
  1. 6
      CHANGELOG.md
  2. 2
      Runtime/Ingredients/Counter/Counter.cs
  3. 1
      Runtime/Ingredients/Factory/Factory.cs
  4. 1
      Runtime/Ingredients/Interactions/Interactive.cs
  5. 1
      Runtime/Ingredients/StateMachine/State.cs
  6. 1
      Runtime/Ingredients/StateMachine/StateMachine.cs
  7. 1
      Runtime/Ingredients/Timer/Timer.cs
  8. 1
      Runtime/LevelScripting/Events/OnEnableDisableEvent.cs
  9. 1
      Runtime/LevelScripting/Events/OnMessageEvent.cs
  10. 1
      Runtime/LevelScripting/Events/OnStartEvent.cs
  11. 1
      Runtime/LevelScripting/Events/OnTriggerEvent.cs
  12. 18
      Runtime/Attributes/AdvancedHierarchyIconAttribute.cs
  13. 11
      Runtime/Attributes/AdvancedHierarchyIconAttribute.cs.meta
  14. 124
      Editor/AdvancedHierarchyView/AdvancedHierarchyPreferences.cs
  15. 11
      Editor/AdvancedHierarchyView/AdvancedHierarchyPreferences.cs.meta
  16. 240
      Editor/AdvancedHierarchyView/AdvancedHierarchyView.cs
  17. 0
      /Editor/AdvancedHierarchyView.meta
  18. 0
      /Runtime/Attributes.meta
  19. 0
      /Runtime/Attributes
  20. 0
      /Editor/AdvancedHierarchyView/AdvancedHierarchyView.cs.meta

6
CHANGELOG.md


## 2019.3.4
#### Added
* Preferences for Advanced Hierarchy View
* Added API to AdvancedHierarchyView to add other Icons from component types
* Renamed HierarchyHints to AdvancedHierarchyView + Changed behaviour to apply visibility from preferences
## 2019.3.3

2
Runtime/Ingredients/Counter/Counter.cs


namespace GameplayIngredients
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Misc/ic-counter.png")]
public class Counter : MonoBehaviour
{
public enum ValueSourceType

1
Runtime/Ingredients/Factory/Factory.cs


namespace GameplayIngredients
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Misc/ic-Factory.png")]
public class Factory : MonoBehaviour
{
public enum BlueprintSelectionMode

1
Runtime/Ingredients/Interactions/Interactive.cs


namespace GameplayIngredients.Interactions
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Misc/ic-interactive.png")]
public abstract class Interactive : EventBase
{
[Header("Events")]

1
Runtime/Ingredients/StateMachine/State.cs


namespace GameplayIngredients.StateMachines
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Misc/ic-State.png")]
public class State : MonoBehaviour
{
public string StateName { get { return gameObject.name; } }

1
Runtime/Ingredients/StateMachine/StateMachine.cs


namespace GameplayIngredients.StateMachines
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Misc/ic-StateMachine.png")]
public class StateMachine : MonoBehaviour
{
[StateMachineState]

1
Runtime/Ingredients/Timer/Timer.cs


namespace GameplayIngredients
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Misc/ic-timer.png")]
public class Timer : MonoBehaviour
{
public bool StartOnEnable = false;

1
Runtime/LevelScripting/Events/OnEnableDisableEvent.cs


namespace GameplayIngredients.Events
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Events/ic-event-enable-disable.png")]
public class OnEnableDisableEvent : EventBase
{
[ReorderableList]

1
Runtime/LevelScripting/Events/OnMessageEvent.cs


namespace GameplayIngredients.Events
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Events/ic-event-message.png")]
public class OnMessageEvent : EventBase
{
public string MessageName = "Message";

1
Runtime/LevelScripting/Events/OnStartEvent.cs


namespace GameplayIngredients.Events
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Events/ic-event-start.png")]
public class OnStartEvent : EventBase
{
[ReorderableList]

1
Runtime/LevelScripting/Events/OnTriggerEvent.cs


namespace GameplayIngredients.Events
{
[AdvancedHierarchyIcon("Packages/net.peeweek.gameplay-ingredients/Icons/Events/ic-event-trigger.png")]
public class OnTriggerEvent : EventBase
{
[ReorderableList]

18
Runtime/Attributes/AdvancedHierarchyIconAttribute.cs


using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GameplayIngredients
{
[AttributeUsage(AttributeTargets.Class)]
public class AdvancedHierarchyIconAttribute : Attribute
{
public readonly string icon;
public AdvancedHierarchyIconAttribute(string icon)
{
this.icon = icon;
}
}
}

11
Runtime/Attributes/AdvancedHierarchyIconAttribute.cs.meta


fileFormatVersion: 2
guid: 84a5d6b8a98d866468c7f3773aed6138
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

124
Editor/AdvancedHierarchyView/AdvancedHierarchyPreferences.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using System.Linq;
namespace GameplayIngredients.Editor
{
static class AdvancedHierarchyPreferences
{
[SettingsProvider]
public static SettingsProvider GetAdvancedHierarchyPreferences()
{
var provider = new SettingsProvider("Preferences/Gameplay Ingredients/Advanced Hierarchy View", SettingsScope.User)
{
label = "Advanced Hierarchy Options",
guiHandler = OnGUI
};
return provider;
}
static Dictionary<Type, bool> s_CachedVisibility;
static readonly string componentPrefix = "GameplayIngredients.HierarchyHints.";
static readonly string staticPref = "GameplayIngredients.HierarchyHints.Static";
[InitializeOnLoadMethod]
static void Initialize()
{
if (s_CachedVisibility == null)
s_CachedVisibility = new Dictionary<Type, bool>();
foreach (var type in AdvancedHierarchyView.allTypes)
{
if (!s_CachedVisibility.ContainsKey(type))
s_CachedVisibility.Add(type, EditorPrefs.GetBool(componentPrefix + type.Name, true));
else
s_CachedVisibility[type] = EditorPrefs.GetBool(componentPrefix + type.Name, true);
}
}
public static bool showStatic { get { return EditorPrefs.GetBool(staticPref, true); } }
public static bool IsVisible(Type t)
{
if (s_CachedVisibility.ContainsKey(t))
return s_CachedVisibility[t];
else
return false;
}
static void OnGUI(string search)
{
EditorGUIUtility.labelWidth = 260;
EditorGUI.indentLevel ++;
EditorGUILayout.Space();
EditorGUILayout.LabelField("Preferences", EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUI.BeginChangeCheck();
var s = EditorGUILayout.Toggle("Show Static", showStatic);
if(EditorGUI.EndChangeCheck())
{
EditorPrefs.SetBool(staticPref, s);
EditorApplication.RepaintHierarchyWindow();
}
EditorGUI.indentLevel--;
EditorGUILayout.Space();
using (new GUILayout.HorizontalScope())
{
GUILayout.Label("Visible Components", EditorStyles.boldLabel, GUILayout.Width(EditorGUIUtility.labelWidth));
if (GUILayout.Button("All"))
ToggleAll(true);
if (GUILayout.Button("None"))
ToggleAll(false);
if (GUILayout.Button("Invert"))
ToggleInvert();
}
EditorGUI.indentLevel ++;
foreach (var type in AdvancedHierarchyView.allTypes)
{
EditorGUI.BeginChangeCheck();
var value = EditorGUILayout.Toggle(type.Name, s_CachedVisibility[type]);
if(EditorGUI.EndChangeCheck())
{
SetValue(type, value, true);
}
}
EditorGUI.indentLevel -= 2;
}
static void SetValue(Type type, bool value, bool repaint = false)
{
s_CachedVisibility[type] = value;
EditorPrefs.SetBool(componentPrefix + type.Name, value);
if(repaint)
EditorApplication.RepaintHierarchyWindow();
}
static void ToggleAll(bool value)
{
var allTypes = s_CachedVisibility.Keys.ToArray();
foreach(var type in allTypes)
{
SetValue(type, value);
}
EditorApplication.RepaintHierarchyWindow();
}
static void ToggleInvert()
{
var allTypes = s_CachedVisibility.Keys.ToArray();
foreach (var type in allTypes)
{
SetValue(type, !s_CachedVisibility[type]);
}
EditorApplication.RepaintHierarchyWindow();
}
}
}

11
Editor/AdvancedHierarchyView/AdvancedHierarchyPreferences.cs.meta


fileFormatVersion: 2
guid: 64b05588573cd7d4dbd975642cd735a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

240
Editor/AdvancedHierarchyView/AdvancedHierarchyView.cs


using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.VFX;
using UnityEditor;
using GameplayIngredients.StateMachines;
using UnityEngine.Playables;
using System.Linq;
using System.Reflection;
namespace GameplayIngredients.Editor
{
[InitializeOnLoad]
public static class AdvancedHierarchyView
{
const string kMenuPath = "Edit/Advanced Hierarchy View %.";
public const int kMenuPriority = 230;
[MenuItem(kMenuPath, priority = kMenuPriority, validate = false)]
static void Toggle()
{
if (Active)
Active = false;
else
Active = true;
}
[MenuItem(kMenuPath, priority = kMenuPriority, validate = true)]
static bool ToggleCheck()
{
Menu.SetChecked(kMenuPath, Active);
return SceneView.sceneViews.Count > 0;
}
static readonly string kPreferenceName = "GameplayIngredients.HierarchyHints";
public static bool Active
{
get
{
return EditorPrefs.GetBool(kPreferenceName, false);
}
set
{
EditorPrefs.SetBool(kPreferenceName, value);
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
}
static AdvancedHierarchyView()
{
EditorApplication.hierarchyWindowItemOnGUI -= HierarchyOnGUI;
EditorApplication.hierarchyWindowItemOnGUI += HierarchyOnGUI;
InitializeTypes();
}
static void InitializeTypes()
{
RegisterComponentType( typeof(MonoBehaviour), "cs Script Icon");
RegisterComponentType( typeof(Camera), "Camera Icon");
RegisterComponentType( typeof(MeshRenderer), "MeshRenderer Icon");
RegisterComponentType( typeof(SkinnedMeshRenderer), "SkinnedMeshRenderer Icon");
RegisterComponentType( typeof(BoxCollider), "BoxCollider Icon");
RegisterComponentType( typeof(SphereCollider), "SphereCollider Icon");
RegisterComponentType( typeof(CapsuleCollider), "CapsuleCollider Icon");
RegisterComponentType( typeof(MeshCollider), "MeshCollider Icon");
RegisterComponentType( typeof(AudioSource), "AudioSource Icon");
RegisterComponentType( typeof(Animation), "Animation Icon");
RegisterComponentType( typeof(Animator), "Animator Icon");
RegisterComponentType( typeof(PlayableDirector), "PlayableDirector Icon");
RegisterComponentType( typeof(Light), "Light Icon");
RegisterComponentType( typeof(LightProbeGroup), "LightProbeGroup Icon");
RegisterComponentType( typeof(LightProbeProxyVolume), "LightProbeProxyVolume Icon");
RegisterComponentType( typeof(ReflectionProbe), "ReflectionProbe Icon");
RegisterComponentType( typeof(VisualEffect), "VisualEffect Icon");
RegisterComponentType( typeof(ParticleSystem), "ParticleSystem Icon");
RegisterComponentType( typeof(Canvas), "Canvas Icon");
RegisterComponentType( typeof(Image), "Image Icon");
RegisterComponentType( typeof(Text), "Text Icon");
RegisterComponentType( typeof(Button), "Button Icon");
RegisterComponentType( typeof(Folder), "Folder Icon");
foreach(var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
var types = assembly.GetTypes();
foreach(var type in types)
{
if(type.IsSubclassOf(typeof(MonoBehaviour)) && !type.IsAbstract)
{
var attrib = type.GetCustomAttribute<AdvancedHierarchyIconAttribute>();
if(attrib != null)
{
RegisterComponentType(type, attrib.icon);
}
}
}
}
catch(Exception e)
{
Debug.LogWarning("Could not load types from assembly:" + assembly.FullName);
}
}
}
public static void RegisterComponentType(Type t, string iconName)
{
if (s_Definitions == null)
s_Definitions = new Dictionary<Type, string>();
if (!s_Definitions.ContainsKey(t))
s_Definitions.Add(t, iconName);
}
public static IEnumerable<Type> allTypes { get { return s_Definitions.Keys; } }
static Dictionary<Type, string> s_Definitions = new Dictionary<Type, string>();
static void HierarchyOnGUI(int instanceID, Rect selectionRect)
{
if (!Active) return;
var fullRect = selectionRect;
fullRect.xMin = 32;
fullRect.xMax = EditorGUIUtility.currentViewWidth;
GameObject o = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if (o == null) return;
var c = GUI.color;
bool isFolder = o.GetComponent<Folder>() != null;
if(isFolder)
{
fullRect.xMin += 28 + 14 * GetObjectDepth(o.transform);
fullRect.width = 16;
EditorGUI.DrawRect(fullRect, EditorGUIUtility.isProSkin? Styles.proBackground : Styles.personalBackground);
DrawIcon(fullRect, Contents.GetContent(typeof(Folder)), o.GetComponent<Folder>().Color);
}
else
{
if (o.isStatic && AdvancedHierarchyPreferences.showStatic)
{
GUI.Label(fullRect, " S");
EditorGUI.DrawRect(fullRect, Colors.dimGray);
}
foreach (var type in s_Definitions.Keys)
{
if(AdvancedHierarchyPreferences.IsVisible(type) && o.GetComponents(type).Length > 0)
selectionRect = DrawIcon(selectionRect, Contents.GetContent(type), Color.white);
}
}
GUI.color = c;
}
static int GetObjectDepth(Transform t, int depth=0)
{
if (t.parent == null)
return depth;
else
return GetObjectDepth(t.parent, depth + 1);
}
static Rect DrawIcon(Rect rect, GUIContent content, Color color, int size = 16)
{
GUI.color = color;
GUI.Label(rect, content, Styles.icon);
rect.width = rect.width - size;
return rect;
}
static class Contents
{
static Dictionary<Type, GUIContent> s_Icons = new Dictionary<Type, GUIContent>();
public static void AddIcon(Type type, string IconName)
{
GUIContent icon;
Texture texture = AssetDatabase.LoadAssetAtPath<Texture>(IconName);
if (texture == null)
icon = EditorGUIUtility.IconContent(IconName);
else
icon = new GUIContent(texture);
s_Icons.Add(type, icon);
}
public static GUIContent GetContent(Type t)
{
if (!s_Icons.ContainsKey(t) && s_Definitions.ContainsKey(t))
AddIcon(t,s_Definitions[t]);
return s_Icons[t];
}
}
static class Colors
{
public static Color orange = new Color(1.0f, 0.7f, 0.1f);
public static Color red = new Color(1.0f, 0.4f, 0.3f);
public static Color yellow = new Color(0.8f, 1.0f, 0.1f);
public static Color green = new Color(0.2f, 1.0f, 0.1f);
public static Color blue = new Color(0.5f, 0.8f, 1.0f);
public static Color violet = new Color(0.8f, 0.5f, 1.0f);
public static Color purple = new Color(1.0f, 0.5f, 0.8f);
public static Color dimGray = new Color(0.4f, 0.4f, 0.4f, 0.2f);
}
static class Styles
{
public static GUIStyle rightLabel;
public static GUIStyle icon;
public static Color proBackground = new Color(0.25f, 0.25f, 0.25f, 1.0f);
public static Color personalBackground = new Color(0.75f, 0.75f, 0.75f, 1.0f);
static Styles()
{
rightLabel = new GUIStyle(EditorStyles.label);
rightLabel.alignment = TextAnchor.MiddleRight;
rightLabel.normal.textColor = Color.white;
rightLabel.onNormal.textColor = Color.white;
rightLabel.active.textColor = Color.white;
rightLabel.onActive.textColor = Color.white;
icon = new GUIStyle(rightLabel);
icon.padding = new RectOffset();
icon.margin = new RectOffset();
}
}
}
}

/Editor/HierarchyHints.meta → /Editor/AdvancedHierarchyView.meta

/Runtime/PropertyAttributes.meta → /Runtime/Attributes.meta

/Runtime/PropertyAttributes → /Runtime/Attributes

/Editor/HierarchyHints/HierarchyHints.cs.meta → /Editor/AdvancedHierarchyView/AdvancedHierarchyView.cs.meta

正在加载...
取消
保存