轨迹插件引入
This commit is contained in:
1 parent
89b5275efd
commit
195893a1b0
1023 files changed
+378944
-18404
No files matched your search
@@ -0,0 +1,100 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public interface IDTClipboardHandler
|
||||
{
|
||||
void Copy(object value);
|
||||
object Paste(object data);
|
||||
bool CanPasteFrom(Type clipboardType);
|
||||
}
|
||||
|
||||
public class DTVector2Clipboard : IDTClipboardHandler
|
||||
{
|
||||
|
||||
public void Copy(object value)
|
||||
{
|
||||
DT.ClipBoardSet(value);
|
||||
EditorGUIUtility.systemCopyBuffer = value.GetType().Name;
|
||||
}
|
||||
|
||||
public object Paste(object data)
|
||||
{
|
||||
if (data is Vector2)
|
||||
return (Vector2)data;
|
||||
else if (data is Vector3)
|
||||
return new Vector2(((Vector3)data).x, ((Vector3)data).y);
|
||||
else if (data is Vector4)
|
||||
return new Vector2(((Vector4)data).x, ((Vector4)data).y);
|
||||
|
||||
return Vector2.zero;
|
||||
}
|
||||
|
||||
public bool CanPasteFrom(Type clipboardType)
|
||||
{
|
||||
return (clipboardType.Matches(typeof(Vector2), typeof(Vector3), typeof(Vector4)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class DTVector3Clipboard : IDTClipboardHandler
|
||||
{
|
||||
|
||||
public void Copy(object value)
|
||||
{
|
||||
DT.ClipBoardSet(value);
|
||||
EditorGUIUtility.systemCopyBuffer = value.GetType().Name;
|
||||
}
|
||||
|
||||
public object Paste(object data)
|
||||
{
|
||||
if (data is Vector3)
|
||||
return (Vector3)data;
|
||||
else if (data is Vector4)
|
||||
return new Vector3(((Vector4)data).x, ((Vector4)data).y, ((Vector4)data).z);
|
||||
|
||||
return Vector2.zero;
|
||||
}
|
||||
|
||||
public bool CanPasteFrom(Type clipboardType)
|
||||
{
|
||||
return (clipboardType.Matches(typeof(Vector3), typeof(Vector4)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class DTAnimationCurveClipboard : IDTClipboardHandler
|
||||
{
|
||||
public void Copy(object value)
|
||||
{
|
||||
DT.ClipBoardSet(value);
|
||||
}
|
||||
|
||||
public object Paste(object data)
|
||||
{
|
||||
AnimationCurve clp=(AnimationCurve)data;
|
||||
AnimationCurve curve=new AnimationCurve(clp.keys);
|
||||
curve.preWrapMode = clp.preWrapMode;
|
||||
curve.postWrapMode = clp.postWrapMode;
|
||||
return curve;
|
||||
}
|
||||
|
||||
public bool CanPasteFrom(Type clipboardType)
|
||||
{
|
||||
return clipboardType == typeof(AnimationCurve);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc604c1a18b9fa14da6b9d0f985e87e0
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a5a9263e8df6d24fbf7ceb6a674385a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using FluffyUnderware.DevTools;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
[CustomEditor(typeof(ComponentPool))]
|
||||
public class ComponentPoolEditor : DTEditor<ComponentPool>
|
||||
{
|
||||
protected override void OnCustomInspectorGUIBefore()
|
||||
{
|
||||
PoolManagerEditor.showBar(Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 007dc0ff09c5d97478ad4fe856644878
|
||||
timeCreated: 1441008968
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using FluffyUnderware.DevTools;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
[CustomEditor(typeof(PoolManager))]
|
||||
public class PoolManagerEditor : DTEditor<PoolManager>
|
||||
{
|
||||
|
||||
protected override void OnReadNodes()
|
||||
{
|
||||
Node.AddSection("Type Pools",typePoolsGUI);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void typePoolsGUI(DTInspectorNode node)
|
||||
{
|
||||
|
||||
foreach (KeyValuePair<Type, IPool> kv in Target.TypePools)
|
||||
{
|
||||
showBar(kv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void showBar(IPool pool)
|
||||
{
|
||||
Rect r = EditorGUILayout.GetControlRect(false, GUILayout.Height(20));
|
||||
float hi = Mathf.Max(pool.Count, pool.Settings.Threshold);
|
||||
Color c = Color.green;
|
||||
if (pool.Count < pool.Settings.MinItems)
|
||||
c = Color.yellow;
|
||||
else if (pool.Count > pool.Settings.Threshold)
|
||||
c = Color.red;
|
||||
DTGUI.PushContentColor(c);
|
||||
string s=pool.Identifier;
|
||||
if (!string.IsNullOrEmpty(s))
|
||||
{
|
||||
int i = s.IndexOf(",");
|
||||
if (i > 0)
|
||||
s = pool.Identifier.Substring(0, i);
|
||||
}
|
||||
EditorGUI.ProgressBar(r, pool.Count / hi, s + ":" + pool.Count.ToString());
|
||||
DTGUI.PopContentColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f1bf8d1bfc7bd84d88dbc07008b45ef
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,24 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using FluffyUnderware.DevTools;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
[CustomEditor(typeof(PrefabPool),true)]
|
||||
public class PrefabPoolEditor : DTEditor<PrefabPool>
|
||||
{
|
||||
protected override void OnCustomInspectorGUIBefore()
|
||||
{
|
||||
PoolManagerEditor.showBar(Target);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 034101b2c8b1d0647afbae54cbffb340
|
||||
timeCreated: 1440757122
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,328 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
using System.Reflection;
|
||||
using FluffyUnderware.DevTools;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static class DT
|
||||
{
|
||||
const char editorPreferencesArraySeparator = ';';
|
||||
|
||||
public const string VERSION = "1.0.3";
|
||||
/// <summary>
|
||||
/// Global override for float precision rounding (e.g. DTPropertyAttribute.Precision)
|
||||
/// </summary>
|
||||
public static bool _UseSnapValuePrecision;
|
||||
|
||||
|
||||
public delegate void Callback();
|
||||
|
||||
public static List<DTProject> Projects
|
||||
{
|
||||
get
|
||||
{
|
||||
return mProjects.Values.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public static DTProject Project(string identifier)
|
||||
{
|
||||
DTProject prj = null;
|
||||
if (!mProjects.TryGetValue(identifier, out prj))
|
||||
{
|
||||
LoadProjects();
|
||||
if (!mProjects.TryGetValue(identifier, out prj))
|
||||
DTLog.LogError("[DevTools] Unable to find project '" + identifier + "' !");
|
||||
}
|
||||
|
||||
return prj;
|
||||
}
|
||||
|
||||
static object mClipboardData;
|
||||
static Dictionary<Type, IDTClipboardHandler> mClipboardHandlers = new Dictionary<Type, IDTClipboardHandler>();
|
||||
static Dictionary<string, DTProject> mProjects = new Dictionary<string, DTProject>();
|
||||
|
||||
static bool _compiling;
|
||||
|
||||
static DT()
|
||||
{
|
||||
EditorApplication.update += delayedInitialize;
|
||||
EditorApplication.update -= compileCheck;
|
||||
EditorApplication.update += compileCheck;
|
||||
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
foreach (DTProject prj in DT.Projects)
|
||||
prj.Clear();
|
||||
DT.Projects.Clear();
|
||||
}
|
||||
|
||||
public static void ReInitialize(bool loadProjects = true)
|
||||
{
|
||||
if (loadProjects)
|
||||
LoadProjects();
|
||||
|
||||
DTToolbar.Initialize();
|
||||
HandleProjectsKeyBindings();
|
||||
}
|
||||
|
||||
static void delayedInitialize()
|
||||
{
|
||||
EditorApplication.update -= delayedInitialize;
|
||||
LoadPreferences();
|
||||
DTSelection.Initialize();
|
||||
ReInitialize();
|
||||
// Register Clipboard-Handlers
|
||||
RegisterClipboardType(typeof(Vector2), new DTVector2Clipboard());
|
||||
RegisterClipboardType(typeof(Vector3), new DTVector3Clipboard());
|
||||
RegisterClipboardType(typeof(AnimationCurve), new DTAnimationCurveClipboard());
|
||||
}
|
||||
|
||||
static void compileCheck()
|
||||
{
|
||||
if (!_compiling)
|
||||
{
|
||||
_compiling = EditorApplication.isCompiling;
|
||||
if (_compiling)
|
||||
Clear();
|
||||
}
|
||||
else
|
||||
_compiling = EditorApplication.isCompiling;
|
||||
}
|
||||
|
||||
#region ### Clipboard ###
|
||||
public static void RegisterClipboardType(Type dataType, IDTClipboardHandler handler, bool overwriteExisting = false)
|
||||
{
|
||||
if (mClipboardHandlers.ContainsKey(dataType))
|
||||
{
|
||||
if (overwriteExisting)
|
||||
mClipboardHandlers[dataType] = handler;
|
||||
}
|
||||
else
|
||||
mClipboardHandlers.Add(dataType, handler);
|
||||
}
|
||||
|
||||
public static void ClipboardCopy(object data)
|
||||
{
|
||||
Type dataType = data.GetType();
|
||||
IDTClipboardHandler handler;
|
||||
if (mClipboardHandlers.TryGetValue(dataType, out handler))
|
||||
{
|
||||
handler.Copy(data);
|
||||
}
|
||||
else
|
||||
DTLog.LogError("[DevTools] No ClipboardHandler for data type '" + data.GetType().Name + "' found!");
|
||||
}
|
||||
|
||||
public static T ClipboardPaste<T>()
|
||||
{
|
||||
IDTClipboardHandler handler;
|
||||
if (mClipboardData != null && mClipboardHandlers.TryGetValue(typeof(T), out handler))
|
||||
{
|
||||
if (handler.CanPasteFrom(mClipboardData.GetType()))
|
||||
{
|
||||
return (T)handler.Paste(mClipboardData);
|
||||
}
|
||||
}
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public static bool ClipboardCanPasteTo<T>()
|
||||
{
|
||||
IDTClipboardHandler handler;
|
||||
if (mClipboardData != null && mClipboardHandlers.TryGetValue(typeof(T), out handler))
|
||||
{
|
||||
return handler.CanPasteFrom(mClipboardData.GetType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static void ClipBoardSet(object data)
|
||||
{
|
||||
mClipboardData = data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ### Project Management ###
|
||||
|
||||
static void LoadProjects()
|
||||
{
|
||||
mProjects.Clear();
|
||||
TypeCache.TypeCollection types = TypeCache.GetTypesDerivedFrom(typeof(DTProject));
|
||||
foreach (Type t in types)
|
||||
{
|
||||
DTProject newProject = (DTProject)Activator.CreateInstance(t);
|
||||
mProjects.Add(newProject.Identifier, newProject);
|
||||
}
|
||||
}
|
||||
|
||||
static void HandleProjectsKeyBindings()
|
||||
{
|
||||
foreach (DTProject prj in Projects)
|
||||
if (!prj.CheckKeyBindingNamesAreUnique())
|
||||
return;
|
||||
else
|
||||
prj.LoadKeyBindingRemappings();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ### EditorPrefs-Helpers ###
|
||||
|
||||
static void LoadPreferences()
|
||||
{
|
||||
// Upgrade?
|
||||
string ver = GetEditorPrefs("FluffyUnderware.DevTools.Version", VERSION);
|
||||
if (ver != VERSION)
|
||||
{
|
||||
UpgradeDevTools(ver);
|
||||
SavePreferences();
|
||||
}
|
||||
}
|
||||
|
||||
static void SavePreferences()
|
||||
{
|
||||
SetEditorPrefs("FluffyUnderware.DevTools.Version", VERSION);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add code to handle upgrading (delete old pref-keys etc...) here
|
||||
/// </summary>
|
||||
/// <param name="oldVersion">the version stored in the EditorPrefs</param>
|
||||
static void UpgradeDevTools(string oldVersion)
|
||||
{
|
||||
DTLog.Log("[DevTools] Upgrading settings from " + oldVersion + " to " + VERSION);
|
||||
}
|
||||
|
||||
public static void SetEditorPrefs<T>(string key, T value)
|
||||
{
|
||||
Type tt = typeof(T);
|
||||
if (tt.IsEnum)
|
||||
{
|
||||
EditorPrefs.SetInt(key, Convert.ToInt32(Enum.Parse(typeof(T), value.ToString()) as Enum));
|
||||
}
|
||||
else if (tt.IsArray)
|
||||
{
|
||||
var list = (IList)value;
|
||||
string[] array = new string[list.Count];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i] = list[i].ToString();
|
||||
if(array[i].Contains(editorPreferencesArraySeparator))
|
||||
throw new ArgumentException(String.Format("value should not have any element containing a {0} character",editorPreferencesArraySeparator));
|
||||
}
|
||||
SetEditorPrefs(key, String.Join(editorPreferencesArraySeparator.ToString(), array));
|
||||
}
|
||||
else if (tt.Matches(typeof(int), typeof(Int32)))
|
||||
EditorPrefs.SetInt(key, (value as int?).Value);
|
||||
else if (tt == typeof(string))
|
||||
EditorPrefs.SetString(key, (value as string));
|
||||
else if (tt == typeof(float))
|
||||
EditorPrefs.SetFloat(key, (value as float?).Value);
|
||||
else if (tt == typeof(bool))
|
||||
EditorPrefs.SetBool(key, (value as bool?).Value);
|
||||
else if (tt == typeof(Color))
|
||||
EditorPrefs.SetString(key, (value as Color?).Value.ToHtml());
|
||||
else
|
||||
DTLog.LogError("[DevTools] SetEditorPrefs: Unsupported datatype: " + tt.Name);
|
||||
}
|
||||
|
||||
public static T GetEditorPrefs<T>(string key, T defaultValue)
|
||||
{
|
||||
if (EditorPrefs.HasKey(key))
|
||||
{
|
||||
Type tt = typeof(T);
|
||||
try
|
||||
{
|
||||
if (tt.IsEnum || tt.Matches(typeof(int), typeof(Int32)))
|
||||
{
|
||||
return (T)(object)EditorPrefs.GetInt(key, (int)(object)defaultValue);
|
||||
}
|
||||
else if (tt.IsArray)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
else if (tt == typeof(string))
|
||||
return (T)(object)EditorPrefs.GetString(key, defaultValue.ToString());
|
||||
else if (tt == typeof(float))
|
||||
return (T)(object)EditorPrefs.GetFloat(key, (float)(object)defaultValue);
|
||||
else if (tt == typeof(bool))
|
||||
return (T)(object)EditorPrefs.GetBool(key, (bool)(object)defaultValue);
|
||||
else if (tt == typeof(Color))
|
||||
return (T)(object)EditorPrefs.GetString(key, ((Color)(object)defaultValue).ToHtml()).ColorFromHtml();
|
||||
else
|
||||
DTLog.LogError("[DevTools] SetEditorPrefs: Unsupported datatype: " + tt.Name);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static string[] GetEditorPrefs(string key)
|
||||
{
|
||||
string arrayString = GetEditorPrefs(key, String.Empty);
|
||||
return String.IsNullOrEmpty(arrayString) ? new string[0] : arrayString.Split(editorPreferencesArraySeparator);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ### Utilities ###
|
||||
|
||||
/// <summary>
|
||||
/// Opens Unity's preferences window
|
||||
/// </summary>
|
||||
public static void OpenPreferencesWindow()
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
SettingsService.OpenUserPreferences();
|
||||
#else
|
||||
Assembly asm = Assembly.GetAssembly(typeof(EditorWindow));
|
||||
Type T = asm.GetType("UnityEditor.PreferencesWindow");
|
||||
if (T != null)
|
||||
{
|
||||
MethodInfo M = T.GetMethod("ShowPreferencesWindow", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
if (M != null)
|
||||
M.Invoke(null, null);
|
||||
else
|
||||
Debug.LogError("Couldn't find method ShowPreferencesWindow in type " + T.FullName);
|
||||
}
|
||||
else
|
||||
Debug.LogError("Couldn't find type UnityEditor.PreferencesWindow in assembly " + asm.FullName);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// Opens Unity's preferences window at a specific path. The path should be the same than the one of the associated <see cref="SettingsProvider"/>
|
||||
/// </summary>
|
||||
public static void OpenPreferencesWindow(string settingsPath)
|
||||
{
|
||||
SettingsService.OpenUserPreferences(settingsPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ae275390dd4915458afdfbc1948f159
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,59 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public class DTDebugWindow : EditorWindow
|
||||
{
|
||||
string Label;
|
||||
public string Text
|
||||
{
|
||||
get { return string.Join("", texts); }
|
||||
set
|
||||
{
|
||||
int size = Mathf.FloorToInt(value.Length / 16382);
|
||||
texts = new string[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
texts[i] = value.Substring(i * 16382, 16382);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vector2 scroll;
|
||||
|
||||
string[] texts;
|
||||
|
||||
GUIStyle stHtmlArea;
|
||||
|
||||
public static void Open(string label, string text, string windowName="Debug Dump")
|
||||
{
|
||||
DTDebugWindow win = EditorWindow.GetWindow<DTDebugWindow>(true, windowName);
|
||||
win.Label = label;
|
||||
win.Text = text;
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (stHtmlArea == null)
|
||||
{
|
||||
stHtmlArea = new GUIStyle(EditorStyles.textArea);
|
||||
stHtmlArea.richText = true;
|
||||
}
|
||||
GUILayout.Label(Label, EditorStyles.boldLabel);
|
||||
scroll = GUILayout.BeginScrollView(scroll);
|
||||
for (int i=0;i<texts.Length;i++)
|
||||
if (i==texts.Length-1)
|
||||
GUILayout.TextArea(texts[i],stHtmlArea,GUILayout.ExpandHeight(true));
|
||||
else
|
||||
GUILayout.TextArea(texts[i], stHtmlArea);
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e278c12763ea71f4fbb47021df15a348
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,512 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using FluffyUnderware.DevToolsEditor.Extensions;
|
||||
using FluffyUnderware.DevTools;
|
||||
using System;
|
||||
using UnityEditorInternal;
|
||||
using UnityEditor.AnimatedValues;
|
||||
using UnityEngine.Events;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public class DTEditor<T> : Editor where T : UnityEngine.Object
|
||||
{
|
||||
#region ### Public Properties ###
|
||||
|
||||
/// <summary>
|
||||
/// Target Script
|
||||
/// </summary>
|
||||
public virtual T Target
|
||||
{
|
||||
get
|
||||
{
|
||||
return (target != null) ? target as T : null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the target is currently selected or not
|
||||
/// </summary>
|
||||
public bool TargetIsActive
|
||||
{
|
||||
get
|
||||
{
|
||||
if (target is MonoBehaviour)
|
||||
return (target != null && ((MonoBehaviour)target).transform == Selection.activeTransform) ? true : false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the target is part of a prefab
|
||||
/// </summary>
|
||||
/// <remarks>Has issues with the new prefab system. See the comments in the code that assigns IsPrefab's value to know more about this</remarks>
|
||||
// TODO Has issues with the new prefab system. See the comments in the code that assigns IsPrefab's value to know more about this
|
||||
[Obsolete("Will get removed in the next major version. Use Unity's PrefabUtility to know if this.Target is part of a prefab")]
|
||||
public bool IsPrefab { get; private set; }
|
||||
|
||||
public bool IsInsideInspector { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The Root node of all inspector fields
|
||||
/// </summary>
|
||||
public DTGroupNode Node
|
||||
{
|
||||
get
|
||||
{
|
||||
return mRootNode;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The renderer used to render inspector fields
|
||||
/// </summary>
|
||||
public IDTInspectorNodeRenderer NodeRenderer
|
||||
{
|
||||
get
|
||||
{
|
||||
return mNodeRenderer;
|
||||
}
|
||||
set
|
||||
{
|
||||
mNodeRenderer = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether the inspector needs a repaint
|
||||
/// </summary>
|
||||
public bool NeedRepaint { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
DTGroupNode mRootNode;
|
||||
IDTInspectorNodeRenderer mNodeRenderer = new DTInspectorNodeDefaultRenderer();
|
||||
bool mEnterChildren;
|
||||
|
||||
#region ### Public Methods ###
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region ### Protected Methods (override to change inspector appearance) ###
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (mRootNode == null)
|
||||
mRootNode = new DTGroupNode("Root");
|
||||
Undo.undoRedoPerformed -= OnUndoRedo;
|
||||
Undo.undoRedoPerformed += OnUndoRedo;
|
||||
#pragma warning disable 618
|
||||
if (target != null)
|
||||
{
|
||||
PrefabAssetType prefabAssetType = PrefabUtility.GetPrefabAssetType(target);
|
||||
//BUG in the new prefab system, an instantiated prefab will have IsPrefab == true, while the documentation of the PrefabUtility.GetPrefabAssetType says otherwise. But is fixing this worth it knowing that IsPrefab is not used in Curvy when using the new prefab system?
|
||||
IsPrefab = prefabAssetType == PrefabAssetType.Regular || prefabAssetType == PrefabAssetType.Variant;
|
||||
}
|
||||
else
|
||||
IsPrefab = false;
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
if (mRootNode != null)
|
||||
mRootNode.Clear();
|
||||
Undo.undoRedoPerformed -= OnUndoRedo;
|
||||
}
|
||||
|
||||
protected virtual void OnReadNodes()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnSceneGUI()
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
RenderGUI(false);
|
||||
}
|
||||
|
||||
public void RenderGUI(bool embedded = false)
|
||||
{
|
||||
if (Target == null)
|
||||
return;
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
serializedObject.UpdateIfRequiredOrScript();
|
||||
#else
|
||||
serializedObject.UpdateIfDirtyOrScript();
|
||||
#endif
|
||||
|
||||
if (Node.Count == 0)
|
||||
ReadNodes();
|
||||
|
||||
NeedRepaint = false;
|
||||
|
||||
if (mRootNode)
|
||||
{
|
||||
DTInspectorNode.IsInsideInspector = !embedded;
|
||||
IsInsideInspector = !embedded;
|
||||
OnCustomInspectorGUIBefore();
|
||||
renderNode(mRootNode);
|
||||
OnCustomInspectorGUI();
|
||||
}
|
||||
if (serializedObject.ApplyModifiedProperties())
|
||||
OnModified();
|
||||
|
||||
GUI.SetNextControlName("");
|
||||
|
||||
if (NeedRepaint)
|
||||
Repaint();
|
||||
}
|
||||
|
||||
protected virtual void OnModified()
|
||||
{
|
||||
}
|
||||
|
||||
// <summary>
|
||||
/// Add custom GUI code here, rendered before the default inspector
|
||||
/// </summary>
|
||||
protected virtual void OnCustomInspectorGUIBefore()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add custom GUI code here, rendered after the default inspector
|
||||
/// </summary>
|
||||
protected virtual void OnCustomInspectorGUI()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to initialize a ReorderableList. Override to add custom behaviour
|
||||
/// </summary>
|
||||
/// <param name="node">field node</param>
|
||||
/// <param name="attribute">ArrayEx attribute of the field</param>
|
||||
protected virtual void SetupArrayEx(DTFieldNode node, ArrayExAttribute attribute)
|
||||
{
|
||||
// Defaults
|
||||
if (attribute.ShowHeader)
|
||||
{
|
||||
node.ArrayEx.drawHeaderCallback = (Rect r) =>
|
||||
{
|
||||
EditorGUI.LabelField(r, node.GUIContent);
|
||||
if (attribute.DropTarget)
|
||||
{
|
||||
Event ev = Event.current;
|
||||
switch (ev.type)
|
||||
{
|
||||
case EventType.DragUpdated:
|
||||
if (r.Contains(ev.mousePosition))
|
||||
{
|
||||
Type fieldType = node.serializedProperty.GetFieldType();
|
||||
//bug? this code is called when dragging a game object over the list of Input Spots, but not the list of Input Game Objects. Why? Both have the ArrayExAttribute with ShowHeader being true
|
||||
bool allowed = DragAndDrop.objectReferences.Length > 0 && DTEditorUtility.DragDropTypeMatch(fieldType);
|
||||
DragAndDrop.visualMode = allowed ? DragAndDropVisualMode.Copy : DragAndDropVisualMode.Rejected;
|
||||
}
|
||||
break;
|
||||
case EventType.DragPerform:
|
||||
if (r.Contains(ev.mousePosition))
|
||||
{
|
||||
Object[] objs = DTEditorUtility.DragDropGetObjectsOfType(node.serializedProperty.GetFieldType());
|
||||
|
||||
foreach (Object o in objs)
|
||||
{
|
||||
int idx = node.serializedProperty.arraySize;
|
||||
node.serializedProperty.InsertArrayElementAtIndex(idx);
|
||||
node.serializedProperty.GetArrayElementAtIndex(idx).objectReferenceValue = o;
|
||||
}
|
||||
node.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
node.ArrayEx.drawElementCallback = (Rect r, int index, bool isActive, bool isFocused) =>
|
||||
{
|
||||
SerializedProperty e = node.ArrayEx.serializedProperty.GetArrayElementAtIndex(index);
|
||||
if (e != null)
|
||||
EditorGUI.PropertyField(r, e);
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when UndoRedo occured
|
||||
/// </summary>
|
||||
public virtual void OnUndoRedo()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// builds node tree and process parsing attributes
|
||||
/// </summary>
|
||||
public void ReadNodes()
|
||||
{
|
||||
DTGroupNode._serializedObject = serializedObject;
|
||||
SerializedProperty iterator = serializedObject.GetIterator();
|
||||
mRootNode.Clear();
|
||||
mEnterChildren = true;
|
||||
|
||||
DTGroupNode baseNode = mRootNode;
|
||||
DTGroupNode parentNode = baseNode;
|
||||
Stack<string> propertyPathStack = new Stack<string>();
|
||||
Stack<DTGroupNode> baseNodeStack = new Stack<DTGroupNode>();
|
||||
bool resetParent = false;
|
||||
|
||||
while (iterator.NextVisible(mEnterChildren))
|
||||
{
|
||||
mEnterChildren = false;
|
||||
if (iterator.name != "m_Script" && iterator.name != "InspectorFoldout")
|
||||
{
|
||||
// handle baseNode resetting (AsGroup etc...)
|
||||
while (propertyPathStack.Count > 0 && !iterator.propertyPath.StartsWith(propertyPathStack.Peek()))
|
||||
{
|
||||
propertyPathStack.Pop();
|
||||
baseNode = baseNodeStack.Pop();
|
||||
parentNode = baseNode;
|
||||
}
|
||||
|
||||
|
||||
DTFieldNode fieldNode = new DTFieldNode(iterator);
|
||||
|
||||
// get group parsing attributes
|
||||
List<Attribute> groupParseAttribs = iterator.GetAttributes(typeof(IDTGroupParsingAttribute));
|
||||
groupParseAttribs.Sort();
|
||||
// get field parsing attributes
|
||||
List<Attribute> parsingAttributes = iterator.GetAttributes(typeof(IDTFieldParsingAttribute));
|
||||
|
||||
foreach (IDTGroupParsingAttribute ga in groupParseAttribs)
|
||||
{
|
||||
|
||||
if (ga is TabAttribute)
|
||||
{
|
||||
TabAttribute tabA = (TabAttribute)ga;
|
||||
parentNode = baseNode.EnsurePath(tabA.Path, false);
|
||||
|
||||
if (!string.IsNullOrEmpty(tabA.TabBarName) && !string.IsNullOrEmpty(tabA.TabName))
|
||||
{
|
||||
if (!parentNode[tabA.TabBarName])
|
||||
parentNode = (DTGroupNode)parentNode.Add(new DTGroupNode(tabA.TabBarName, null, DTInspectorNode.RenderAsEnum.TabBar));
|
||||
else
|
||||
parentNode = (DTGroupNode)parentNode[tabA.TabBarName];
|
||||
if (!parentNode[tabA.TabName])
|
||||
parentNode = (DTGroupNode)parentNode.Add(new DTGroupNode(tabA.TabName, iterator, DTInspectorNode.RenderAsEnum.Tab));
|
||||
else
|
||||
parentNode = (DTGroupNode)parentNode[tabA.TabName];
|
||||
if (tabA.Sort != 100)
|
||||
parentNode.SortOrder = tabA.Sort;
|
||||
}
|
||||
else
|
||||
DTLog.LogWarningFormat("[DevTools] Skipping [Tab] on '{0}' because Path is missing TabBar or Tab!", iterator.propertyPath);
|
||||
|
||||
}
|
||||
else if (ga is SectionAttribute)
|
||||
{
|
||||
SectionAttribute sectionA = (SectionAttribute)ga;
|
||||
parentNode = createGroup(baseNode, sectionA.Path, iterator);
|
||||
if (sectionA.Sort != 100)
|
||||
parentNode.SortOrder = sectionA.Sort;
|
||||
}
|
||||
else if (ga is AsGroupAttribute)
|
||||
{
|
||||
AsGroupAttribute asGroupA = (AsGroupAttribute)ga;
|
||||
propertyPathStack.Push(fieldNode.SerializedPropertyPath);
|
||||
baseNodeStack.Push(baseNode);
|
||||
parentNode = createGroup((asGroupA.PathIsAbsolute) ? baseNode : parentNode, (asGroupA.Path == null) ? fieldNode.Name : asGroupA.Path + "/" + fieldNode.Name, iterator);
|
||||
baseNode = parentNode;
|
||||
|
||||
}
|
||||
else if (ga is GroupAttribute)
|
||||
{
|
||||
GroupAttribute groupA = (GroupAttribute)ga;
|
||||
parentNode = createGroup(baseNode, groupA.Path, iterator);
|
||||
if (groupA.Sort != 100)
|
||||
parentNode.SortOrder = groupA.Sort;
|
||||
resetParent = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (IDTFieldParsingAttribute pa in parsingAttributes)
|
||||
{
|
||||
if (pa is Hide)
|
||||
{
|
||||
fieldNode.Visible = false;
|
||||
fieldNode.ContentVisible = false;
|
||||
mEnterChildren = false;
|
||||
}
|
||||
else if (pa is AsGroupAttribute || pa is Inline)
|
||||
{
|
||||
fieldNode.Visible = false;
|
||||
fieldNode.ContentVisible = false;
|
||||
mEnterChildren = true;
|
||||
|
||||
}
|
||||
else if (pa is ArrayExAttribute)
|
||||
{
|
||||
ArrayExAttribute arrayA = (ArrayExAttribute)pa;
|
||||
fieldNode.ArrayEx = new ReorderableList(serializedObject, iterator, arrayA.Draggable, arrayA.ShowHeader, arrayA.ShowAdd, arrayA.ShowDelete);
|
||||
SetupArrayEx(fieldNode, arrayA);
|
||||
}
|
||||
else if (pa is SortOrderAttribute)
|
||||
{
|
||||
fieldNode.SortOrder = ((SortOrderAttribute)pa).Sort;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
parentNode.Add(fieldNode);
|
||||
if (resetParent)
|
||||
{
|
||||
parentNode = parentNode.Parent as DTGroupNode;
|
||||
resetParent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
OnReadNodes();
|
||||
Node.Sort();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the node tree and process rendering attributes
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
void renderNode(DTInspectorNode node)
|
||||
{
|
||||
if (serializedObject == null)
|
||||
return;
|
||||
bool guistate = GUI.enabled;
|
||||
DTInspectorNode item;
|
||||
for (int i = 0; i < node.Items.Count; i++)
|
||||
{
|
||||
item = node[i];
|
||||
item.serializedObject = serializedObject;
|
||||
|
||||
if (item.Disabled)
|
||||
GUI.enabled = false;
|
||||
if (item is DTFieldNode)
|
||||
{
|
||||
|
||||
DTFieldNode field = (DTFieldNode)item;
|
||||
|
||||
field.serializedProperty = serializedObject.FindProperty(field.SerializedPropertyPath);
|
||||
if (field.serializedProperty == null)
|
||||
return;
|
||||
field.Calculate();
|
||||
|
||||
if (field.Visible)
|
||||
{
|
||||
foreach (ActionAttribute act in item.Actions)
|
||||
if (act.Position == ActionAttribute.ActionPositionEnum.Above)
|
||||
NodeRenderer.RenderAction(item, act, this, Target);
|
||||
|
||||
if (field.ArrayEx != null)
|
||||
{
|
||||
field.ArrayEx.serializedProperty = field.serializedProperty;
|
||||
field.ArrayEx.DoLayoutList();
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeRenderer.RenderField(field);
|
||||
field.raiseOnRender();
|
||||
}
|
||||
|
||||
foreach (ActionAttribute act in item.Actions)
|
||||
if (act.Position == ActionAttribute.ActionPositionEnum.Below)
|
||||
NodeRenderer.RenderAction(item, act, this, Target);
|
||||
}
|
||||
|
||||
}
|
||||
else if (item is DTGroupNode)
|
||||
{
|
||||
DTGroupNode group = (DTGroupNode)item;
|
||||
group.Calculate();
|
||||
|
||||
if (group.Visible)
|
||||
{
|
||||
foreach (ActionAttribute act in item.Actions)
|
||||
if (act.Position == ActionAttribute.ActionPositionEnum.Above)
|
||||
NodeRenderer.RenderAction(item, act, this, Target);
|
||||
|
||||
if (group.Disabled)
|
||||
GUI.enabled = false;
|
||||
|
||||
switch (item.RenderAs)
|
||||
{
|
||||
case DTInspectorNode.RenderAsEnum.Section:
|
||||
NodeRenderer.RenderSectionHeader(group);
|
||||
if (group.ContentVisible)
|
||||
{
|
||||
renderNode(group);
|
||||
group.raiseOnRender();
|
||||
}
|
||||
NodeRenderer.RenderSectionFooter(group);
|
||||
break;
|
||||
case DTInspectorNode.RenderAsEnum.TabBar:
|
||||
NodeRenderer.RenderTabBarHeader(group, (group.MaxItemsPerRow == -1) ? group.Items.Count : group.MaxItemsPerRow);
|
||||
if (group.SelectedIndex > -1)
|
||||
{
|
||||
renderNode(group[group.SelectedIndex]);
|
||||
group[group.SelectedIndex].raiseOnRender();
|
||||
}
|
||||
NodeRenderer.RenderTabBarFooter(group);
|
||||
break;
|
||||
default:
|
||||
if (group.ContentVisible)
|
||||
renderNode(group);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (ActionAttribute act in item.Actions)
|
||||
if (act.Position == ActionAttribute.ActionPositionEnum.Below)
|
||||
NodeRenderer.RenderAction(item, act, this, Target);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
GUI.enabled = guistate;
|
||||
if (item.NeedRepaint)
|
||||
{
|
||||
item.NeedRepaint = false;
|
||||
NeedRepaint = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a parent group for a field, creating the path if neccessary
|
||||
/// </summary>
|
||||
/// <param name="baseNode">"root" the path is applied to</param>
|
||||
/// <param name="path">node path</param>
|
||||
/// <param name="forProperty">field property the parent node is for</param>
|
||||
/// <returns></returns>
|
||||
DTGroupNode createGroup(DTGroupNode baseNode, string path, SerializedProperty forProperty)
|
||||
{
|
||||
DTGroupNode node = baseNode.EnsurePath(path, false, forProperty);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74ac27c5ac9d99c4d8071cdcc6c7c3aa
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,851 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using FluffyUnderware.DevTools;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
using FluffyUnderware.DevToolsEditor.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.AnimatedValues;
|
||||
using UnityEditorInternal;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public delegate void DTInspectorNodeEvent(DTInspectorNode e);
|
||||
|
||||
/// <summary>
|
||||
/// Base Node class
|
||||
/// </summary>
|
||||
public class DTInspectorNode : IComparable
|
||||
{
|
||||
public static bool IsInsideInspector { get; set; }
|
||||
public event DTInspectorNodeEvent OnNodeRender;
|
||||
|
||||
public enum RenderAsEnum { Invisible, Section, TabBar, Tab, Field };
|
||||
/// <summary>
|
||||
/// How to render this node
|
||||
/// </summary>
|
||||
public RenderAsEnum RenderAs = RenderAsEnum.Field;
|
||||
/// <summary>
|
||||
/// Gets a list of actions of this node
|
||||
/// </summary>
|
||||
public List<ActionAttribute> Actions = new List<ActionAttribute>();
|
||||
/// <summary>
|
||||
/// Parent node
|
||||
/// </summary>
|
||||
public DTInspectorNode Parent;
|
||||
/// <summary>
|
||||
/// Child nodes
|
||||
/// </summary>
|
||||
public List<DTInspectorNode> Items = new List<DTInspectorNode>();
|
||||
/// <summary>
|
||||
/// Gets the number of child nodes
|
||||
/// </summary>
|
||||
public int Count { get { return Items.Count; } }
|
||||
/// <summary>
|
||||
/// Gets all attributes for this node
|
||||
/// </summary>
|
||||
public List<Attribute> Attributes;
|
||||
/// <summary>
|
||||
/// Node name
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the node is expanded/visible or not
|
||||
/// </summary>
|
||||
public virtual bool Expanded { get; set; }
|
||||
/// <summary>
|
||||
/// Whether this node needs a repaint
|
||||
/// </summary>
|
||||
public virtual bool NeedRepaint { get; set; }
|
||||
/// <summary>
|
||||
/// Whether child nodes are visible or not
|
||||
/// </summary>
|
||||
public virtual bool ContentVisible
|
||||
{
|
||||
get { return mContentVisible; }
|
||||
set { mContentVisible = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this node is visible or not
|
||||
/// </summary>
|
||||
public virtual bool Visible
|
||||
{
|
||||
get { return mVisible; }
|
||||
set { mVisible = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether this node is disabled or not
|
||||
/// </summary>
|
||||
public virtual bool Disabled { get; set; }
|
||||
/// <summary>
|
||||
/// The serializedObject currently processed
|
||||
/// </summary>
|
||||
public SerializedObject serializedObject { get; set; }
|
||||
/// <summary>
|
||||
/// Label/Icon/Tooltip of this node
|
||||
/// </summary>
|
||||
public GUIContent GUIContent { get; set; }
|
||||
/// <summary>
|
||||
/// The absolute Path of this node
|
||||
/// </summary>
|
||||
public string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Parent) ? Parent.Path + "/" + Name : Name;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The nesting Level of this node
|
||||
/// </summary>
|
||||
public int Level { get; private set; }
|
||||
/// <summary>
|
||||
/// Sort order
|
||||
/// </summary>
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a child node by it's index
|
||||
/// </summary>
|
||||
/// <param name="index">index of the child</param>
|
||||
/// <returns>a node or null</returns>
|
||||
public DTInspectorNode this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return Items[index];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a child node by it's name
|
||||
/// </summary>
|
||||
/// <param name="name">name of the child</param>
|
||||
/// <returns>a node or null</returns>
|
||||
public DTInspectorNode this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
return Items.Find(x => x.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
public int Index { get; protected set; }
|
||||
|
||||
|
||||
|
||||
bool mContentVisible = true;
|
||||
bool mVisible = true;
|
||||
|
||||
|
||||
protected DTInspectorNode(string name)
|
||||
{
|
||||
SortOrder = 100;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public virtual int CompareTo(object obj)
|
||||
{
|
||||
DTInspectorNode other = (DTInspectorNode)obj;
|
||||
int c = SortOrder.CompareTo(other.SortOrder);
|
||||
return (c != 0) ? c : Index.CompareTo(other.Index);
|
||||
}
|
||||
/// <summary>
|
||||
/// Clear everything the node contains
|
||||
/// </summary>
|
||||
public virtual void Clear()
|
||||
{
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
Items[i].Clear();
|
||||
Items.Clear();
|
||||
}
|
||||
|
||||
public virtual DTInspectorNode Add(DTInspectorNode node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
Items.Add(node);
|
||||
node.Index = Items.IndexOf(node);
|
||||
node.Parent = this;
|
||||
node.Level = node.Parent.Level + 1;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public virtual void Calculate(bool firstRun = false) { }
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
foreach (DTInspectorNode it in Items)
|
||||
it.Delete();
|
||||
if (Parent)
|
||||
{
|
||||
Parent.Items.Remove(this);
|
||||
Parent.Sort(); // to reset Index
|
||||
}
|
||||
Parent = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a certain attribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the attribute</typeparam>
|
||||
/// <returns>the attribute or null</returns>
|
||||
public T GetAttribute<T>() where T : Attribute
|
||||
{
|
||||
return Attributes.Find(x => x.GetType().IsAssignableFrom(typeof(T))) as T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all attributes
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the attribute</typeparam>
|
||||
/// <returns>all attributes</returns>
|
||||
public T[] GetAllAttributes<T>() where T : Attribute
|
||||
{
|
||||
List<Attribute> res = Attributes.FindAll(x => x.GetType().IsAssignableFrom(typeof(T)));
|
||||
T[] r = new T[res.Count];
|
||||
for (int i = 0; i < res.Count; i++)
|
||||
r[i] = (T)res[i];
|
||||
return r;
|
||||
}
|
||||
|
||||
public static implicit operator bool(DTInspectorNode a)
|
||||
{
|
||||
return !object.ReferenceEquals(a, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search for a node at a specific path
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the node in question</typeparam>
|
||||
/// <param name="name">Path and Name of the node in question</param>
|
||||
/// <param name="node">The search result or null</param>
|
||||
/// <returns>true if found</returns>
|
||||
public bool FindNodeAt<T>(string pathAndName, out T node) where T : DTInspectorNode
|
||||
{
|
||||
string[] p = pathAndName.Split('/');
|
||||
node = null;
|
||||
DTInspectorNode N = this;
|
||||
for (int i = 0; i < p.Length; i++)
|
||||
{
|
||||
N = N[p[i]];
|
||||
if (N == null)
|
||||
return false;
|
||||
}
|
||||
node = N as T;
|
||||
return node != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search all child nodes for a node of the given type with a certain name
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the node in question</typeparam>
|
||||
/// <param name="name">Name of the node in question</param>
|
||||
/// <param name="node">The search result or null</param>
|
||||
/// <returns>true if found</returns>
|
||||
public bool FindNode<T>(string name, out T node) where T : DTInspectorNode
|
||||
{
|
||||
node = this[name] as T;
|
||||
if (node != null)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
foreach (DTInspectorNode it in Items)
|
||||
if (it.FindNode(name, out node))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sort child nodes
|
||||
/// </summary>
|
||||
public void Sort()
|
||||
{
|
||||
Items.Sort();
|
||||
|
||||
foreach (DTInspectorNode it in Items)
|
||||
{
|
||||
it.Index = Items.IndexOf(it);
|
||||
if (it is DTGroupNode)
|
||||
it.Sort();
|
||||
}
|
||||
}
|
||||
|
||||
internal void raiseOnRender()
|
||||
{
|
||||
if (OnNodeRender != null)
|
||||
OnNodeRender(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Field Node class
|
||||
/// </summary>
|
||||
public class DTFieldNode : DTInspectorNode
|
||||
{
|
||||
public string SerializedPropertyPath;
|
||||
public SerializedProperty serializedProperty { get; set; }
|
||||
public bool IncludeChildren { get; set; }
|
||||
public ReorderableList ArrayEx { get; set; }
|
||||
public string Tooltip { get; set; }
|
||||
public string HelpURL { get; set; }
|
||||
|
||||
public DTFieldNode(SerializedProperty property) : base(property.name)
|
||||
{
|
||||
RenderAs = RenderAsEnum.Field;
|
||||
SerializedPropertyPath = property.propertyPath;
|
||||
Attributes = property.GetAttributes(typeof(IDTFieldRenderAttribute));
|
||||
Attributes.Sort();
|
||||
GUIContent = new GUIContent(ObjectNames.NicifyVariableName(Name));
|
||||
Calculate(true);
|
||||
}
|
||||
|
||||
public override void Calculate(bool firstRun = false)
|
||||
{
|
||||
IncludeChildren = true;
|
||||
Visible = true;
|
||||
Disabled = false;
|
||||
Actions.Clear();
|
||||
foreach (IDTFieldRenderAttribute a in Attributes)
|
||||
{
|
||||
if (a is Hide || a is AsGroupAttribute)
|
||||
{
|
||||
Visible = false;
|
||||
ContentVisible = false;
|
||||
IncludeChildren = false;
|
||||
}
|
||||
else if (a is Inline)
|
||||
{
|
||||
Visible = false;
|
||||
IncludeChildren = true;
|
||||
}
|
||||
|
||||
else if (serializedProperty != null)
|
||||
{
|
||||
if (a is FieldConditionAttribute)
|
||||
{
|
||||
FieldConditionAttribute condA = (FieldConditionAttribute)a;
|
||||
bool met = condA.ConditionMet(serializedProperty.serializedObject.targetObject);
|
||||
|
||||
switch (condA.Action)
|
||||
{
|
||||
case ConditionalAttribute.ActionEnum.Show:
|
||||
Visible = met;
|
||||
break;
|
||||
case ConditionalAttribute.ActionEnum.Hide:
|
||||
Visible = !met;
|
||||
break;
|
||||
case ConditionalAttribute.ActionEnum.Enable:
|
||||
Disabled = !met;
|
||||
break;
|
||||
case ConditionalAttribute.ActionEnum.Disable:
|
||||
Disabled = met;
|
||||
break;
|
||||
default:
|
||||
if (met)
|
||||
Actions.Add(condA);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else if (a is FieldActionAttribute)
|
||||
{
|
||||
Actions.Add((FieldActionAttribute)a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Group node class
|
||||
/// </summary>
|
||||
public class DTGroupNode : DTInspectorNode
|
||||
{
|
||||
|
||||
static internal SerializedObject _serializedObject;
|
||||
|
||||
public override bool Expanded
|
||||
{
|
||||
get
|
||||
{
|
||||
return mState.target;
|
||||
}
|
||||
set
|
||||
{
|
||||
|
||||
if (mState.target != value)
|
||||
{
|
||||
mState.target = value;
|
||||
if (serializedObject != null)
|
||||
DTPersistentState.SetBool(serializedObject.targetObject.GetInstanceID().ToString() + Path, value);
|
||||
NeedRepaint = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float ExpandedFaded
|
||||
{
|
||||
get
|
||||
{
|
||||
return mState.faded;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ContentVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.ContentVisible && ExpandedFaded != 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.ContentVisible = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool NeedRepaint
|
||||
{
|
||||
get
|
||||
{
|
||||
return mState.isAnimating;
|
||||
}
|
||||
}
|
||||
|
||||
public string HelpURL { get; set; }
|
||||
public bool Fixed { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
#region --- Tab Bar Properties ---
|
||||
|
||||
public int SelectedIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return Count > 0 ? Mathf.Clamp(mSelectedItem, 0, Count - 1) : -1;
|
||||
}
|
||||
set
|
||||
{
|
||||
mSelectedItem = Count > 0 ? Mathf.Clamp(value, 0, Count - 1) : -1;
|
||||
}
|
||||
}
|
||||
|
||||
public DTInspectorNode SelectedItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return (SelectedIndex != -1) ? Items[SelectedIndex] : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
SelectedIndex = (value == null) ? -1 : value.Index;
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxItemsPerRow { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
AnimBool mState = new AnimBool(true);
|
||||
int mSelectedItem = -1;
|
||||
|
||||
public DTGroupNode(string name, SerializedProperty forProperty = null, RenderAsEnum renderAs = RenderAsEnum.Section) : base(name)
|
||||
{
|
||||
RenderAs = renderAs;
|
||||
MaxItemsPerRow = -1;
|
||||
if (forProperty != null)
|
||||
{
|
||||
Attributes = forProperty.GetAttributes(typeof(IDTGroupRenderAttribute));
|
||||
Attributes.Sort();
|
||||
Calculate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Attributes = new List<Attribute>();
|
||||
GUIContent = new GUIContent(ObjectNames.NicifyVariableName(Name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void Calculate(bool firstRun = false)
|
||||
{
|
||||
Actions.Clear();
|
||||
foreach (IDTGroupRenderAttribute a in Attributes)
|
||||
{
|
||||
if (a is GroupAttribute)
|
||||
{
|
||||
GroupAttribute groupA = (GroupAttribute)a;
|
||||
if (groupA.Invisible)
|
||||
RenderAs = RenderAsEnum.Invisible;
|
||||
if (firstRun)
|
||||
{
|
||||
mState.value = groupA.Expanded;
|
||||
getAdditionalGroupParams(groupA);
|
||||
}
|
||||
}
|
||||
else if (serializedObject != null)
|
||||
{
|
||||
if (a is GroupConditionAttribute)
|
||||
{
|
||||
GroupConditionAttribute condA = (GroupConditionAttribute)a;
|
||||
bool met = condA.ConditionMet(serializedObject.targetObject);
|
||||
|
||||
switch (condA.Action)
|
||||
{
|
||||
case ConditionalAttribute.ActionEnum.Show:
|
||||
Visible = met;
|
||||
break;
|
||||
case ConditionalAttribute.ActionEnum.Hide:
|
||||
Visible = !met;
|
||||
break;
|
||||
case ConditionalAttribute.ActionEnum.Enable:
|
||||
Disabled = !met;
|
||||
break;
|
||||
case ConditionalAttribute.ActionEnum.Disable:
|
||||
Disabled = met;
|
||||
break;
|
||||
default:
|
||||
if (met)
|
||||
Actions.Add(condA);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else if (a is GroupActionAttribute)
|
||||
{
|
||||
Actions.Add((GroupActionAttribute)a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getAdditionalGroupParams(GroupAttribute a)
|
||||
{
|
||||
if (a == null)
|
||||
{
|
||||
GUIContent = new GUIContent(ObjectNames.NicifyVariableName(Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIContent = new GUIContent(a.Label ?? ObjectNames.NicifyVariableName(Name), a.Tooltip);
|
||||
HelpURL = a.HelpURL;
|
||||
}
|
||||
}
|
||||
|
||||
public DTGroupNode EnsurePath(string path, bool includesName = false, SerializedProperty forProperty = null)
|
||||
{
|
||||
DTGroupNode node = this;
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
string[] p = path.Split('/');
|
||||
int hi = (includesName) ? p.Length - 1 : p.Length;
|
||||
for (int i = 0; i < hi; i++)
|
||||
{
|
||||
DTGroupNode sub = node[p[i]] as DTGroupNode;
|
||||
if (sub == null)
|
||||
{
|
||||
if (forProperty != null && i == hi - 1)
|
||||
sub = new DTGroupNode(p[i], forProperty);
|
||||
else
|
||||
sub = new DTGroupNode(p[i]);
|
||||
node.Add(sub);
|
||||
}
|
||||
node = sub;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public GUIContent[] GetItemsGUIContent()
|
||||
{
|
||||
GUIContent[] res = new GUIContent[Count];
|
||||
for (int i = 0; i < Count; i++)
|
||||
res[i] = this[i].GUIContent;
|
||||
return res;
|
||||
}
|
||||
|
||||
public DTGroupNode FindTabBarAt(string nameAndPath)
|
||||
{
|
||||
DTGroupNode node;
|
||||
if (FindNodeAt(nameAndPath, out node))
|
||||
if (node.RenderAs == RenderAsEnum.TabBar)
|
||||
return node;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override DTInspectorNode Add(DTInspectorNode node)
|
||||
{
|
||||
node = base.Add(node);
|
||||
DTGroupNode grp = node as DTGroupNode;
|
||||
if (grp != null && _serializedObject != null && _serializedObject.targetObject != null)
|
||||
grp.mState.value = DTPersistentState.GetBool(_serializedObject.targetObject.GetInstanceID().ToString() + grp.Path, grp.mState.value);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public DTGroupNode AddSection(string name, DTInspectorNodeEvent func)
|
||||
{
|
||||
DTInspectorNode item = this[name];
|
||||
if (item)
|
||||
{
|
||||
if (item.RenderAs != RenderAsEnum.Section)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = new DTGroupNode(name, null, RenderAsEnum.Section);
|
||||
Add(item);
|
||||
item.OnNodeRender += func;
|
||||
}
|
||||
return item as DTGroupNode;
|
||||
}
|
||||
|
||||
public DTGroupNode AddTab(string name, DTInspectorNodeEvent func)
|
||||
{
|
||||
if (RenderAs == RenderAsEnum.TabBar)
|
||||
{
|
||||
DTInspectorNode item = this[name];
|
||||
if (item)
|
||||
{
|
||||
if (item.RenderAs != RenderAsEnum.Tab)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = new DTGroupNode(name, null, RenderAsEnum.Tab);
|
||||
Add(item);
|
||||
item.OnNodeRender += func;
|
||||
}
|
||||
return item as DTGroupNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class DTPersistentState
|
||||
{
|
||||
static Dictionary<string, bool> _states = new Dictionary<string, bool>();
|
||||
|
||||
|
||||
public static bool GetBool(string ident, bool defaultState = true)
|
||||
{
|
||||
|
||||
bool res;
|
||||
if (!_states.TryGetValue(ident, out res))
|
||||
{
|
||||
res = defaultState;
|
||||
_states.Add(ident, defaultState);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void SetBool(string ident, bool state)
|
||||
{
|
||||
if (!_states.ContainsKey(ident))
|
||||
_states.Add(ident, state);
|
||||
else
|
||||
_states[ident] = state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region ### Renderer ###
|
||||
|
||||
public interface IDTInspectorNodeRenderer
|
||||
{
|
||||
void RenderTabBarHeader(DTGroupNode node, int maxItemsPerRow);
|
||||
void RenderTabBarFooter(DTGroupNode node);
|
||||
void RenderSectionHeader(DTGroupNode node);
|
||||
void RenderSectionFooter(DTGroupNode node);
|
||||
void RenderField(DTFieldNode node);
|
||||
void RenderAction(DTInspectorNode node, ActionAttribute action, System.Object editorObject, System.Object targetObject);
|
||||
}
|
||||
|
||||
public class DTInspectorNodeDefaultRenderer : IDTInspectorNodeRenderer
|
||||
{
|
||||
|
||||
|
||||
public static Texture HelpIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mHelpIcon == null)
|
||||
mHelpIcon = (Texture)EditorGUIUtility.Load("icons/_Help.png");
|
||||
return mHelpIcon;
|
||||
}
|
||||
}
|
||||
static Texture mHelpIcon;
|
||||
public static GUIStyle BoldFoldout
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mBoldFoldout == null)
|
||||
{
|
||||
mBoldFoldout = new GUIStyle(EditorStyles.foldout);
|
||||
mBoldFoldout.fontStyle = FontStyle.Bold;
|
||||
mBoldFoldout.margin.top += 2;
|
||||
mBoldFoldout.margin.bottom += 4;
|
||||
|
||||
}
|
||||
return mBoldFoldout;
|
||||
}
|
||||
}
|
||||
static GUIStyle mBoldFoldout;
|
||||
|
||||
public static GUIStyle TabbarButton
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mTabbarButton == null)
|
||||
{
|
||||
mTabbarButton = new GUIStyle(EditorStyles.toolbarButton);
|
||||
mTabbarButton.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
GUIStyle skinButton = GUI.skin.button;
|
||||
RectOffset skinButtonPadding = skinButton.padding;
|
||||
RectOffset skinButtonMargin = skinButton.margin;
|
||||
RectOffset skinButtonBorder = skinButton.border;
|
||||
RectOffset skinButtonOverflow = skinButton.overflow;
|
||||
|
||||
mTabbarButton.padding = new RectOffset(skinButtonPadding.left, skinButtonPadding.right, skinButtonPadding.top, skinButtonPadding.bottom);
|
||||
mTabbarButton.margin = new RectOffset(skinButtonMargin.left, skinButtonMargin.right, skinButtonMargin.top, skinButtonMargin.bottom);
|
||||
mTabbarButton.border = new RectOffset(skinButtonBorder.left, skinButtonBorder.right, skinButtonBorder.top, skinButtonBorder.bottom);
|
||||
mTabbarButton.overflow = new RectOffset(skinButtonOverflow.left, skinButtonOverflow.right, skinButtonOverflow.top, skinButtonOverflow.bottom);
|
||||
}
|
||||
|
||||
return mTabbarButton;
|
||||
}
|
||||
}
|
||||
static GUIStyle mTabbarButton;
|
||||
|
||||
public virtual void RenderAction(DTInspectorNode node, ActionAttribute action, System.Object editorObject, System.Object targetObject)
|
||||
{
|
||||
switch (action.Action)
|
||||
{
|
||||
case ActionAttribute.ActionEnum.ShowInfo:
|
||||
EditorGUILayout.HelpBox(action.ActionData as string, MessageType.Info);
|
||||
return;
|
||||
case ActionAttribute.ActionEnum.ShowWarning:
|
||||
EditorGUILayout.HelpBox(action.ActionData as string, MessageType.Warning);
|
||||
return;
|
||||
case ActionAttribute.ActionEnum.ShowError:
|
||||
EditorGUILayout.HelpBox(action.ActionData as string, MessageType.Error);
|
||||
return;
|
||||
case ActionAttribute.ActionEnum.Callback:
|
||||
action.Callback(editorObject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void RenderField(DTFieldNode node)
|
||||
{
|
||||
EditorGUILayout.PropertyField(node.serializedProperty, node.IncludeChildren);
|
||||
}
|
||||
|
||||
public virtual void RenderSectionHeader(DTGroupNode node)
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
|
||||
string helpUrl = node.HelpURL;
|
||||
|
||||
Rect controlRect = EditorGUILayout.GetControlRect(false, 16);
|
||||
int xOffset = (node.Level <= 1 && DTInspectorNode.IsInsideInspector) ? 12 : 0;
|
||||
controlRect.x -= xOffset;
|
||||
|
||||
bool toggleState = node.Expanded;
|
||||
int indentLevel = RenderHeader(controlRect, xOffset, helpUrl, node.GUIContent, ref toggleState);
|
||||
|
||||
node.Expanded = toggleState;
|
||||
EditorGUILayout.BeginFadeGroup(node.ExpandedFaded);
|
||||
EditorGUI.indentLevel = (node.Level <= 1) ? indentLevel : indentLevel + 1;
|
||||
}
|
||||
|
||||
#pragma warning disable 162
|
||||
#pragma warning disable 429
|
||||
private static readonly Color SectionHeaderBackgroundColor =
|
||||
DTEditorUtility.UsesNewEditorUI ? new Color(1f, 1f, 1f) : new Color(0.8f, 0.8f, 0.8f);
|
||||
#pragma warning restore 429
|
||||
#pragma warning restore 162
|
||||
public static int RenderHeader(Rect controlRect, int xOffset, string helpUrl, GUIContent toggleGuiContent, ref bool toggleState)
|
||||
{
|
||||
int indentLevel = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = Mathf.Max(0, indentLevel - 1);
|
||||
controlRect = EditorGUI.IndentedRect(controlRect);
|
||||
DTGUI.PushColor(SectionHeaderBackgroundColor);
|
||||
const int additionalHeight = 4;
|
||||
Rect boxRectangle = new Rect(controlRect.x, controlRect.y - 2, controlRect.width + xOffset + 1, controlRect.height + additionalHeight);
|
||||
GUI.Box(boxRectangle, "", GUI.skin.box);
|
||||
DTHandles.DrawOutline(boxRectangle, Color.black);
|
||||
DTGUI.PopColor();
|
||||
|
||||
Rect expandClickableArea = new Rect(controlRect);
|
||||
bool hasHelp = !string.IsNullOrEmpty(helpUrl);
|
||||
if (hasHelp)
|
||||
expandClickableArea.width -= 12;
|
||||
|
||||
toggleState = GUI.Toggle(expandClickableArea, toggleState, toggleGuiContent, BoldFoldout);
|
||||
if (hasHelp)
|
||||
{
|
||||
if (GUI.Button(new Rect(boxRectangle.xMax - 20, boxRectangle.y + 3, 16, 16)
|
||||
, new GUIContent(HelpIcon, "Help"), new GUIStyle()))
|
||||
Application.OpenURL(helpUrl);
|
||||
}
|
||||
|
||||
GUILayout.Space(additionalHeight);
|
||||
return indentLevel;
|
||||
}
|
||||
|
||||
public virtual void RenderSectionFooter(DTGroupNode node)
|
||||
{
|
||||
if (node.Level > 1)
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.EndFadeGroup();
|
||||
}
|
||||
|
||||
public virtual void RenderTabBarHeader(DTGroupNode node, int maxItemsPerRow)
|
||||
{
|
||||
GUILayout.Space(4);
|
||||
|
||||
int s = GUILayout.SelectionGrid(node.SelectedIndex, node.GetItemsGUIContent(), Mathf.Min(node.Count, maxItemsPerRow), TabbarButton);
|
||||
if (s != node.SelectedIndex)
|
||||
{
|
||||
node.SelectedIndex = s;
|
||||
GUIUtility.keyboardControl = 0;
|
||||
}
|
||||
Color c = GUI.color;
|
||||
if (!EditorGUIUtility.isProSkin)
|
||||
GUI.color = new Color(c.r, c.g, c.b, 0.5f);
|
||||
|
||||
GUILayout.BeginVertical(GUI.skin.box);
|
||||
GUI.color = c;
|
||||
}
|
||||
|
||||
public virtual void RenderTabBarFooter(DTGroupNode node)
|
||||
{
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c82ecfa39ebfe4a4984a5602b822ca2d
|
||||
timeCreated: 1436962698
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,159 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
using System.Collections;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public static class DTEditorUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// Does Unity use the new editor's UI?
|
||||
/// </summary>
|
||||
public const bool UsesNewEditorUI
|
||||
#if UNITY_2019_3_OR_NEWER //new UI
|
||||
= true;
|
||||
#else
|
||||
= false;
|
||||
#endif
|
||||
|
||||
public static Camera ActiveCamera
|
||||
{
|
||||
get
|
||||
{
|
||||
return (SceneView.currentDrawingSceneView) ? SceneView.currentDrawingSceneView.camera : Camera.current;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool DragDropTypeMatch(System.Type type)
|
||||
{
|
||||
foreach (Object go in DragAndDrop.objectReferences)
|
||||
{
|
||||
if (go is GameObject)
|
||||
{
|
||||
if (type.IsSubclassOf(typeof(Component)) == false)
|
||||
return false;
|
||||
if (((GameObject)go).GetComponent(type) == null)
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (go.GetType() != type)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool DragDropTypeMatch<T>() where T : Object
|
||||
{
|
||||
return DragDropTypeMatch(typeof(T));
|
||||
}
|
||||
|
||||
public static Object[] DragDropGetObjectsOfType(System.Type type)
|
||||
{
|
||||
if (type.IsArrayOrList())
|
||||
return new Object[0];
|
||||
List<Object> res = new List<Object>();
|
||||
foreach (Object o in DragAndDrop.objectReferences)
|
||||
{
|
||||
if (o.GetType() == type)
|
||||
res.Add(o);
|
||||
else if (o is GameObject)
|
||||
{
|
||||
Component f = ((GameObject)o).GetComponent(type);
|
||||
if (f != null)
|
||||
res.Add(f);
|
||||
}
|
||||
}
|
||||
return res.ToArray();
|
||||
}
|
||||
|
||||
public static T CreateAsset<T>() where T : ScriptableObject
|
||||
{
|
||||
T asset = ScriptableObject.CreateInstance<T>();
|
||||
ProjectWindowUtil.CreateAsset(asset, "New " + typeof(T).Name + ".asset");
|
||||
AssetDatabase.SaveAssets();
|
||||
return asset;
|
||||
}
|
||||
|
||||
public static void ToggleSceneViewGizmos(bool gizmosOn)
|
||||
{
|
||||
ToggleSceneViewGizmos(gizmosOn, new string[0]);
|
||||
}
|
||||
|
||||
public static void ToggleSceneViewGizmos(bool gizmosOn, params string[] scriptClasses)
|
||||
{
|
||||
int val = gizmosOn ? 1 : 0;
|
||||
List<string> classes = new List<string>(scriptClasses);
|
||||
Assembly asm = Assembly.GetAssembly(typeof(Editor));
|
||||
System.Type type = asm.GetType("UnityEditor.AnnotationUtility");
|
||||
if (type != null)
|
||||
{
|
||||
MethodInfo getAnnotations = type.GetMethod("GetAnnotations", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
if (getAnnotations != null)
|
||||
{
|
||||
MethodInfo setGizmoEnabled = type.GetMethod("SetGizmoEnabled", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
if (setGizmoEnabled != null)
|
||||
{
|
||||
MethodInfo setIconEnabled = type.GetMethod("SetIconEnabled", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
if (setIconEnabled != null)
|
||||
{
|
||||
object annotations = getAnnotations.Invoke(null, null);
|
||||
foreach (object annotation in (IEnumerable)annotations)
|
||||
{
|
||||
Type annotationType = annotation.GetType();
|
||||
FieldInfo classIdField = annotationType.GetField("classID", BindingFlags.Public | BindingFlags.Instance);
|
||||
FieldInfo scriptClassField = annotationType.GetField("scriptClass", BindingFlags.Public | BindingFlags.Instance);
|
||||
if (classIdField != null && scriptClassField != null)
|
||||
{
|
||||
int classId = (int)classIdField.GetValue(annotation);
|
||||
string scriptClass = (string)scriptClassField.GetValue(annotation);
|
||||
if (classes.Count == 0 || classes.Contains(scriptClass))
|
||||
{
|
||||
setGizmoEnabled.Invoke(null, new object[] { classId, scriptClass, val });
|
||||
setIconEnabled.Invoke(null, new object[] { classId, scriptClass, val });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Debug.LogError("Couldn't find method SetIconEnabled in type " + type.FullName);
|
||||
}
|
||||
else
|
||||
Debug.LogError("Couldn't find method SetGizmoEnabled in type " + type.FullName);
|
||||
}
|
||||
else
|
||||
Debug.LogError("Couldn't find method GetAnnotations in type " + type.FullName);
|
||||
}
|
||||
else
|
||||
Debug.LogError("Couldn't find type UnityEditor.AnnotationUtility in assembly " + asm.FullName);
|
||||
}
|
||||
|
||||
public static List<T> LoadPrefabsContaining<T>(string path) where T : UnityEngine.Component
|
||||
{
|
||||
List<T> res = new List<T>();
|
||||
|
||||
string[] gos = AssetDatabase.FindAssets("t:gameobject", new string[] { path });
|
||||
foreach (string id in gos)
|
||||
{
|
||||
GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(id));
|
||||
T cmp = go.GetComponent<T>();
|
||||
if (cmp != null)
|
||||
res.Add(cmp);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d1ee7bd8bdd696409b8ed1a10163e05
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,201 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public static class DTGUI
|
||||
{
|
||||
static Stack<Color> _BGColorStack = new Stack<Color>();
|
||||
static Stack<Color> _ColorStack = new Stack<Color>();
|
||||
static Stack<Color> _ContentColorStack = new Stack<Color>();
|
||||
|
||||
|
||||
#region --- Colors ---
|
||||
|
||||
public static void PushColor(Color col)
|
||||
{
|
||||
_ColorStack.Push(GUI.color);
|
||||
GUI.color = col;
|
||||
}
|
||||
|
||||
public static void PopColor()
|
||||
{
|
||||
GUI.color = _ColorStack.Pop();
|
||||
}
|
||||
|
||||
public static void PushBackgroundColor(Color col)
|
||||
{
|
||||
_BGColorStack.Push(GUI.color);
|
||||
GUI.color = col;
|
||||
}
|
||||
|
||||
public static void PopBackgroundColor()
|
||||
{
|
||||
GUI.color = _BGColorStack.Pop();
|
||||
}
|
||||
|
||||
public static void PushContentColor(Color col)
|
||||
{
|
||||
_ContentColorStack.Push(GUI.contentColor);
|
||||
GUI.contentColor = col;
|
||||
}
|
||||
|
||||
public static void PopContentColor()
|
||||
{
|
||||
GUI.contentColor = _ContentColorStack.Pop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- Events ---
|
||||
|
||||
public static bool IsClick
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Event.current!=null && Event.current.type == EventType.MouseDown && Event.current.button == 0);
|
||||
}
|
||||
}
|
||||
public static bool IsContextClick
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Event.current != null && Event.current.type == EventType.MouseDown && Event.current.button == 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsLayout { get { return Event.current != null && Event.current.type == EventType.Layout; } }
|
||||
public static bool IsRepaint { get { return Event.current != null && Event.current.type == EventType.Repaint; } }
|
||||
|
||||
public static Vector2 MousePosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Event.current != null) ? Event.current.mousePosition : Vector2.zero;
|
||||
}
|
||||
}
|
||||
|
||||
public static void UseEvent(int hashcode, Event e)
|
||||
{
|
||||
int controlID = GUIUtility.GetControlID(hashcode, FocusType.Passive);
|
||||
GUIUtility.hotControl = controlID;
|
||||
e.Use();
|
||||
GUIUtility.hotControl = 0;
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- Controls ---
|
||||
|
||||
public static void HtmlHelpBox(string message, MessageType type = MessageType.None)
|
||||
{
|
||||
GUIContent c;
|
||||
switch (type)
|
||||
{
|
||||
case MessageType.Info:
|
||||
c = EditorGUIUtility.IconContent("console.infoicon");
|
||||
break;
|
||||
case MessageType.Warning:
|
||||
c = EditorGUIUtility.IconContent("console.warningicon");
|
||||
break;
|
||||
case MessageType.Error:
|
||||
c = EditorGUIUtility.IconContent("console.erroricon");
|
||||
break;
|
||||
default:
|
||||
c = new GUIContent();
|
||||
break;
|
||||
}
|
||||
c.text=message;
|
||||
GUILayout.Label(c, DTStyles.HtmlHelpBox);
|
||||
}
|
||||
|
||||
public static Vector2 CompactVector2Field(Rect position, Vector2 value)
|
||||
{
|
||||
float labelWidth = 13f;
|
||||
|
||||
float num2 = (position.width - 2) / 2f;
|
||||
Rect position2 = new Rect(position);
|
||||
position2.width = num2;
|
||||
float labelWidth2 = EditorGUIUtility.labelWidth;
|
||||
int indentLevel = EditorGUI.indentLevel;
|
||||
EditorGUIUtility.labelWidth = labelWidth;
|
||||
EditorGUI.indentLevel = 0;
|
||||
value.x = EditorGUI.FloatField(position2, "X", value.x);
|
||||
position2.x += num2 + 2f;
|
||||
value.y = EditorGUI.FloatField(position2, "Y", value.y);
|
||||
|
||||
EditorGUIUtility.labelWidth = labelWidth2;
|
||||
EditorGUI.indentLevel = indentLevel;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Vector3 CompactVector3Field(Rect position, Vector3 value)
|
||||
{
|
||||
float labelWidth = 13f;
|
||||
float num2 = (position.width - 4) / 3f;
|
||||
Rect position2 = new Rect(position);
|
||||
position2.width = num2;
|
||||
float labelWidth2 = EditorGUIUtility.labelWidth;
|
||||
int indentLevel = EditorGUI.indentLevel;
|
||||
EditorGUIUtility.labelWidth = labelWidth;
|
||||
EditorGUI.indentLevel = 0;
|
||||
value.x = EditorGUI.FloatField(position2, "X", value.x);
|
||||
position2.x += num2 + 2f;
|
||||
value.y = EditorGUI.FloatField(position2, "Y", value.y);
|
||||
position2.x += num2 + 2f;
|
||||
value.z = EditorGUI.FloatField(position2, "Z", value.z);
|
||||
|
||||
EditorGUIUtility.labelWidth = labelWidth2;
|
||||
EditorGUI.indentLevel = indentLevel;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static bool LinkButton(Rect position, GUIContent content, ref bool repaint)
|
||||
{
|
||||
if (position.Contains(DTGUI.MousePosition))
|
||||
repaint = true;
|
||||
return GUI.Button(position, content, DTStyles.HtmlLinkLabel);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static float LabelWidth(string label)
|
||||
{
|
||||
return LabelWidth(new GUIContent(label));
|
||||
}
|
||||
public static float LabelWidth(GUIContent label)
|
||||
{
|
||||
return EditorStyles.label.CalcSize(label).x;
|
||||
}
|
||||
|
||||
public static Rect FromTo(this Vector2 start, Vector2 end)
|
||||
{
|
||||
Rect result = new Rect(start.x, start.y, end.x - start.x, end.y - start.y);
|
||||
if (result.width < 0f)
|
||||
{
|
||||
result.x += result.width;
|
||||
result.width = -result.width;
|
||||
}
|
||||
if (result.height < 0f)
|
||||
{
|
||||
result.y += result.height;
|
||||
result.height = -result.height;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef286eb30f9728447bb8584e9a582119
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,538 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public static class DTHandles
|
||||
{
|
||||
public static class SnapSettings
|
||||
{
|
||||
private static float s_MoveSnapX;
|
||||
private static float s_MoveSnapY;
|
||||
private static float s_MoveSnapZ;
|
||||
private static float s_ScaleSnap;
|
||||
private static float s_RotationSnap;
|
||||
private static bool s_Initialized;
|
||||
|
||||
private static void Initialize()
|
||||
{
|
||||
if (!s_Initialized)
|
||||
{
|
||||
s_MoveSnapX = EditorPrefs.GetFloat("MoveSnapX", 1f);
|
||||
s_MoveSnapY = EditorPrefs.GetFloat("MoveSnapY", 1f);
|
||||
s_MoveSnapZ = EditorPrefs.GetFloat("MoveSnapZ", 1f);
|
||||
s_ScaleSnap = EditorPrefs.GetFloat("ScaleSnap", 0.1f);
|
||||
s_RotationSnap = EditorPrefs.GetFloat("RotationSnap", 15f);
|
||||
s_Initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3 Move
|
||||
{
|
||||
get { return new Vector3(MoveX, MoveY, MoveZ); }
|
||||
}
|
||||
public static float MoveX
|
||||
{
|
||||
get { Initialize(); return s_MoveSnapX; }
|
||||
}
|
||||
public static float MoveY
|
||||
{
|
||||
get { Initialize(); return s_MoveSnapY; }
|
||||
}
|
||||
public static float MoveZ
|
||||
{
|
||||
get { Initialize(); return s_MoveSnapZ; }
|
||||
}
|
||||
public static float Rotation
|
||||
{
|
||||
get { Initialize(); return s_RotationSnap; }
|
||||
}
|
||||
public static float ScaleSnap
|
||||
{
|
||||
get { Initialize(); return s_ScaleSnap; }
|
||||
}
|
||||
}
|
||||
|
||||
public static bool MouseOverSceneView
|
||||
{
|
||||
get
|
||||
{
|
||||
return (SceneView.currentDrawingSceneView != null && Event.current != null) ?
|
||||
SceneView.currentDrawingSceneView.position.Contains(GUIUtility.GUIToScreenPoint(Event.current.mousePosition)) : false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SceneViewIsSelected
|
||||
{
|
||||
get
|
||||
{
|
||||
return SceneView.focusedWindow == SceneView.currentDrawingSceneView;
|
||||
}
|
||||
}
|
||||
|
||||
static Stack<Color> mHandlesColorstack = new Stack<Color>();
|
||||
|
||||
public static void PushHandlesColor(Color col)
|
||||
{
|
||||
mHandlesColorstack.Push(GUI.color);
|
||||
Handles.color = col;
|
||||
}
|
||||
|
||||
public static void PopHandlesColor()
|
||||
{
|
||||
Handles.color = mHandlesColorstack.Pop();
|
||||
}
|
||||
|
||||
static Stack<Matrix4x4> mHandlesMatrixstack = new Stack<Matrix4x4>();
|
||||
|
||||
public static void PushMatrix(Matrix4x4 matrix)
|
||||
{
|
||||
mHandlesMatrixstack.Push(matrix);
|
||||
Handles.matrix = matrix;
|
||||
}
|
||||
|
||||
public static void PopMatrix()
|
||||
{
|
||||
Handles.matrix = mHandlesMatrixstack.Pop();
|
||||
}
|
||||
|
||||
|
||||
public static void LabelIcon(Vector3 position, string text, Color labelColor)
|
||||
{
|
||||
GUIStyle iconStyle = GUI.skin.button;
|
||||
iconStyle.normal.textColor = labelColor;
|
||||
Handles.Label(position, text, iconStyle);
|
||||
}
|
||||
|
||||
public static bool Button(int id, Vector3 position, Quaternion direction, float size, float pickSize, bool useHandleSize, Handles.CapFunction capFunc, Color hoverCol, out bool isHovering)
|
||||
{
|
||||
Event current = Event.current;
|
||||
isHovering = false;
|
||||
if (useHandleSize)
|
||||
{
|
||||
float s = HandleUtility.GetHandleSize(position);
|
||||
size *= s;
|
||||
pickSize *= s;
|
||||
}
|
||||
switch (current.GetTypeForControl(id))
|
||||
{
|
||||
case EventType.MouseDown:
|
||||
if (HandleUtility.nearestControl == id)
|
||||
{
|
||||
GUIUtility.hotControl = id;
|
||||
current.Use();
|
||||
}
|
||||
break;
|
||||
case EventType.MouseUp:
|
||||
if ((current.button == 0 || current.button == 2) && GUIUtility.hotControl == id)
|
||||
{
|
||||
GUIUtility.hotControl = 0;
|
||||
current.Use();
|
||||
if (HandleUtility.nearestControl == id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EventType.MouseMove:
|
||||
if ((HandleUtility.nearestControl == id && current.button == 0) || (GUIUtility.keyboardControl == id && current.button == 2))
|
||||
{
|
||||
HandleUtility.Repaint();
|
||||
}
|
||||
break;
|
||||
case EventType.Repaint:
|
||||
{
|
||||
Color color = Handles.color;
|
||||
if (HandleUtility.nearestControl == id && GUI.enabled)
|
||||
{
|
||||
isHovering = true;
|
||||
Handles.color = hoverCol;
|
||||
}
|
||||
|
||||
capFunc(id, position, Quaternion.identity, size, EventType.Repaint);
|
||||
Handles.color = color;
|
||||
break;
|
||||
}
|
||||
case EventType.Layout:
|
||||
if (GUI.enabled)
|
||||
{
|
||||
HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(position, pickSize));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool PositionHandle(Vector3 position, Quaternion rotation, out Vector3 delta)
|
||||
{
|
||||
Vector3 p = Handles.PositionHandle(position, rotation);
|
||||
delta = p - position;
|
||||
return delta != Vector3.zero;
|
||||
}
|
||||
|
||||
public static bool RotationHandle(Vector3 position, Quaternion rotation, out Quaternion newRotation)
|
||||
{
|
||||
newRotation = Handles.RotationHandle(rotation, position);
|
||||
return (newRotation != rotation);
|
||||
}
|
||||
|
||||
static Vector2 s_StartMousePosition;
|
||||
static Vector2 s_CurrentMousePosition;
|
||||
static float s_StartScale;
|
||||
|
||||
public static bool ScaleSlider(float scale, Vector3 position, Vector3 direction, Quaternion rotation, float length, float size, float snap, out float delta)
|
||||
{
|
||||
int id = GUIUtility.GetControlID("ScaleSliderHash".GetHashCode(), FocusType.Keyboard);
|
||||
float newScale = scale;
|
||||
Event current = Event.current;
|
||||
switch (current.GetTypeForControl(id))
|
||||
{
|
||||
case EventType.MouseDown:
|
||||
if ((HandleUtility.nearestControl == id && current.button == 0) || (GUIUtility.keyboardControl == id && current.button == 2))
|
||||
{
|
||||
GUIUtility.keyboardControl = id;
|
||||
GUIUtility.hotControl = id;
|
||||
s_CurrentMousePosition = (s_StartMousePosition = current.mousePosition);
|
||||
s_StartScale = scale;
|
||||
current.Use();
|
||||
EditorGUIUtility.SetWantsMouseJumping(1);
|
||||
}
|
||||
break;
|
||||
case EventType.MouseUp:
|
||||
if (GUIUtility.hotControl == id && (current.button == 0 || current.button == 2))
|
||||
{
|
||||
GUIUtility.hotControl = 0;
|
||||
current.Use();
|
||||
EditorGUIUtility.SetWantsMouseJumping(0);
|
||||
}
|
||||
break;
|
||||
case EventType.MouseDrag:
|
||||
if (GUIUtility.hotControl == id)
|
||||
{
|
||||
s_CurrentMousePosition += current.delta;
|
||||
float num = 1f + HandleUtility.CalcLineTranslation(s_StartMousePosition, s_CurrentMousePosition, position, direction) * 0.1f;
|
||||
num = Handles.SnapValue(num, snap);
|
||||
newScale = s_StartScale * num;
|
||||
GUI.changed = true;
|
||||
current.Use();
|
||||
}
|
||||
break;
|
||||
case EventType.Repaint:
|
||||
{
|
||||
Color color = Color.white;
|
||||
if (id == GUIUtility.keyboardControl)
|
||||
{
|
||||
color = Handles.color;
|
||||
Handles.color = Handles.selectedColor;
|
||||
}
|
||||
//float num2 = size;
|
||||
//if (GUIUtility.hotControl == id)
|
||||
//{
|
||||
// num2 = size * scale / s_StartScale;
|
||||
//}
|
||||
Handles.CubeHandleCap(id, position + direction * length, rotation, HandleUtility.GetHandleSize(position) * size, EventType.Repaint);
|
||||
|
||||
Handles.DrawLine(position, position + direction * length);
|
||||
if (id == GUIUtility.keyboardControl)
|
||||
{
|
||||
Handles.color = color;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventType.Layout:
|
||||
HandleUtility.AddControl(id, HandleUtility.DistanceToLine(position, position + direction * length));
|
||||
HandleUtility.AddControl(id, HandleUtility.DistanceToCircle(position + direction * length, size));
|
||||
break;
|
||||
}
|
||||
delta = newScale - scale;
|
||||
|
||||
return (scale != newScale);
|
||||
}
|
||||
|
||||
public static Quaternion RotationHandle(Quaternion rotation, Vector3 position, float size)
|
||||
{
|
||||
Color staticColor = new Color(0.5f, 0.5f, 0.5f, 0f);
|
||||
float staticBlend = 0.6f;
|
||||
float handleSize = HandleUtility.GetHandleSize(position) * size;
|
||||
Color color = Handles.color;
|
||||
bool flag = !Tools.hidden && EditorApplication.isPlaying && ContainsStatic(Selection.gameObjects);
|
||||
Handles.color = ((!flag) ? Handles.xAxisColor : Color.Lerp(Handles.xAxisColor, staticColor, staticBlend));
|
||||
rotation = Handles.Disc(rotation, position, rotation * Vector3.right, handleSize, true, SnapSettings.Rotation);
|
||||
Handles.color = ((!flag) ? Handles.yAxisColor : Color.Lerp(Handles.yAxisColor, staticColor, staticBlend));
|
||||
rotation = Handles.Disc(rotation, position, rotation * Vector3.up, handleSize, true, SnapSettings.Rotation);
|
||||
Handles.color = ((!flag) ? Handles.zAxisColor : Color.Lerp(Handles.zAxisColor, staticColor, staticBlend));
|
||||
rotation = Handles.Disc(rotation, position, rotation * Vector3.forward, handleSize, true, SnapSettings.Rotation);
|
||||
if (!flag)
|
||||
{
|
||||
Handles.color = Handles.centerColor;
|
||||
rotation = Handles.Disc(rotation, position, Camera.current.transform.forward, handleSize * 1.1f, false, 0f);
|
||||
rotation = Handles.FreeRotateHandle(rotation, position, handleSize);
|
||||
}
|
||||
Handles.color = color;
|
||||
return rotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a 3D position handle
|
||||
/// </summary>
|
||||
/// <returns>The updated position</returns>
|
||||
/// <seealso cref="GUIUtility.GetControlID(int,FocusType)"/>
|
||||
public static Vector3 PositionHandle(int controlId1, int controlId2, int controlId3, Vector3 position, Quaternion rotation, float handleSize, float rectangleToSliderRatio = 0.15f, Color additionalColor = new Color())
|
||||
{
|
||||
float sliderSize = HandleUtility.GetHandleSize(position) * handleSize;
|
||||
float rectangleSize = sliderSize * rectangleToSliderRatio;
|
||||
|
||||
Vector3 snap = SnapSettings.Move;
|
||||
|
||||
Vector3 axis1 = rotation * Vector3.right;
|
||||
Vector3 axis2 = rotation * Vector3.up;
|
||||
Vector3 axis3 = rotation * Vector3.forward;
|
||||
Color axis1Color = new Color(0.9f, 0.3f, 0.1f) + additionalColor;
|
||||
Color axis2Color = new Color(0.6f, 0.9f, 0.3f) + additionalColor;
|
||||
Color axis3Color = new Color(0.2f, 0.4f, 0.9f) + additionalColor;
|
||||
|
||||
Vector3 updatedPosition = position;
|
||||
|
||||
Handles.color = axis1Color;
|
||||
updatedPosition += Handles.Slider(position, axis1, sliderSize, Handles.ArrowHandleCap, snap.x) - position;
|
||||
updatedPosition += Handles.Slider2D(controlId1, position, rectangleSize * (axis3 + axis2), Vector3.Cross(axis3, axis2), axis2, axis3, rectangleSize, Handles.RectangleHandleCap, new Vector2(snap.y, snap.z)) - position;
|
||||
|
||||
Handles.color = axis2Color;
|
||||
updatedPosition += Handles.Slider(position, axis2, sliderSize, Handles.ArrowHandleCap, snap.y) - position;
|
||||
updatedPosition += Handles.Slider2D(controlId2, position, rectangleSize * (axis1 + axis3), Vector3.Cross(axis1, axis3), axis3, axis1, rectangleSize, Handles.RectangleHandleCap, new Vector2(snap.z, snap.x)) - position;
|
||||
|
||||
Handles.color = axis3Color;
|
||||
updatedPosition += Handles.Slider(position, axis3, sliderSize, Handles.ArrowHandleCap, snap.z) - position;
|
||||
updatedPosition += Handles.Slider2D(controlId3, position, rectangleSize * (axis1 + axis2), Vector3.Cross(axis1, axis2), axis2, axis1, rectangleSize, Handles.RectangleHandleCap, new Vector2(snap.y, snap.x)) - position;
|
||||
|
||||
return updatedPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a 2D position handle
|
||||
/// </summary>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="plane">0 for XY, 1 for XZ and 2 for YZ</param>
|
||||
/// <param name="controlId"><see cref="GUIUtility.GetControlID(int,FocusType)"/></param>
|
||||
/// <param name="position"></param>
|
||||
/// <param name="rotation"></param>
|
||||
/// <returns>The updated position</returns>
|
||||
public static Vector3 PositionHandle2D(int controlId, Vector3 position, Quaternion rotation, float size, int plane = 0)
|
||||
{
|
||||
float sliderSize = HandleUtility.GetHandleSize(position) * size;
|
||||
float rectSize = sliderSize * 0.15f;
|
||||
|
||||
Vector3 snap = SnapSettings.Move;
|
||||
|
||||
Vector3 axis1;
|
||||
Vector3 axis2;
|
||||
Color axis1Color;
|
||||
Color axis2Color;
|
||||
Color planeColor;
|
||||
{
|
||||
Color xColor = new Color(0.9f, 0.3f, 0.1f);
|
||||
Color yColor = new Color(0.6f, 0.9f, 0.3f);
|
||||
Color zColor = new Color(0.2f, 0.4f, 0.9f);
|
||||
|
||||
switch (plane)
|
||||
{
|
||||
//XY
|
||||
case 0:
|
||||
axis1 = rotation * Vector3.right;
|
||||
axis2 = rotation * Vector3.up;
|
||||
axis1Color = xColor;
|
||||
axis2Color = yColor;
|
||||
planeColor = zColor;
|
||||
break;
|
||||
//XZ
|
||||
case 1:
|
||||
axis1 = rotation * Vector3.right;
|
||||
axis2 = rotation * Vector3.forward;
|
||||
axis1Color = xColor;
|
||||
axis2Color = zColor;
|
||||
planeColor = yColor;
|
||||
break;
|
||||
//YZ
|
||||
case 2:
|
||||
axis1 = rotation * Vector3.up;
|
||||
axis2 = rotation * Vector3.forward;
|
||||
axis1Color = yColor;
|
||||
axis2Color = zColor;
|
||||
planeColor = xColor;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(plane));
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 updatedPosition = position;
|
||||
|
||||
Handles.color = axis1Color;
|
||||
updatedPosition += Handles.Slider(position, axis1, sliderSize, Handles.ArrowHandleCap, snap.x) - position;
|
||||
|
||||
Handles.color = axis2Color;
|
||||
updatedPosition += Handles.Slider(position, axis2, sliderSize, Handles.ArrowHandleCap, snap.y) - position;
|
||||
|
||||
Handles.color = planeColor;
|
||||
updatedPosition += Handles.Slider2D(controlId, position, rectSize * (axis1 + axis2), Vector3.Cross(axis1, axis2), axis2, axis1, rectSize, Handles.RectangleHandleCap, new Vector2(snap.x, snap.y)) - position;
|
||||
|
||||
return updatedPosition;
|
||||
}
|
||||
|
||||
public static Vector3 TinyHandle2D(int id, Vector3 position, Quaternion rotation, float size, Handles.CapFunction func = null)
|
||||
{
|
||||
return TinyHandle2D(id, position, rotation * Vector3.forward, rotation * Vector3.up, rotation * Vector3.right, size, func);
|
||||
}
|
||||
|
||||
public static Vector3 TinyHandle2D(int id, Transform transform, float size, Handles.CapFunction func = null)
|
||||
{
|
||||
return TinyHandle2D(id, transform.position, transform.forward, transform.up, transform.right, size, func);
|
||||
}
|
||||
|
||||
public static Vector3 TinyHandle2D(int id, Vector3 pos, Vector3 forward, Vector3 up, Vector3 right, float size, Handles.CapFunction func = null)
|
||||
{
|
||||
return Handles.Slider2D(id, pos, forward, up, right, HandleUtility.GetHandleSize(pos) * size, func, SnapSettings.Move);
|
||||
}
|
||||
|
||||
public static void DrawSolidRectangleWithOutline(Vector2 center, Vector2 extends, Color backgroundColor, Color outlineColor)
|
||||
{
|
||||
DrawSolidRectangleWithOutline(new Rect(center.x - extends.x / 2, center.y - extends.y / 2, extends.x, extends.y), backgroundColor, outlineColor);
|
||||
}
|
||||
|
||||
public static void DrawSolidRectangleWithOutline(Rect r, Color backgroundColor, Color outlineColor)
|
||||
{
|
||||
Vector3[] verts = new Vector3[4]
|
||||
{
|
||||
new Vector3(r.xMin,r.yMin,0),
|
||||
new Vector3(r.xMax,r.yMin,0),
|
||||
new Vector3(r.xMax,r.yMax,0),
|
||||
new Vector3(r.xMin,r.yMax,0)
|
||||
};
|
||||
Handles.DrawSolidRectangleWithOutline(verts, backgroundColor, outlineColor);
|
||||
}
|
||||
|
||||
public static void DrawOutline(Rect r, Color outlineColor)
|
||||
{
|
||||
DrawSolidRectangleWithOutline(r, new Color(0, 0, 0, 0), outlineColor);
|
||||
}
|
||||
|
||||
public static void WireCubeCap(Vector3 position, Vector3 size)
|
||||
{
|
||||
Vector3 half = size / 2;
|
||||
// draw front
|
||||
Handles.DrawLine(position + new Vector3(-half.x, -half.y, half.z), position + new Vector3(half.x, -half.y, half.z));
|
||||
Handles.DrawLine(position + new Vector3(-half.x, -half.y, half.z), position + new Vector3(-half.x, half.y, half.z));
|
||||
Handles.DrawLine(position + new Vector3(half.x, half.y, half.z), position + new Vector3(half.x, -half.y, half.z));
|
||||
Handles.DrawLine(position + new Vector3(half.x, half.y, half.z), position + new Vector3(-half.x, half.y, half.z));
|
||||
// draw back
|
||||
Handles.DrawLine(position + new Vector3(-half.x, -half.y, -half.z), position + new Vector3(half.x, -half.y, -half.z));
|
||||
Handles.DrawLine(position + new Vector3(-half.x, -half.y, -half.z), position + new Vector3(-half.x, half.y, -half.z));
|
||||
Handles.DrawLine(position + new Vector3(half.x, half.y, -half.z), position + new Vector3(half.x, -half.y, -half.z));
|
||||
Handles.DrawLine(position + new Vector3(half.x, half.y, -half.z), position + new Vector3(-half.x, half.y, -half.z));
|
||||
// draw corners
|
||||
Handles.DrawLine(position + new Vector3(-half.x, -half.y, -half.z), position + new Vector3(-half.x, -half.y, half.z));
|
||||
Handles.DrawLine(position + new Vector3(half.x, -half.y, -half.z), position + new Vector3(half.x, -half.y, half.z));
|
||||
Handles.DrawLine(position + new Vector3(-half.x, half.y, -half.z), position + new Vector3(-half.x, half.y, half.z));
|
||||
Handles.DrawLine(position + new Vector3(half.x, half.y, -half.z), position + new Vector3(half.x, half.y, half.z));
|
||||
}
|
||||
|
||||
public static void ArrowCap(Vector3 position, Vector3 direction, Color outlineColor, float length, float lineWidth = 0.4f, float headWidth = 1f, float headRatio = 0.3f, bool useHandleSize = true)
|
||||
{
|
||||
float size = (useHandleSize) ? HandleUtility.GetHandleSize(position) : 1;
|
||||
|
||||
ArrowCap(position, direction, Vector3.up, outlineColor, length, lineWidth, headWidth, headRatio, size);
|
||||
}
|
||||
|
||||
public static void ArrowCap(Vector3 position, Vector3 direction, Vector3 upDirection, Color outlineColor, float length, float lineWidth, float headWidth, float headRatio, float sizeMultiplier)
|
||||
{
|
||||
Vector3[] arrow = new Vector3[8];
|
||||
Vector3 start = position;
|
||||
length *= sizeMultiplier;
|
||||
Vector3 end = position + direction * length;
|
||||
|
||||
Vector3 right = Vector3.Cross(upDirection, direction).normalized;
|
||||
|
||||
float hh = length * headRatio;
|
||||
Vector3 rlw2 = right * lineWidth / 2 * sizeMultiplier;
|
||||
Vector3 rhw2 = right * headWidth / 2 * sizeMultiplier;
|
||||
arrow[0] = start - rlw2;
|
||||
arrow[1] = end - direction * hh - rlw2;
|
||||
arrow[2] = end - direction * hh - rhw2;
|
||||
arrow[3] = end;
|
||||
arrow[4] = end - direction * hh + rhw2;
|
||||
arrow[5] = end - direction * hh + rlw2;
|
||||
arrow[6] = start + rlw2;
|
||||
arrow[7] = arrow[0];
|
||||
|
||||
Handles.DrawAAConvexPolygon(arrow[2], arrow[3], arrow[4]);
|
||||
Handles.DrawAAConvexPolygon(arrow[0], arrow[1], arrow[5], arrow[6]);
|
||||
if (Handles.color != outlineColor)
|
||||
{
|
||||
Color c = Handles.color;
|
||||
Handles.color = outlineColor;
|
||||
Handles.DrawAAPolyLine(arrow);
|
||||
Handles.color = c;
|
||||
}
|
||||
}
|
||||
|
||||
public static void BoundsCap(Bounds b)
|
||||
{
|
||||
WireCubeCap(b.center, b.size);
|
||||
}
|
||||
|
||||
public static Vector3 TranslateByPixel(Vector3 position, float x, float y)
|
||||
{
|
||||
return TranslateByPixel(position, new Vector3(x, y));
|
||||
}
|
||||
public static Vector3 TranslateByPixel(Vector3 position, Vector3 translateBy)
|
||||
{
|
||||
Camera cam = SceneView.currentDrawingSceneView.camera;
|
||||
if (cam)
|
||||
return cam.ScreenToWorldPoint(cam.WorldToScreenPoint(position) + translateBy);
|
||||
else
|
||||
return position;
|
||||
}
|
||||
|
||||
public static Vector3 TranslateAligned(Vector3 position, GUIContent content, TextAlignment alignment = TextAlignment.Center, GUIStyle style = null)
|
||||
{
|
||||
if (style == null)
|
||||
style = EditorStyles.label;
|
||||
float w = style.CalcSize(content).x;
|
||||
switch (alignment)
|
||||
{
|
||||
case TextAlignment.Center:
|
||||
return TranslateByPixel(position, new Vector3(-w / 2, 0, 0));
|
||||
case TextAlignment.Right:
|
||||
return TranslateByPixel(position, new Vector3(w / 2, 0, 0));
|
||||
default:
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool ContainsStatic(GameObject[] objects)
|
||||
{
|
||||
if (objects == null || objects.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < objects.Length; i++)
|
||||
{
|
||||
if (objects[i] != null && objects[i].isStatic)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6a1d31433dbd4e43934fdeedb24a25b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,242 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using FluffyUnderware.DevTools;
|
||||
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public abstract class DTProject : IComparable
|
||||
{
|
||||
public string Identifier { get; private set; }
|
||||
public string Version { get; private set; }
|
||||
public DTResource Resource { get; protected set; }
|
||||
[Obsolete("Assumed to be always true")]
|
||||
public bool ShowToolbarInAllSceneViews = false;
|
||||
|
||||
public DTToolbarOrientation ToolbarOrientation
|
||||
{
|
||||
get { return mTBOrientation; }
|
||||
set
|
||||
{
|
||||
if (mTBOrientation != value)
|
||||
{
|
||||
mTBOrientation = value;
|
||||
if (!string.IsNullOrEmpty(Identifier))
|
||||
{
|
||||
SetEditorPrefs("ToolbarOrientation", ToolbarOrientation);
|
||||
}
|
||||
else
|
||||
DTLog.LogError("[DevTools] Project " + this.GetType().Name + "missing identifier!");
|
||||
DTToolbar.RecalcItemSize = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
public DTToolbarMode ToolbarMode
|
||||
{
|
||||
get { return mTBMode; }
|
||||
set
|
||||
{
|
||||
if (mTBMode != value)
|
||||
{
|
||||
mTBMode = value;
|
||||
if (!string.IsNullOrEmpty(Identifier))
|
||||
{
|
||||
SetEditorPrefs("ToolbarMode", ToolbarMode);
|
||||
}
|
||||
else
|
||||
DTLog.LogError("[DevTools] Project " + this.GetType().Name + "missing identifier!");
|
||||
DTToolbar.RecalcItemSize = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, EditorKeyBinding> AdditionalKeyBindings = new Dictionary<string, EditorKeyBinding>();
|
||||
internal List<DTToolbarItem> ToolbarItems = new List<DTToolbarItem>();
|
||||
|
||||
static DTToolbarOrientation mTBOrientation = DTToolbarOrientation.Left;
|
||||
static DTToolbarMode mTBMode = DTToolbarMode.Full;
|
||||
|
||||
protected DTProject(string identifier, string version)
|
||||
{
|
||||
Identifier = identifier;
|
||||
Version = version;
|
||||
LoadPreferences();
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
ToolbarItems.Clear();
|
||||
AdditionalKeyBindings.Clear();
|
||||
}
|
||||
|
||||
public virtual void ResetPreferences()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void LoadPreferences()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Identifier))
|
||||
{
|
||||
// Upgrade?
|
||||
string ver=GetEditorPrefs("Version", Version);
|
||||
if (string.Compare(ver, Version)==-1)// (ver != Version)
|
||||
{
|
||||
UpgradePreferences(ver);
|
||||
SetEditorPrefs("Version", Version);
|
||||
}
|
||||
|
||||
mTBMode=GetEditorPrefs("ToolbarMode", ToolbarMode);
|
||||
mTBOrientation=GetEditorPrefs("ToolbarOrientation", ToolbarOrientation);
|
||||
|
||||
} else
|
||||
DTLog.LogError("[DevTools] Project "+this.GetType().Name+"missing identifier!");
|
||||
}
|
||||
|
||||
public virtual void SavePreferences()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Identifier))
|
||||
{
|
||||
SetEditorPrefs("Version",Version);
|
||||
SetEditorPrefs("ToolbarMode", ToolbarMode);
|
||||
SetEditorPrefs("ToolbarOrientation", ToolbarOrientation);
|
||||
} else
|
||||
DTLog.LogError("[DevTools] Project " + this.GetType().Name + "missing identifier!");
|
||||
}
|
||||
|
||||
public List<EditorKeyBinding> GetProjectBindings()
|
||||
{
|
||||
List<EditorKeyBinding> res = new List<EditorKeyBinding>();
|
||||
foreach (DTToolbarItem item in ToolbarItems)
|
||||
foreach (EditorKeyBinding binding in item.KeyBindings)
|
||||
if (binding.ShowInPrefs)
|
||||
res.Add(binding);
|
||||
res.AddRange(AdditionalKeyBindings.Values);
|
||||
res.Sort();
|
||||
return res;
|
||||
}
|
||||
|
||||
public EditorKeyBinding RegisterKeyBinding(EditorKeyBinding binding)
|
||||
{
|
||||
EditorKeyBinding b;
|
||||
if (AdditionalKeyBindings.TryGetValue(binding.Name,out b))
|
||||
return b;
|
||||
else {
|
||||
setKeyBindingFromPrefs(binding,false);
|
||||
AdditionalKeyBindings.Add(binding.Name, binding);
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For all EditorKeyBindings registered to ToolbarItems of this project, check if Name is unique
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal bool CheckKeyBindingNamesAreUnique()
|
||||
{
|
||||
|
||||
Dictionary<string, object> dict = new Dictionary<string, object>();
|
||||
object exist;
|
||||
foreach (DTToolbarItem item in ToolbarItems)
|
||||
foreach (EditorKeyBinding binding in item.KeyBindings)
|
||||
{
|
||||
if (dict.TryGetValue(binding.Name, out exist)){
|
||||
DTLog.LogError(string.Format("[DevTools] KeyBindings need unique names! ({0} and {1}",item.GetType().Name,exist.GetType().Name));
|
||||
return false;
|
||||
} else
|
||||
dict.Add(binding.Name,item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setKeyBindingFromPrefs(EditorKeyBinding binding, bool removePrefsIfEqual=true)
|
||||
{
|
||||
string newBindString = GetEditorPrefs(binding.Name, "");
|
||||
if (!string.IsNullOrEmpty(newBindString) ){
|
||||
// Same binding? Then remove prefs setting
|
||||
if (removePrefsIfEqual && newBindString == binding.ToPrefsString())
|
||||
DeleteEditorPrefs(binding.Name);
|
||||
else // load and set new binding
|
||||
binding.Set(newBindString);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For all EditorKeyBindings registered to ToolbarItems of this project, manage remappings stored in EditorPrefs
|
||||
/// </summary>
|
||||
internal void LoadKeyBindingRemappings()
|
||||
{
|
||||
// Toolbars
|
||||
foreach (DTToolbarItem item in ToolbarItems)
|
||||
for (int i=0;i<item.KeyBindings.Count;i++)
|
||||
setKeyBindingFromPrefs(item.KeyBindings[i]);
|
||||
}
|
||||
|
||||
protected virtual void UpgradePreferences(string oldVersion)
|
||||
{
|
||||
DTLog.Log(string.Format("[{0}] Upgrading project settings from {1} to {2}", Identifier, oldVersion, Version));
|
||||
}
|
||||
|
||||
public void SetEditorPrefs<T>(string key, T value)
|
||||
{
|
||||
DT.SetEditorPrefs(Identifier + "." + key, value);
|
||||
}
|
||||
|
||||
public T GetEditorPrefs<T>(string key, T defaultValue)
|
||||
{
|
||||
return DT.GetEditorPrefs(Identifier + "." + key, defaultValue);
|
||||
}
|
||||
|
||||
public string[] GetEditorPrefs(string key)
|
||||
{
|
||||
return DT.GetEditorPrefs(Identifier + "." + key);
|
||||
}
|
||||
|
||||
public bool HasEditorPrefs(string key)
|
||||
{
|
||||
return EditorPrefs.HasKey(Identifier + "." + key);
|
||||
}
|
||||
|
||||
public void DeleteEditorPrefs(string key)
|
||||
{
|
||||
EditorPrefs.DeleteKey(Identifier + "." + key);
|
||||
}
|
||||
|
||||
public T FindItem<T>() where T:DTToolbarItem
|
||||
{
|
||||
Type t = typeof(T);
|
||||
for (int i = 0; i < ToolbarItems.Count; i++)
|
||||
if (ToolbarItems[i].GetType() == t)
|
||||
return (T)ToolbarItems[i];
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void SetRadioGroupState(DTToolbarRadioButton active)
|
||||
{
|
||||
for (int i = 0; i < ToolbarItems.Count; i++)
|
||||
{
|
||||
DTToolbarRadioButton rad = ToolbarItems[i] as DTToolbarRadioButton;
|
||||
if (rad && rad.RadioGroup.Equals(active.RadioGroup, StringComparison.CurrentCultureIgnoreCase))
|
||||
rad.mOn = (rad == active);
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
DTProject other = (DTProject)obj;
|
||||
return Identifier.CompareTo(other.Identifier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f699006303cd07e4fb52f3fd516ad100
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,160 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using System.Reflection;
|
||||
using FluffyUnderware.DevTools;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for loading image resources
|
||||
/// </summary>
|
||||
public abstract class DTResource
|
||||
{
|
||||
public Assembly ResourceDLL;
|
||||
public string ResourceNamespace = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Load an image defined by a packed string either from the Resource DLL or the Editor/Resources folder
|
||||
/// </summary>
|
||||
/// <param name="packedstring">string formed name (including namespace),width,height. E.g. "Assets/Editor/myIcon,16,16"</param>
|
||||
/// <returns>a Texture</returns>
|
||||
public virtual Texture2D LoadPacked(string packedstring,Assembly assembly=null, string resourcePath="")
|
||||
{
|
||||
if (!string.IsNullOrEmpty(packedstring))
|
||||
{
|
||||
string[] s = packedstring.Split(',');
|
||||
if (s.Length == 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
int w = int.Parse(s[1], System.Globalization.CultureInfo.InvariantCulture);
|
||||
int h = int.Parse(s[2], System.Globalization.CultureInfo.InvariantCulture);
|
||||
return Load(s[0], w, h, assembly, resourcePath);
|
||||
}
|
||||
catch (Exception e) { Debug.LogException(e);}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load an image either from a Resource DLL or the Editor/Resources folder
|
||||
/// </summary>
|
||||
/// <param name="assembly">the resource DLL assembly</param>
|
||||
/// <param name="resourcePath">the resource path(namespace)</param>
|
||||
/// <param name="resourceName">name of the resource file (without extension)</param>
|
||||
/// <param name="width">width of the image (can be omitted when loading from texture file)</param>
|
||||
/// <param name="height">height of the image (can be omitted when loading from texture file)</param>
|
||||
/// <returns>a Texture</returns>
|
||||
public virtual Texture2D Load(string resourceName, int width=0, int height=0,Assembly assembly=null, string resourcePath="")
|
||||
{
|
||||
if (assembly == null)
|
||||
assembly = ResourceDLL;
|
||||
if (string.IsNullOrEmpty(resourcePath))
|
||||
resourcePath = ResourceNamespace;
|
||||
|
||||
Texture2D texture = null;
|
||||
if (string.IsNullOrEmpty(System.IO.Path.GetExtension(resourceName)))
|
||||
resourceName += ".png";
|
||||
|
||||
//if (!resourcePath.EndsWith("."))
|
||||
// resourcePath += ".";
|
||||
|
||||
if (assembly != null)
|
||||
{
|
||||
using (System.IO.Stream myStream = assembly.GetManifestResourceStream(resourcePath + resourceName))
|
||||
{
|
||||
if (myStream != null)
|
||||
{
|
||||
texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
|
||||
texture.LoadImage(ReadToEnd(myStream));
|
||||
if (texture != null)
|
||||
{
|
||||
//texture.hideFlags = HideFlags.DontSave;
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try from file sys:
|
||||
texture = (Texture2D)Resources.Load($"Editor/{System.IO.Path.GetFileNameWithoutExtension(resourceName)}");
|
||||
|
||||
if (texture == null)
|
||||
{
|
||||
DTLog.LogWarning("Missing resource: " + resourcePath + resourceName);
|
||||
}
|
||||
//else
|
||||
// texture.hideFlags = HideFlags.DontSave;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return texture;
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected static byte[] ReadToEnd(System.IO.Stream stream)
|
||||
{
|
||||
long originalPosition = stream.Position;
|
||||
stream.Position = 0;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] readBuffer = new byte[4096];
|
||||
|
||||
int totalBytesRead = 0;
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
|
||||
{
|
||||
totalBytesRead += bytesRead;
|
||||
|
||||
if (totalBytesRead == readBuffer.Length)
|
||||
{
|
||||
int nextByte = stream.ReadByte();
|
||||
if (nextByte != -1)
|
||||
{
|
||||
byte[] temp = new byte[readBuffer.Length * 2];
|
||||
System.Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
|
||||
System.Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
|
||||
readBuffer = temp;
|
||||
totalBytesRead++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] buffer = readBuffer;
|
||||
if (readBuffer.Length != totalBytesRead)
|
||||
{
|
||||
buffer = new byte[totalBytesRead];
|
||||
System.Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream.Position = originalPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public static Assembly FindResourceDLL(string name)
|
||||
{
|
||||
//BUG will return the wrong dll if there is another dll that starts with the same name
|
||||
return TypeExt.GetLoadedAssemblies().FirstOrDefault(asm => asm.FullName.StartsWith(name));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e7542226fdb3e8458d6dd939f67c79e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,136 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
using System;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
[Obsolete("Now that SceneView has a OnSceneGUI method, there is seemingly no need to use DTSceneView which implements its own OnSceneGUI. It might even conflict with SceneView.OnSceneGUI")]
|
||||
#endif
|
||||
public class DTSceneView : SceneView
|
||||
{
|
||||
|
||||
#region ### Serialized fields ###
|
||||
#endregion
|
||||
|
||||
#region ### Public Properties ###
|
||||
|
||||
public bool In2DMode
|
||||
{
|
||||
get { return in2DMode; }
|
||||
set
|
||||
{
|
||||
in2DMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SceneViewState State
|
||||
{
|
||||
get
|
||||
{
|
||||
return mStateField.GetValue(this) as SceneViewState;
|
||||
}
|
||||
set
|
||||
{
|
||||
mStateField.SetValue(this, value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ### Privates Fields ###
|
||||
|
||||
FieldInfo mStateField;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ### Unity Callbacks ###
|
||||
/*! \cond UNITY */
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
getInternals();
|
||||
SceneView.
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
duringSceneGui
|
||||
#else
|
||||
onSceneGUIDelegate
|
||||
#endif
|
||||
+= onScene;
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
SceneView.
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
duringSceneGui
|
||||
#else
|
||||
onSceneGUIDelegate
|
||||
#endif
|
||||
-= onScene;
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
/*! \endcond */
|
||||
#endregion
|
||||
|
||||
#region ### Public Static Methods ###
|
||||
#endregion
|
||||
|
||||
#region ### Public Methods ###
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
protected new virtual void OnSceneGUI()
|
||||
#else
|
||||
protected virtual void OnSceneGUI()
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ### Privates & Internals ###
|
||||
/*! \cond PRIVATE */
|
||||
|
||||
void onScene(SceneView view)
|
||||
{
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
SceneView.
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
duringSceneGui
|
||||
#else
|
||||
onSceneGUIDelegate
|
||||
#endif
|
||||
-= onScene;
|
||||
Close();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
if (view == this)
|
||||
OnSceneGUI();
|
||||
}
|
||||
|
||||
void getInternals()
|
||||
{
|
||||
mStateField = GetType().FieldByName("m_SceneViewState", true, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*! \endcond */
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97953e54a2c2482449099d6d8dfb2de4
|
||||
timeCreated: 1468747688
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,207 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public static class DTSelection
|
||||
{
|
||||
static GameObject mCurrentGameObject;
|
||||
static int mCurrentGameObjectsCount;
|
||||
|
||||
public static event DT.Callback OnSelectionChange;
|
||||
|
||||
internal static bool MuteEvents { get; set; }
|
||||
|
||||
public static int Count
|
||||
{
|
||||
get { return mCurrentGameObjectsCount; }
|
||||
}
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
EditorApplication.update -= checkSelection;
|
||||
//TODO listen on Selection.selectionChanged instead?
|
||||
EditorApplication.update += checkSelection;
|
||||
|
||||
}
|
||||
|
||||
public static bool HasComponent<T>(bool allowMultiSelection = false) where T : Component
|
||||
{
|
||||
if (allowMultiSelection)
|
||||
return mCurrentGameObjectsCount >= 1 && getSelection<T>().Count > 0;
|
||||
else
|
||||
return mCurrentGameObjectsCount == 1 && mCurrentGameObject != null && mCurrentGameObject.GetComponent(typeof(T)) != null;
|
||||
}
|
||||
|
||||
public static bool HasComponent<T, T1>(bool allowMultiSelection = false) where T : Component where T1 : Component
|
||||
{
|
||||
return HasComponent<T>(allowMultiSelection) ||
|
||||
HasComponent<T1>(allowMultiSelection);
|
||||
}
|
||||
|
||||
public static bool HasComponent<T, T1, T2>(bool allowMultiSelection = false)
|
||||
where T : Component
|
||||
where T1 : Component
|
||||
where T2 : Component
|
||||
{
|
||||
return HasComponent<T>(allowMultiSelection) ||
|
||||
HasComponent<T1>(allowMultiSelection) ||
|
||||
HasComponent<T2>(allowMultiSelection);
|
||||
}
|
||||
|
||||
public static bool HasComponent<T, T1, T2, T3>(bool allowMultiSelection = false)
|
||||
where T : Component
|
||||
where T1 : Component
|
||||
where T2 : Component
|
||||
where T3 : Component
|
||||
{
|
||||
return HasComponent<T>(allowMultiSelection) ||
|
||||
HasComponent<T1>(allowMultiSelection) ||
|
||||
HasComponent<T2>(allowMultiSelection) ||
|
||||
HasComponent<T3>(allowMultiSelection);
|
||||
}
|
||||
|
||||
public static bool HasComponent<T, T1, T2, T3, T4>(bool allowMultiSelection = false)
|
||||
where T : Component
|
||||
where T1 : Component
|
||||
where T2 : Component
|
||||
where T3 : Component
|
||||
where T4 : Component
|
||||
{
|
||||
return HasComponent<T>(allowMultiSelection) ||
|
||||
HasComponent<T1>(allowMultiSelection) ||
|
||||
HasComponent<T2>(allowMultiSelection) ||
|
||||
HasComponent<T3>(allowMultiSelection) ||
|
||||
HasComponent<T4>(allowMultiSelection);
|
||||
}
|
||||
|
||||
public static T GetAs<T>(bool allowMultiSelection = false) where T : Component
|
||||
{
|
||||
List<T> ar = getSelection<T>();
|
||||
if (ar.Count == 1 || (ar.Count > 0 && allowMultiSelection))
|
||||
return (T)ar[0];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<T> GetAllAs<T>() where T : Component
|
||||
{
|
||||
return getSelection<T>();
|
||||
}
|
||||
|
||||
public static GameObject GetGameObject(bool allowMultiSelection = false)
|
||||
{
|
||||
GameObject[] selectedGameObjects = Selection.gameObjects;
|
||||
if (selectedGameObjects.Length == 1 || (selectedGameObjects.Length > 1 && allowMultiSelection))
|
||||
return Selection.activeGameObject;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Vector3 GetPosition()
|
||||
{
|
||||
Vector3 p = Vector3.zero;
|
||||
List<Transform> tt = DTSelection.GetAllAs<Transform>();
|
||||
if (tt.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < tt.Count; i++)
|
||||
p += tt[i].position;
|
||||
|
||||
p /= tt.Count;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static List<T> getSelection<T>() where T : Component
|
||||
{
|
||||
Object[] S = Selection.GetFiltered(typeof(T), SelectionMode.TopLevel | SelectionMode.ExcludePrefab | SelectionMode.Editable);
|
||||
List<T> L = new List<T>();
|
||||
foreach (Object O in S)
|
||||
if (O != null)
|
||||
{
|
||||
if (Selection.activeTransform == ((Component)O).transform)
|
||||
L.Insert(0, (T)O);
|
||||
else
|
||||
L.Add((T)O);
|
||||
}
|
||||
return L;
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
Selection.objects = new Object[0];
|
||||
mCurrentGameObject = null;
|
||||
mCurrentGameObjectsCount = 0;
|
||||
raiseOnSelectionChange();
|
||||
}
|
||||
|
||||
public static void Set(params Object[] objects)
|
||||
{
|
||||
if (objects.Length > 0)
|
||||
{
|
||||
Selection.objects = objects;
|
||||
mCurrentGameObject = Selection.activeGameObject;
|
||||
mCurrentGameObjectsCount = Selection.gameObjects.Length;
|
||||
raiseOnSelectionChange();
|
||||
}
|
||||
else
|
||||
Clear();
|
||||
}
|
||||
|
||||
public static void AddGameObjects(params Component[] objects)
|
||||
{
|
||||
List<GameObject> gl = new List<GameObject>(objects.Length);
|
||||
foreach (Component c in objects)
|
||||
if (c != null && c.gameObject != null && !gl.Contains(c.gameObject) && !Selection.Contains(c))
|
||||
gl.Add(c.gameObject);
|
||||
if (gl.Count > 0)
|
||||
{
|
||||
GameObject[] cur = Selection.gameObjects;
|
||||
Selection.objects = cur.AddRange(gl.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetGameObjects(params Component[] objects)
|
||||
{
|
||||
if (objects.Length > 0)
|
||||
{
|
||||
List<GameObject> gl = new List<GameObject>(objects.Length);
|
||||
foreach (Component c in objects)
|
||||
if (c != null && c.gameObject != null && !gl.Contains(c.gameObject))
|
||||
gl.Add(c.gameObject);
|
||||
Selection.objects = gl.ToArray();
|
||||
mCurrentGameObject = Selection.activeGameObject;
|
||||
mCurrentGameObjectsCount = Selection.gameObjects.Length;
|
||||
raiseOnSelectionChange();
|
||||
}
|
||||
else
|
||||
Clear();
|
||||
}
|
||||
|
||||
static void checkSelection()
|
||||
{
|
||||
GameObject[] selectedGameObjects = Selection.gameObjects;
|
||||
if (!MuteEvents && Selection.activeGameObject != mCurrentGameObject || mCurrentGameObjectsCount != selectedGameObjects.Length)
|
||||
{
|
||||
mCurrentGameObject = Selection.activeGameObject;
|
||||
mCurrentGameObjectsCount = selectedGameObjects.Length;
|
||||
raiseOnSelectionChange();
|
||||
}
|
||||
}
|
||||
|
||||
static void raiseOnSelectionChange()
|
||||
{
|
||||
if (OnSelectionChange != null)
|
||||
OnSelectionChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb2b7daa166196847886162a590328f2
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,151 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
using FluffyUnderware.DevToolsEditor.Extensions;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public class DTStatusbar
|
||||
{
|
||||
string mSourceIdent;
|
||||
string mStatusBarMessage;
|
||||
MessageType mStatusBarMessageType;
|
||||
float mStatusBarMessageDelay;
|
||||
double mStatusBarMessageLastTime;
|
||||
|
||||
GUIStyle mMessageStyle;
|
||||
public GUIStyle MessageStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mMessageStyle == null)
|
||||
{
|
||||
mMessageStyle = GetStyle();
|
||||
}
|
||||
return mMessageStyle;
|
||||
}
|
||||
set
|
||||
{
|
||||
mMessageStyle = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Visible = true;
|
||||
|
||||
|
||||
protected virtual GUIStyle GetStyle()
|
||||
{
|
||||
GUIStyle st=new GUIStyle(GUI.skin.GetStyle("HelpBox"));
|
||||
st.richText = true;
|
||||
return st;
|
||||
}
|
||||
|
||||
protected virtual void GetColors()
|
||||
{
|
||||
switch (mStatusBarMessageType)
|
||||
{
|
||||
case MessageType.Error:
|
||||
GUI.contentColor = Color.white;
|
||||
GUI.backgroundColor = Color.red.SkinAwareColor();
|
||||
break;
|
||||
case MessageType.Warning:
|
||||
GUI.contentColor = Color.white;
|
||||
GUI.backgroundColor = Color.yellow.SkinAwareColor();
|
||||
break;
|
||||
case MessageType.Info:
|
||||
GUI.contentColor = Color.yellow;
|
||||
break;
|
||||
default:
|
||||
GUI.contentColor = Color.white;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Clear(string source="")
|
||||
{
|
||||
if (source == mSourceIdent || string.IsNullOrEmpty(mSourceIdent))
|
||||
{
|
||||
mStatusBarMessage = "";
|
||||
mStatusBarMessageType = MessageType.None;
|
||||
mStatusBarMessageDelay = 0;
|
||||
mStatusBarMessageLastTime = EditorApplication.timeSinceStartup;
|
||||
mSourceIdent = "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Set(string text, string source="",float delay = 0)
|
||||
{
|
||||
SetMessage(text, source,MessageType.None, delay);
|
||||
}
|
||||
|
||||
public void SetError(string text, string source = "", float delay = 0)
|
||||
{
|
||||
SetMessage(text,source, MessageType.Error, delay);
|
||||
}
|
||||
|
||||
public void SetInfo(string text, string source = "", float delay = 0)
|
||||
{
|
||||
SetMessage(text, source,MessageType.Info, delay);
|
||||
}
|
||||
|
||||
public void SetWarning(string text, string source = "", float delay = 0)
|
||||
{
|
||||
SetMessage(text, source,MessageType.Warning, delay);
|
||||
}
|
||||
|
||||
public void SetMessage(string msg = "", string source="",MessageType type = MessageType.None, float delay = 0)
|
||||
{
|
||||
mStatusBarMessage = msg;
|
||||
mStatusBarMessageType = type;
|
||||
mStatusBarMessageDelay = delay;
|
||||
mStatusBarMessageLastTime = EditorApplication.timeSinceStartup;
|
||||
mSourceIdent = source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the StatusBar
|
||||
/// </summary>
|
||||
/// <param name="renderingZone">the rect to use</param>
|
||||
/// <param name="style">(Optional) A style to override the default style</param>
|
||||
/// <param name="fit">Allow the <paramref name="renderingZone"/> to be modified to fit the text to render</param>
|
||||
/// <returns>true if you should do a repaint (i.e. a color fade is in progress)</returns>
|
||||
public bool Render(Rect renderingZone, GUIStyle style=null, bool fit=false)
|
||||
{
|
||||
if (!Visible || string.IsNullOrEmpty(mStatusBarMessage))
|
||||
return false;
|
||||
|
||||
Color c = GUI.contentColor;
|
||||
//Color bc = GUI.backgroundColor;
|
||||
GetColors();
|
||||
GUI.contentColor = GUI.contentColor.Fade(mStatusBarMessageLastTime, mStatusBarMessageDelay, 1);
|
||||
bool repaint = (EditorApplication.timeSinceStartup-mStatusBarMessageDelay<mStatusBarMessageLastTime);
|
||||
if (fit)
|
||||
{
|
||||
Vector2 calcSize = EditorStyles.label.CalcSize(new GUIContent(mStatusBarMessage));
|
||||
float w=calcSize.x + 20;
|
||||
renderingZone.x += (renderingZone.width - w) / 2;
|
||||
renderingZone.width = w;
|
||||
float h = calcSize.y;
|
||||
renderingZone.y += renderingZone.height - h;
|
||||
renderingZone.height = h;
|
||||
}
|
||||
|
||||
EditorGUI.LabelField(renderingZone, mStatusBarMessage, style==null ? MessageStyle:style);
|
||||
GUI.contentColor = c;
|
||||
//GUI.backgroundColor = bc;
|
||||
return repaint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e51fd46e878d264ead8664f69a93db9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,124 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
using FluffyUnderware.DevToolsEditor.Extensions;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public static class DTStyles
|
||||
{
|
||||
|
||||
public static GUIStyle BackdropHtmlLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mBackdropHtmlLabel == null)
|
||||
{
|
||||
mBackdropHtmlLabel = new GUIStyle();//GUI.skin.GetStyle("HelpBox"));
|
||||
mBackdropHtmlLabel.alignment = TextAnchor.MiddleCenter;
|
||||
Texture2D bgTex = new Texture2D(1, 1);
|
||||
bgTex.SetPixel(0, 0, new Color(1, 1, 1, 0.3f));
|
||||
bgTex.Apply();
|
||||
bgTex.hideFlags = HideFlags.DontSave;
|
||||
mBackdropHtmlLabel.padding = new RectOffset(1, 2, 0, 0);
|
||||
mBackdropHtmlLabel.normal.background = bgTex;
|
||||
mBackdropHtmlLabel.richText = true;
|
||||
}
|
||||
return mBackdropHtmlLabel;
|
||||
}
|
||||
}
|
||||
static GUIStyle mBackdropHtmlLabel;
|
||||
|
||||
static GUIStyle mTBButton;
|
||||
public static GUIStyle TBButton
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mTBButton == null)
|
||||
{
|
||||
mTBButton = new GUIStyle(GUI.skin.button);
|
||||
mTBButton.alignment = TextAnchor.MiddleLeft;
|
||||
mTBButton.padding.top = 4;
|
||||
mTBButton.padding.bottom = 2;
|
||||
}
|
||||
|
||||
return mTBButton;
|
||||
}
|
||||
}
|
||||
|
||||
static GUIStyle mTBBackground;
|
||||
public static GUIStyle TBBackground
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mTBBackground == null)
|
||||
{
|
||||
mTBBackground = new GUIStyle(GUI.skin.textArea);
|
||||
}
|
||||
return mTBBackground;
|
||||
}
|
||||
}
|
||||
|
||||
static GUIStyle mHtmlHelpBox;
|
||||
public static GUIStyle HtmlHelpBox
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mHtmlHelpBox == null)
|
||||
{
|
||||
mHtmlHelpBox= new GUIStyle(GUI.skin.GetStyle("HelpBox"));
|
||||
mHtmlHelpBox.richText = true;
|
||||
return mHtmlHelpBox;
|
||||
}
|
||||
return mHtmlHelpBox;
|
||||
}
|
||||
}
|
||||
|
||||
static GUIStyle mHtmlLabel;
|
||||
public static GUIStyle HtmlLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mHtmlLabel == null)
|
||||
{
|
||||
mHtmlLabel = new GUIStyle(GUI.skin.label);
|
||||
mHtmlLabel.richText = true;
|
||||
return mHtmlLabel;
|
||||
}
|
||||
return mHtmlLabel;
|
||||
}
|
||||
}
|
||||
|
||||
static GUIStyle mHtmlLinkLabel;
|
||||
public static GUIStyle HtmlLinkLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mHtmlLinkLabel == null)
|
||||
{
|
||||
mHtmlLinkLabel = new GUIStyle(EditorStyles.label);
|
||||
mHtmlLinkLabel.richText = true;
|
||||
int h = (int)mHtmlLinkLabel.lineHeight;
|
||||
mHtmlLinkLabel.normal.background = new Texture2D(1, h);
|
||||
Color lineCol = new Color(.44f, .57f, .79f);
|
||||
for (int i = 0; i < h; i++)
|
||||
mHtmlLinkLabel.normal.background.SetPixel(0, i, (i==3) ? lineCol : new Color(0,0,0,0));
|
||||
|
||||
mHtmlLinkLabel.normal.background.Apply();
|
||||
|
||||
mHtmlLinkLabel.hover.background = mHtmlLinkLabel.normal.background;
|
||||
mHtmlLinkLabel.hover.textColor = new Color(.44f, .57f, .79f);
|
||||
return mHtmlLinkLabel;
|
||||
}
|
||||
return mHtmlLinkLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7eda549546892154681be2d439a3445b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,412 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
public static class DTToolbar
|
||||
{
|
||||
const int ITEMSPACE = 10;
|
||||
const int PROJECTSPACE = 20;
|
||||
|
||||
public static bool RecalcItemSize = true;
|
||||
public static bool MouseOverToolbarElement { get; private set; }
|
||||
|
||||
static Vector2[] _MaxItemDimension = new Vector2[4]; // each Orientation has it's own max. Dimension
|
||||
/// <summary>
|
||||
/// Starting position for each side
|
||||
/// </summary>
|
||||
static Rect[] _InitialRects;
|
||||
/// <summary>
|
||||
/// Last item position for each side
|
||||
/// </summary>
|
||||
static Rect[] _ItemRect;
|
||||
|
||||
static Event _handleEvent;
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
RecalcItemSize = true;
|
||||
_handleEvent = null;
|
||||
loadItems();
|
||||
DTSelection.OnSelectionChange -= OnSelectionChange;
|
||||
DTSelection.OnSelectionChange += OnSelectionChange;
|
||||
SceneView.
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
duringSceneGui
|
||||
#else
|
||||
onSceneGUIDelegate
|
||||
#endif
|
||||
-= Render;
|
||||
SceneView.
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
duringSceneGui
|
||||
#else
|
||||
onSceneGUIDelegate
|
||||
#endif
|
||||
+= Render;
|
||||
EditorApplication.hierarchyWindowItemOnGUI -= onHierarchy;
|
||||
EditorApplication.hierarchyWindowItemOnGUI += onHierarchy;
|
||||
EditorApplication.update -= onUpdate;
|
||||
EditorApplication.update += onUpdate;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void loadItems()
|
||||
{
|
||||
foreach (DTProject prj in DT.Projects)
|
||||
prj.ToolbarItems.Clear();
|
||||
|
||||
TypeCache.TypeCollection toolbarItemTypes = TypeCache.GetTypesDerivedFrom(typeof(DTToolbarItem));
|
||||
toolbarItemTypes.Intersect(TypeCache.GetTypesWithAttribute<ToolbarItemAttribute>()).ForEach(type => Activator.CreateInstance(type));
|
||||
|
||||
foreach (DTProject prj in DT.Projects)
|
||||
prj.ToolbarItems.Sort();
|
||||
}
|
||||
|
||||
static void OnSelectionChange()
|
||||
{
|
||||
foreach (DTProject project in DT.Projects)
|
||||
foreach (DTToolbarItem item in project.ToolbarItems)
|
||||
item.OnSelectionChange();
|
||||
|
||||
RecalcItemSize = true;
|
||||
}
|
||||
|
||||
static void onHierarchy(int instanceID, Rect selectionRect)
|
||||
{
|
||||
if (Selection.instanceIDs.Contains(instanceID))
|
||||
_handleEvent = new Event(Event.current);
|
||||
}
|
||||
|
||||
static void onUpdate()
|
||||
{
|
||||
if (Event.current != null || _handleEvent != null)
|
||||
{
|
||||
DTSelection.MuteEvents = true;
|
||||
foreach (DTProject project in DT.Projects)
|
||||
foreach (DTToolbarItem item in project.ToolbarItems)
|
||||
{
|
||||
if (_handleEvent != null && item.Visible && item.Enabled)
|
||||
item.HandleEvents(_handleEvent);
|
||||
if (Event.current != null && item.Visible && item.Enabled)
|
||||
item.HandleEvents(Event.current);
|
||||
}
|
||||
DTSelection.MuteEvents = false;
|
||||
}
|
||||
_handleEvent = null;
|
||||
}
|
||||
|
||||
|
||||
static Rect getStatusBarRect()
|
||||
{
|
||||
Vector2 v = GUIUtility.GUIToScreenPoint(Vector2.zero);
|
||||
Rect r = SceneView.currentDrawingSceneView.position;
|
||||
// If SceneView is on another monitor, r.x doesn't start at 0, but GUIToScreenPoint gives the offset
|
||||
r.x -= v.x;
|
||||
r.y = _ItemRect[(int)DTToolbarOrientation.Bottom].y - 25;
|
||||
r.height = 20;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public static bool detailOpen;
|
||||
|
||||
static void Render(SceneView view)
|
||||
{
|
||||
Event ev = Event.current;
|
||||
MouseOverToolbarElement = false;
|
||||
// Only let certain hotkeys pass
|
||||
if (!EditorGUIUtility.editingTextField)
|
||||
{
|
||||
GUIUtility.keyboardControl = GUIUtility.GetControlID(FocusType.Passive);
|
||||
}
|
||||
|
||||
List<DTProject> projects = DT.Projects;
|
||||
projects.Sort();
|
||||
|
||||
Handles.BeginGUI();
|
||||
GUI.skin = null; // to ensure light-skin is used if set in preferences (or not Pro)
|
||||
// Get largest item for each side
|
||||
if (RecalcItemSize)
|
||||
calcMaxItemDimension();
|
||||
|
||||
// Get starting position for each side
|
||||
_InitialRects = getInitialItemRect();
|
||||
_ItemRect = new Rect[4];
|
||||
_InitialRects.CopyTo(_ItemRect, 0);
|
||||
|
||||
DTToolbarItem lastItem = null;
|
||||
DTSelection.MuteEvents = true;
|
||||
|
||||
DTToolbarItem hovering = null;
|
||||
|
||||
foreach (DTProject project in projects)
|
||||
{
|
||||
int side = (int)project.ToolbarOrientation;
|
||||
if (lastItem && lastItem.Project.ToolbarOrientation != project.ToolbarOrientation)
|
||||
lastItem = null;
|
||||
List<DTToolbarItem> items = project.ToolbarItems;
|
||||
|
||||
// Render items
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
if (items[i].Visible)
|
||||
{
|
||||
Vector2 itemSize = items[i].GetItemSize(); // size of current item
|
||||
_ItemRect[side] = advanceItemRect(lastItem, items[i], itemSize); // advance by using the last itemRect and the new(current) size
|
||||
|
||||
items[i].mItemRect = _ItemRect[side]; // Store current item rect
|
||||
|
||||
|
||||
if (items[i].Enabled)
|
||||
{
|
||||
Handles.EndGUI();
|
||||
EditorKeyBinding.BindingsEnabled = false;
|
||||
if (items[i].mItemRect.Contains(DTGUI.MousePosition))
|
||||
{
|
||||
hovering = items[i];
|
||||
MouseOverToolbarElement = true;
|
||||
}
|
||||
items[i].OnSceneGUI();
|
||||
|
||||
EditorKeyBinding.BindingsEnabled = true;
|
||||
Handles.BeginGUI();
|
||||
}
|
||||
GUI.enabled = items[i].Enabled;
|
||||
items[i].Render(_ItemRect[side]);
|
||||
|
||||
GUI.enabled = true;
|
||||
if (ev != null && items[i].Enabled && (DTToolbarItem.FocusedItem == null || DTToolbarItem.FocusedItem == items[i]))
|
||||
items[i].HandleEvents(ev);
|
||||
|
||||
lastItem = items[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
DTSelection.MuteEvents = false;
|
||||
detailOpen = false;
|
||||
// Render items client area (Note: itemRect contains the last rendered item, a.k.a. a way to get the number of rows/cols needed
|
||||
foreach (DTProject project in projects)
|
||||
{
|
||||
List<DTToolbarItem> items = project.ToolbarItems;
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
if (items[i].Visible && items[i].ShowClientArea)
|
||||
{
|
||||
detailOpen = true;
|
||||
Rect clientRect = items[i].mItemRect;
|
||||
int side = (int)project.ToolbarOrientation;
|
||||
switch (project.ToolbarOrientation)
|
||||
{
|
||||
case DTToolbarOrientation.Left:
|
||||
clientRect.x = _ItemRect[side].x + _MaxItemDimension[side].x + 5;
|
||||
break;
|
||||
case DTToolbarOrientation.Right:
|
||||
clientRect.x = _ItemRect[side].x - 5;
|
||||
break;
|
||||
case DTToolbarOrientation.Top:
|
||||
clientRect.y = _ItemRect[side].y + _MaxItemDimension[side].y + 5;
|
||||
break;
|
||||
case DTToolbarOrientation.Bottom:
|
||||
clientRect.y = _ItemRect[side].y - 5;
|
||||
break;
|
||||
}
|
||||
if (clientRect.width > 0 && clientRect.height > 0)
|
||||
{
|
||||
items[i].mBackgroundRects.Clear();
|
||||
MouseOverToolbarElement = MouseOverToolbarElement || clientRect.Contains(DTGUI.MousePosition);
|
||||
EditorKeyBinding.BindingsEnabled = false;
|
||||
items[i].RenderClientArea(clientRect);
|
||||
EditorKeyBinding.BindingsEnabled = true;
|
||||
if (DTGUI.IsClick)
|
||||
foreach (Rect r in items[i].mBackgroundRects)
|
||||
if (r.Contains(ev.mousePosition))
|
||||
DTGUI.UseEvent(items[i].GetHashCode(), ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle statusbar info when hovering over an item
|
||||
if (hovering != null)
|
||||
DTToolbarItem._StatusBar.Set(hovering.StatusBarInfo, "Info");
|
||||
else
|
||||
DTToolbarItem._StatusBar.Clear("Info");
|
||||
|
||||
// Render Statusbar
|
||||
DTToolbarItem._StatusBar.Render(getStatusBarRect(), null, true);
|
||||
|
||||
Handles.EndGUI();
|
||||
|
||||
}
|
||||
|
||||
static Rect[] getInitialItemRect()
|
||||
{
|
||||
Rect[] res = new Rect[4];
|
||||
for (int side = 0; side < 4; side++)
|
||||
{
|
||||
Rect r = new Rect();
|
||||
switch (side)
|
||||
{
|
||||
case (int)DTToolbarOrientation.Left:
|
||||
r.x = 5; r.y = 10;
|
||||
break;
|
||||
case (int)DTToolbarOrientation.Right:
|
||||
r.x = SceneView.currentDrawingSceneView.position.width - 10 - _MaxItemDimension[side].x;
|
||||
r.y = 115;
|
||||
break;
|
||||
case (int)DTToolbarOrientation.Top:
|
||||
float lft = _MaxItemDimension[(int)DTToolbarOrientation.Left].x;
|
||||
r.x = 5; r.y = 10;
|
||||
if (lft > 0)
|
||||
r.x += 10 + lft;
|
||||
break;
|
||||
default: // Bottom
|
||||
lft = _MaxItemDimension[(int)DTToolbarOrientation.Left].x;
|
||||
r.x = 5; r.y = SceneView.currentDrawingSceneView.position.height - _MaxItemDimension[side].y - 30;
|
||||
if (lft > 0)
|
||||
r.x += 10 + lft;
|
||||
break;
|
||||
}
|
||||
res[side] = r;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static Rect advanceItemRect(DTToolbarItem lastItem, DTToolbarItem newItem, Vector2 newItemSize)
|
||||
{
|
||||
Rect itemRect;
|
||||
float space = 0;
|
||||
int side = (int)newItem.Project.ToolbarOrientation;
|
||||
|
||||
if (lastItem != null)
|
||||
{
|
||||
itemRect = lastItem.mItemRect;
|
||||
if (lastItem.Project != newItem.Project)
|
||||
space = PROJECTSPACE;
|
||||
else
|
||||
space = (newItem.Order - lastItem.Order >= 10) ? ITEMSPACE : 0;
|
||||
}
|
||||
else
|
||||
itemRect = _InitialRects[side];
|
||||
|
||||
switch (newItem.Project.ToolbarOrientation)
|
||||
{
|
||||
case DTToolbarOrientation.Left:
|
||||
itemRect.y += itemRect.height + 3 + space;
|
||||
if (itemRect.y + newItemSize.y > SceneView.currentDrawingSceneView.position.height - 30)
|
||||
{
|
||||
itemRect.y = 10;
|
||||
itemRect.x += _MaxItemDimension[(int)DTToolbarOrientation.Left].x + 5;
|
||||
}
|
||||
itemRect.width = _MaxItemDimension[(int)DTToolbarOrientation.Left].x;
|
||||
itemRect.height = newItemSize.y;
|
||||
break;
|
||||
case DTToolbarOrientation.Right:
|
||||
itemRect.y += itemRect.height + 3 + space;
|
||||
if (itemRect.y + newItemSize.y > SceneView.currentDrawingSceneView.position.height - 30)
|
||||
{
|
||||
itemRect.y = 10;
|
||||
itemRect.x -= _MaxItemDimension[(int)DTToolbarOrientation.Right].x + 5;
|
||||
}
|
||||
itemRect.width = _MaxItemDimension[(int)DTToolbarOrientation.Right].x;
|
||||
itemRect.height = newItemSize.y;
|
||||
break;
|
||||
case DTToolbarOrientation.Top:
|
||||
itemRect.x += 3 + itemRect.width + space;
|
||||
if (itemRect.x + newItemSize.x > SceneView.currentDrawingSceneView.position.width - _MaxItemDimension[(int)DTToolbarOrientation.Left].x - _MaxItemDimension[(int)DTToolbarOrientation.Right].x)
|
||||
{
|
||||
itemRect.x = _InitialRects[(int)DTToolbarOrientation.Top].x;
|
||||
itemRect.y += _MaxItemDimension[(int)DTToolbarOrientation.Top].y + 5;
|
||||
}
|
||||
itemRect.width = _MaxItemDimension[(int)DTToolbarOrientation.Top].x;
|
||||
itemRect.height = newItemSize.y;
|
||||
break;
|
||||
case DTToolbarOrientation.Bottom:
|
||||
itemRect.x += 3 + itemRect.width + space;
|
||||
if (itemRect.x + newItemSize.x > SceneView.currentDrawingSceneView.position.width - _MaxItemDimension[(int)DTToolbarOrientation.Left].x - _MaxItemDimension[(int)DTToolbarOrientation.Right].x)
|
||||
{
|
||||
itemRect.x = _InitialRects[(int)DTToolbarOrientation.Top].x;
|
||||
itemRect.y -= _MaxItemDimension[(int)DTToolbarOrientation.Bottom].y + 5;
|
||||
}
|
||||
itemRect.width = _MaxItemDimension[(int)DTToolbarOrientation.Bottom].x;
|
||||
itemRect.height = newItemSize.y;
|
||||
break;
|
||||
|
||||
}
|
||||
return itemRect;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For each side, find the item with the largest dimensions
|
||||
/// </summary>
|
||||
static void calcMaxItemDimension()
|
||||
{
|
||||
RecalcItemSize = false;
|
||||
_MaxItemDimension = new Vector2[4];
|
||||
int side;
|
||||
foreach (DTProject prj in DT.Projects)
|
||||
{
|
||||
side = (int)prj.ToolbarOrientation;
|
||||
foreach (DTToolbarItem item in prj.ToolbarItems)
|
||||
if (item.Visible)
|
||||
_MaxItemDimension[side] = Vector2.Max(_MaxItemDimension[side], item.GetItemSize());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal static void SetRadioGroupState(DTToolbarRadioButton active)
|
||||
{
|
||||
active.Project.SetRadioGroupState(active);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DTToolbarMode : int
|
||||
{
|
||||
Text = 1,
|
||||
Icon = 2,
|
||||
Full = 15,
|
||||
}
|
||||
|
||||
public enum DTToolbarOrientation : int
|
||||
{
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
Top = 2,
|
||||
Bottom = 3
|
||||
}
|
||||
|
||||
public class DTToolbarStatus : DTStatusbar
|
||||
{
|
||||
|
||||
protected override void GetColors()
|
||||
{
|
||||
GUI.contentColor = new Color(0, 0, 0, 0.75f);
|
||||
}
|
||||
protected override GUIStyle GetStyle()
|
||||
{
|
||||
GUIStyle style = base.GetStyle();
|
||||
style.alignment = TextAnchor.MiddleCenter;
|
||||
Texture2D bgTex = new Texture2D(1, 1);
|
||||
bgTex.SetPixel(0, 0, new Color(1, 1, 1, 0.5f));
|
||||
bgTex.Apply();
|
||||
bgTex.hideFlags = HideFlags.DontSave;
|
||||
style.normal.background = bgTex;
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d3bf3b884967a3469804e83d059b658
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,365 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using FluffyUnderware.DevTools;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
|
||||
public abstract class DTToolbarItem : IComparable
|
||||
{
|
||||
/// <summary>
|
||||
/// If set, disables event processing for all other items.
|
||||
/// </summary>
|
||||
public static DTToolbarItem FocusedItem { get; set; }
|
||||
public Texture2D Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
if (mIcon==null && !string.IsNullOrEmpty(mIconPackedString) && Project.Resource!=null)
|
||||
mIcon = Project.Resource.LoadPacked(mIconPackedString);
|
||||
return mIcon;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (mIcon != value)
|
||||
mIcon = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Label { get; set; }
|
||||
public string Tooltip { get; set; }
|
||||
public DTProject Project { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
public static DTToolbarStatus _StatusBar = new DTToolbarStatus();
|
||||
|
||||
public List<EditorKeyBinding> KeyBindings
|
||||
{
|
||||
get { return mKeyBindings;}
|
||||
}
|
||||
|
||||
public GUIStyle Style
|
||||
{
|
||||
get { return DTStyles.TBButton; }
|
||||
}
|
||||
|
||||
public GUIContent Content
|
||||
{
|
||||
get
|
||||
{
|
||||
string keyTT = (KeyBindings.Count>0) ? KeyBindings[0].ToTooltipString() : string.Empty;
|
||||
|
||||
switch (Project.ToolbarMode)
|
||||
{
|
||||
case DTToolbarMode.Icon:
|
||||
if (Icon != null)
|
||||
return new GUIContent(Icon, Tooltip + keyTT);
|
||||
else // fallback to "Text"
|
||||
return new GUIContent(Label, Tooltip + keyTT);
|
||||
case DTToolbarMode.Text:
|
||||
return new GUIContent(Label, Tooltip+keyTT);
|
||||
default:
|
||||
return new GUIContent(Label, Icon, Tooltip+keyTT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Visible
|
||||
{
|
||||
get { return mVisible; }
|
||||
set
|
||||
{
|
||||
if (mVisible != value)
|
||||
mVisible=value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get { return mEnabled; }
|
||||
set
|
||||
{
|
||||
if (mEnabled != value)
|
||||
mEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool ShowClientArea
|
||||
{
|
||||
get { return mShowClientArea; }
|
||||
set
|
||||
{
|
||||
if (mShowClientArea != value)
|
||||
mShowClientArea = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMouseOver
|
||||
{
|
||||
get
|
||||
{
|
||||
return mItemRect.Contains(DTGUI.MousePosition);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string StatusBarInfo
|
||||
{
|
||||
get { return string.Empty; }
|
||||
}
|
||||
|
||||
bool mVisible = true;
|
||||
bool mEnabled = true;
|
||||
bool mShowClientArea;
|
||||
string mIconPackedString;
|
||||
Texture2D mIcon;
|
||||
|
||||
List<EditorKeyBinding> mKeyBindings = new List<EditorKeyBinding>();
|
||||
|
||||
static DTToolbarItem _lastClickedItem;
|
||||
|
||||
internal Rect mItemRect;
|
||||
internal List<Rect> mBackgroundRects = new List<Rect>();
|
||||
|
||||
protected DTToolbarItem()
|
||||
{
|
||||
object[] attribs = this.GetType().GetCustomAttributes(typeof(ToolbarItemAttribute), true);
|
||||
if (attribs.Length > 0)
|
||||
{
|
||||
ToolbarItemAttribute a=(ToolbarItemAttribute)attribs[0];
|
||||
Project = DT.Project(a.Project);
|
||||
Project.ToolbarItems.Add(this);
|
||||
Label = a.Label;
|
||||
Tooltip = a.Tooltip;
|
||||
if (!string.IsNullOrEmpty(a.Icon))
|
||||
{
|
||||
mIconPackedString = (!EditorGUIUtility.isProSkin && !string.IsNullOrEmpty(a.IconLightSkin)) ? a.IconLightSkin : a.Icon;
|
||||
}
|
||||
Order = a.Order;
|
||||
OnSelectionChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region ### Events ###
|
||||
|
||||
public virtual void OnClick()
|
||||
{
|
||||
if (_lastClickedItem!=null && _lastClickedItem!=this)
|
||||
_lastClickedItem.OnOtherItemClicked(this);
|
||||
_lastClickedItem = this;
|
||||
}
|
||||
|
||||
public virtual void OnSelectionChange()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnOtherItemClicked(DTToolbarItem other)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Renders the item (button etc.) itself inside a Handles.BeginGUI()/Handles.EndGUI() block
|
||||
/// </summary>
|
||||
/// <param name="r">area to use</param>
|
||||
public virtual void Render(Rect r)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders an item's client area (if ShowClientArea==true) inside a Handles.BeginGUI()/Handles.EndGUI() block
|
||||
/// </summary>
|
||||
/// <param name="r">initial Rect with x/y set to starting position</param>
|
||||
public virtual void RenderClientArea(Rect r)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regular OnSceneGUI call. Place preview etc. here
|
||||
/// </summary>
|
||||
public virtual void OnSceneGUI()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the size of the item
|
||||
/// </summary>
|
||||
/// <returns>the size the item needs</returns>
|
||||
public virtual Vector2 GetItemSize()
|
||||
{
|
||||
return Style.CalcSize(Content);
|
||||
}
|
||||
|
||||
public virtual void HandleEvents(Event e)
|
||||
{
|
||||
if (KeyBindings.Count > 0 && KeyBindings[0].IsTriggered(e))
|
||||
OnClick();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region ### GUI Orientation Helpers ###
|
||||
|
||||
/// <summary>
|
||||
/// Changes the rect to properly place an GUI control with a certain width and height.
|
||||
/// </summary>
|
||||
/// <remarks>Call this before the first GUI control, but after Background()</remarks>
|
||||
/// <param name="r"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <param name="height"></param>
|
||||
protected void SetElementSize(ref Rect r, float width, float height)
|
||||
{
|
||||
r.width = width;
|
||||
r.height = height;
|
||||
switch (Project.ToolbarOrientation)
|
||||
{
|
||||
case DTToolbarOrientation.Right:
|
||||
r.x -= r.width;
|
||||
break;
|
||||
case DTToolbarOrientation.Bottom:
|
||||
r.y-=r.height;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//SmallLineAdjust(ref r,height);
|
||||
Rect scene=SceneView.currentDrawingSceneView.position;
|
||||
|
||||
if (r.xMax > scene.width)
|
||||
r.xMin = scene.width - r.width;
|
||||
if (r.yMax > scene.height)
|
||||
r.yMin = scene.height - r.height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a background, taking only position from the rect
|
||||
/// </summary>
|
||||
/// <param name="r"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <param name="height"></param>
|
||||
/// <param name="guiStyle"></param>
|
||||
protected void Background(Rect r, float width, float height,GUIStyle guiStyle=null)
|
||||
{
|
||||
mBackgroundRects.Add(r);
|
||||
if (guiStyle == null)
|
||||
guiStyle = DTStyles.TBBackground;
|
||||
r.y -= 1;
|
||||
r.x -= 1;
|
||||
r.width = width + 2;
|
||||
r.height = height + 2;
|
||||
switch (Project.ToolbarOrientation)
|
||||
{
|
||||
case DTToolbarOrientation.Right:
|
||||
r.x-=width;
|
||||
break;
|
||||
case DTToolbarOrientation.Bottom:
|
||||
r.y -= height;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
GUI.Box(r, "", guiStyle);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advance the rect to a new line, respecting Toolbar Orientation
|
||||
/// </summary>
|
||||
protected void Advance(ref Rect r) { Advance(ref r, r.height); }
|
||||
/// <summary>
|
||||
/// Advance the rect to a new line, respecting Toolbar Orientation
|
||||
/// </summary>
|
||||
protected void Advance(ref Rect r, float lastLineHeight)
|
||||
{
|
||||
switch (Project.ToolbarOrientation)
|
||||
{
|
||||
case DTToolbarOrientation.Bottom:
|
||||
r.y -= lastLineHeight + 5;
|
||||
break;
|
||||
case DTToolbarOrientation.Left:
|
||||
r.x += r.width + 2;
|
||||
break;
|
||||
case DTToolbarOrientation.Right:
|
||||
r.x -= r.width + 2;
|
||||
break;
|
||||
default: // Top
|
||||
r.y += lastLineHeight + 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advance the rect to a new line below (or above) the existing rect, depending on Toolbar Orientation
|
||||
/// </summary>
|
||||
protected void AdvanceBelow(ref Rect r) { AdvanceBelow(ref r, r.height); }
|
||||
/// <summary>
|
||||
/// Advance the rect to a new line below (or above) the existing rect, depending on Toolbar Orientation
|
||||
/// </summary>
|
||||
protected void AdvanceBelow(ref Rect r, float lastLineHeight)
|
||||
{
|
||||
switch (Project.ToolbarOrientation)
|
||||
{
|
||||
case DTToolbarOrientation.Bottom:
|
||||
r.y -= lastLineHeight;
|
||||
break;
|
||||
default:
|
||||
r.y += lastLineHeight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
DTToolbarItem other = (DTToolbarItem)obj;
|
||||
|
||||
if (Order == other.Order)
|
||||
return Label.CompareTo(other.Label);
|
||||
else
|
||||
return Order.CompareTo(other.Order);
|
||||
}
|
||||
|
||||
public static implicit operator bool(DTToolbarItem a)
|
||||
{
|
||||
return !object.ReferenceEquals(a, null);
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class,AllowMultiple=false)]
|
||||
public class ToolbarItemAttribute : Attribute
|
||||
{
|
||||
public readonly string Project;
|
||||
public readonly int Order;
|
||||
public readonly string Label;
|
||||
public readonly string Tooltip;
|
||||
public readonly string Icon;
|
||||
public readonly string IconLightSkin;
|
||||
|
||||
public ToolbarItemAttribute(int order, string project, string label, string tooltip = "", string icon = "",string iconLight="") : this(project,label,tooltip,icon,iconLight,order)
|
||||
{
|
||||
}
|
||||
|
||||
public ToolbarItemAttribute(string project, string label, string tooltip = "", string icon = "", string iconLight="", int order = 0)
|
||||
{
|
||||
Project = project;
|
||||
Label = label;
|
||||
Tooltip = tooltip;
|
||||
Icon = icon;
|
||||
IconLightSkin = iconLight;
|
||||
Order = order;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c805355f5c0010740a0af2f9d9173e01
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,42 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AnimatedValues;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor.Data{
|
||||
[System.Serializable]
|
||||
public class AnimVector2 : BaseAnimValue<Vector2>
|
||||
{
|
||||
[SerializeField]
|
||||
private Vector3 m_Value;
|
||||
public AnimVector2()
|
||||
: base(Vector2.zero)
|
||||
{
|
||||
}
|
||||
public AnimVector2(Vector3 value)
|
||||
: base(value)
|
||||
{
|
||||
}
|
||||
public AnimVector2(Vector2 value, UnityAction callback)
|
||||
: base(value, callback)
|
||||
{
|
||||
}
|
||||
protected override Vector2 GetValue()
|
||||
{
|
||||
this.m_Value = Vector2.Lerp(base.start, base.target, base.lerpPosition);
|
||||
return this.m_Value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{value} / {target}. Speed {speed}. Lerp {lerpPosition}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ab6be8bc89cf594f8be7d642df90bf5
|
||||
timeCreated: 1440665948
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,170 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
[System.Serializable]
|
||||
public class EditorKeyBinding : IComparable
|
||||
{
|
||||
public static bool BindingsEnabled = true;
|
||||
|
||||
public enum MouseButtonEnum
|
||||
{
|
||||
None = -1,
|
||||
Click = 0,
|
||||
RClick = 1,
|
||||
MClick = 2,
|
||||
}
|
||||
|
||||
public string Name;
|
||||
public string Description;
|
||||
public KeyCode Key;
|
||||
public bool Shift;
|
||||
public bool Control;
|
||||
public bool Alt;
|
||||
public bool Command;
|
||||
public MouseButtonEnum MouseButton;
|
||||
|
||||
public bool ShowInPrefs = true;
|
||||
|
||||
public EditorKeyBinding(string name, string description, KeyCode defKey = KeyCode.None, bool defShift = false, bool defControl = false, bool defAlt = false, bool defCommand = false, MouseButtonEnum defMouseButton = MouseButtonEnum.None)
|
||||
{
|
||||
Set(name, description, defKey, defShift, defControl, defAlt, defCommand, defMouseButton);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a binding from it's serialized string from the user preferences
|
||||
/// </summary>
|
||||
public EditorKeyBinding(string bindingString)
|
||||
{
|
||||
Set(bindingString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the binding from it's serialized string from the user preferences
|
||||
/// </summary>
|
||||
public void Set(string bindingString)
|
||||
{
|
||||
string[] s = bindingString.Split(',');
|
||||
if (s.Length < 6) return;
|
||||
Name = s[0];
|
||||
Key = (KeyCode)System.Enum.Parse(typeof(KeyCode), s[1]);
|
||||
Shift = bool.Parse(s[2]);
|
||||
Control = bool.Parse(s[3]);
|
||||
Alt = bool.Parse(s[4]);
|
||||
Command = bool.Parse(s[5]);
|
||||
MouseButton = (MouseButtonEnum)System.Enum.Parse(typeof(MouseButtonEnum), s[6]);
|
||||
}
|
||||
|
||||
public void Set(string name, string description, KeyCode defKey = KeyCode.None, bool defShift = false, bool defControl = false, bool defAlt = false, bool defCommand = false, MouseButtonEnum defMouseButton = MouseButtonEnum.None)
|
||||
{
|
||||
Name = name;
|
||||
Description = description;
|
||||
Key = defKey;
|
||||
Shift = defShift;
|
||||
Control = defControl;
|
||||
Alt = defAlt;
|
||||
Command = defCommand;
|
||||
MouseButton = defMouseButton;
|
||||
}
|
||||
|
||||
|
||||
public bool IsTriggered(Event e=null)
|
||||
{
|
||||
|
||||
if (!BindingsEnabled)
|
||||
return false;
|
||||
|
||||
if (e == null)
|
||||
e = Event.current;
|
||||
if ((e.type == EventType.MouseDown && e.button == (int)MouseButton) ||
|
||||
(e.type == EventType.KeyDown && Key != KeyCode.None && e.keyCode == Key))
|
||||
return (e.shift == Shift &&
|
||||
e.control == Control &&
|
||||
e.alt == Alt &&
|
||||
e.command == Command);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnPreferencesGUI()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Key = (KeyCode)EditorGUILayout.EnumPopup(new GUIContent(Name), Key);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
Shift = GUILayout.Toggle(Shift, "Shift");
|
||||
Control = GUILayout.Toggle(Control, "Ctrl");
|
||||
Alt = GUILayout.Toggle(Alt, "Alt");
|
||||
Command = GUILayout.Toggle(Command, "Cmd");
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
MouseButton = (MouseButtonEnum)EditorGUILayout.EnumPopup(MouseButton);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
return EditorGUI.EndChangeCheck();
|
||||
}
|
||||
|
||||
public string ToTooltipString()
|
||||
{
|
||||
if (Key == KeyCode.None && MouseButton==MouseButtonEnum.None)
|
||||
return string.Empty;
|
||||
|
||||
List<string> s = new List<string>();
|
||||
if (Control)
|
||||
s.Add("Ctrl");
|
||||
if (Alt)
|
||||
s.Add("Alt");
|
||||
if (Shift)
|
||||
s.Add("Shift");
|
||||
if (Command)
|
||||
s.Add("Cmd");
|
||||
|
||||
string res = string.Join("-", s.ToArray());
|
||||
if (res.Length > 0)
|
||||
res += "-";
|
||||
|
||||
if (Key != KeyCode.None)
|
||||
return "(" + res + Key.ToString() + ")";
|
||||
else
|
||||
return "(" + res + MouseButton.ToString() + ")";
|
||||
}
|
||||
|
||||
public string ToPrefsString()
|
||||
{
|
||||
return Name + "," + ((int)Key).ToString() + "," + Shift.ToString() + "," + Control.ToString() + "," + Alt.ToString() + "," + Command.ToString() + "," + ((int)MouseButton).ToString();
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
return Name.CompareTo(((EditorKeyBinding)obj).Name);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
EditorKeyBinding o = (EditorKeyBinding)obj;
|
||||
return (Name == o.Name &&
|
||||
Key == o.Key &&
|
||||
Shift == o.Shift &&
|
||||
Control == o.Control &&
|
||||
Alt == o.Alt &&
|
||||
Command == o.Command &&
|
||||
MouseButton == o.MouseButton);
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Name.GetHashCode() ^ Key.GetHashCode() ^ Shift.GetHashCode() ^ Control.GetHashCode() ^ Alt.GetHashCode() ^ Command.GetHashCode() ^ MouseButton.GetHashCode();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97a419ac824222d41b8a477f5151f56a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08c16b9720ddc734eb7c69bbd147c2cd
|
||||
folderAsset: yes
|
||||
timeCreated: 1436273971
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,248 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using FluffyUnderware.DevTools.Extensions;
|
||||
using Object = UnityEngine.Object;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor.Extensions
|
||||
{
|
||||
|
||||
public static class ColorEditorExt
|
||||
{
|
||||
|
||||
public static Color SkinAwareColor(this Color c, bool subtle = false)
|
||||
{
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
return c;
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
|
||||
if (subtle)
|
||||
return Color.Lerp(c, Color.white,
|
||||
DTEditorUtility.UsesNewEditorUI ? 0.9f : 0.7f);
|
||||
else
|
||||
{
|
||||
if (c == Color.white)
|
||||
return Color.black;
|
||||
else if (c == Color.black)
|
||||
return Color.white;
|
||||
else
|
||||
{
|
||||
float br = c.Brightness();
|
||||
if (br > 0.9)
|
||||
return Color.Lerp(c, Color.black, 0.7f);
|
||||
else
|
||||
return Color.Lerp(c, Color.black, 0.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float Brightness(this Color c)
|
||||
{
|
||||
return 0.299f * c.r + 0.587f * c.g + 0.114f * c.b;
|
||||
}
|
||||
|
||||
public static Color Fade(this Color c, double startTime, double stayTime, float fadeSpeed)
|
||||
{
|
||||
double d = EditorApplication.timeSinceStartup - startTime;
|
||||
if (stayTime == 0 || d < stayTime)
|
||||
return c;
|
||||
else
|
||||
return new Color(c.r, c.g, c.b, 1 - Mathf.Clamp01((float)(d - stayTime) / Mathf.Max(0, 0001f, fadeSpeed)));
|
||||
}
|
||||
}
|
||||
|
||||
public static class SerializePropertyExt
|
||||
{
|
||||
|
||||
public static GUIContent GetContent(this SerializedProperty property, string label, string tooltip)
|
||||
{
|
||||
if (string.IsNullOrEmpty(label))
|
||||
label = property.displayName;
|
||||
return new GUIContent(label, tooltip);
|
||||
}
|
||||
|
||||
public static List<System.Attribute> GetAttributes(this SerializedProperty property, params System.Type[] ofType)
|
||||
{
|
||||
List<System.Attribute> res = new List<System.Attribute>();
|
||||
Type objType = property.GetObjectType();
|
||||
if (objType != null)
|
||||
{
|
||||
FieldInfo fi = objType.FieldByName(property.name, true, true);
|
||||
|
||||
if (fi != null)
|
||||
{
|
||||
object[] attribs = fi.GetCustomAttributes(true);
|
||||
foreach (System.Attribute a in attribs)
|
||||
{
|
||||
|
||||
if (ofType.Length == 0)
|
||||
res.Add(a);
|
||||
else
|
||||
{
|
||||
Type at = a.GetType();
|
||||
foreach (Type t in ofType)
|
||||
if (t.IsAssignableFrom(at))
|
||||
{
|
||||
res.Add(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the objec type the property is a children of.
|
||||
/// </summary>
|
||||
public static Type GetObjectType(this SerializedProperty property)
|
||||
{
|
||||
Type baseType = property.serializedObject.targetObject.GetType();
|
||||
if (property.depth > 0)
|
||||
{
|
||||
string[] path = property.Path();
|
||||
FieldInfo fi;
|
||||
for (int i = 0; i < path.Length - 1; i++)
|
||||
{
|
||||
fi = baseType.GetField(path[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (fi == null)
|
||||
return null;
|
||||
baseType = fi.FieldType;
|
||||
}
|
||||
}
|
||||
return baseType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the field type
|
||||
/// </summary>
|
||||
public static Type GetFieldType(this SerializedProperty property)
|
||||
{
|
||||
Type parentType = GetObjectType(property);
|
||||
FieldInfo fi = parentType.FieldByName(property.name, true, true);
|
||||
if (fi != null)
|
||||
{
|
||||
Type tt = fi.FieldType;
|
||||
if (tt.IsGenericType && tt.GetGenericTypeDefinition() == typeof(List<>))
|
||||
{
|
||||
return tt.GetGenericArguments()[0];
|
||||
}
|
||||
if (fi.FieldType.IsArray)
|
||||
return fi.FieldType.GetElementType();
|
||||
else
|
||||
return fi.FieldType;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string[] Path(this SerializedProperty property)
|
||||
{
|
||||
return property.propertyPath.Split('.');
|
||||
}
|
||||
|
||||
public static SerializedProperty Parent(this SerializedProperty property)
|
||||
{
|
||||
string[] path = property.propertyPath.Split('.');
|
||||
if (path.Length > 1)
|
||||
return property.serializedObject.FindProperty(path[path.Length - 2]);
|
||||
else
|
||||
return property;
|
||||
}
|
||||
|
||||
public static object GetParentObject(this SerializedProperty prop)
|
||||
{
|
||||
string path = prop.propertyPath.Replace(".Array.data[", "[");
|
||||
object obj = prop.serializedObject.targetObject;
|
||||
string[] elements = path.Split('.');
|
||||
for (int i = 0; i < elements.Length - 1; i++)
|
||||
{
|
||||
string element = elements[i];
|
||||
if (element.Contains("["))
|
||||
{
|
||||
string elementName = element.Substring(0, element.IndexOf("["));
|
||||
int index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
|
||||
obj = getValue(obj, elementName, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = getValue(obj, element);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
static object getValue(object source, string name)
|
||||
{
|
||||
if (source == null)
|
||||
return null;
|
||||
Type type = source.GetType();
|
||||
FieldInfo f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
if (f == null)
|
||||
{
|
||||
PropertyInfo p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
||||
if (p == null)
|
||||
return null;
|
||||
return p.GetValue(source, null);
|
||||
}
|
||||
return f.GetValue(source);
|
||||
}
|
||||
|
||||
static object getValue(object source, string name, int index)
|
||||
{
|
||||
IEnumerable enumerable = getValue(source, name) as IEnumerable;
|
||||
IEnumerator enm = enumerable.GetEnumerator();
|
||||
while (index-- >= 0)
|
||||
enm.MoveNext();
|
||||
return enm.Current;
|
||||
}
|
||||
|
||||
|
||||
public static SerializedProperty Root(this SerializedProperty property)
|
||||
{
|
||||
string[] path = property.propertyPath.Split('.');
|
||||
if (path.Length > 0)
|
||||
return property.serializedObject.FindProperty(path[0]);
|
||||
else
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RectEditorExt
|
||||
{
|
||||
public static Rect ShiftXBy(this Rect r, float x)
|
||||
{
|
||||
r.x += x;
|
||||
r.width -= x;
|
||||
return new Rect(r);
|
||||
}
|
||||
|
||||
public static Rect WithoutLabel(this Rect r)
|
||||
{
|
||||
return r.ShiftXBy(EditorGUIUtility.labelWidth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21c52a1cbd7d1274f95e82c253456bda
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name":"FluffyUnderware.DevTools.Editor",
|
||||
"references":[
|
||||
"ToolBuddy.ArraysPooling",
|
||||
"FluffyUnderware.DevTools"
|
||||
],
|
||||
"includePlatforms":[
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms":[]
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b1d373d568c0384aa3484d7d316284d
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bc4fb38a6e10f34c8923621b5f349d7
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0565c5d04b968af40bece709cba9bf78
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
|
||||
public class DTToolbarButton : DTToolbarItem
|
||||
{
|
||||
|
||||
public override void Render(Rect r)
|
||||
{
|
||||
if (GUI.Button(r, Content,DTStyles.TBButton))
|
||||
OnClick();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23190dcdedb51a74c914b829d6473b8c
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
|
||||
public class DTToolbarRadioButton : DTToolbarToggleButton
|
||||
{
|
||||
public string RadioGroup = string.Empty;
|
||||
|
||||
protected bool AllOffAllowed {get; set;}
|
||||
|
||||
public override bool On
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.On;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (mOn!=value)
|
||||
{
|
||||
if (value == true)
|
||||
DTToolbar.SetRadioGroupState(this);
|
||||
else if (AllOffAllowed)
|
||||
{
|
||||
mOn = false;
|
||||
OnClick();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShowClientArea
|
||||
{
|
||||
get
|
||||
{
|
||||
return On;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public DTToolbarRadioButton(string radioGroupName, bool defaultOn=false)
|
||||
{
|
||||
RadioGroup = radioGroupName;
|
||||
AllOffAllowed = false;
|
||||
mOn = defaultOn;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d892a9daccfb1d04ba11b0f7ecb26c70
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
|
||||
public class DTToolbarRadioOffButton : DTToolbarRadioButton
|
||||
{
|
||||
|
||||
public override bool On
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.On;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (mOn != value)
|
||||
{
|
||||
if (value == true)
|
||||
DTToolbar.SetRadioGroupState(this);
|
||||
else if (AllOffAllowed)
|
||||
{
|
||||
mOn = false;
|
||||
OnClick();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShowClientArea
|
||||
{
|
||||
get
|
||||
{
|
||||
return On;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public DTToolbarRadioOffButton(string radioGroupName, bool defaultOn=false)
|
||||
: base(radioGroupName,defaultOn)
|
||||
{
|
||||
AllOffAllowed = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41cca5920ca067a40b4b73d4db3f20e5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
// =====================================================================
|
||||
// Copyright 2013-2017 Fluffy Underware
|
||||
// All rights reserved
|
||||
//
|
||||
// http://www.fluffyunderware.com
|
||||
// =====================================================================
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace FluffyUnderware.DevToolsEditor
|
||||
{
|
||||
|
||||
public class DTToolbarToggleButton : DTToolbarItem
|
||||
{
|
||||
|
||||
public virtual bool On
|
||||
{
|
||||
get { return mOn; }
|
||||
set
|
||||
{
|
||||
if (mOn != value)
|
||||
{
|
||||
mOn = value;
|
||||
if (!mOn && FocusedItem == this)
|
||||
FocusedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool mOn;
|
||||
|
||||
public override bool ShowClientArea
|
||||
{
|
||||
get
|
||||
{
|
||||
return On;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void OnOtherItemClicked(DTToolbarItem other)
|
||||
{
|
||||
base.OnOtherItemClicked(other);
|
||||
On = false;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
base.OnClick();
|
||||
On = !On;
|
||||
}
|
||||
|
||||
public override void Render(Rect r)
|
||||
{
|
||||
bool b = GUI.Toggle(r, On, Content, DTStyles.TBButton);
|
||||
if (b!=On)
|
||||
OnClick();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53c6546eb43ea874e92c8a7b1a7ef015
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
Reference in new issue
Block a user