轨迹插件引入

This commit is contained in:
lishuo committed 2022-09-06 13:47:45 +08:00
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:
@@ -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);
}
}
}
@@ -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();
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 21c52a1cbd7d1274f95e82c253456bda
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,11 @@
{
"name":"FluffyUnderware.DevTools.Editor",
"references":[
"ToolBuddy.ArraysPooling",
"FluffyUnderware.DevTools"
],
"includePlatforms":[
"Editor"
],
"excludePlatforms":[]
}
@@ -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:
@@ -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();
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 23190dcdedb51a74c914b829d6473b8c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -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;
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d892a9daccfb1d04ba11b0f7ecb26c70
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -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;
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 41cca5920ca067a40b4b73d4db3f20e5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -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();
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 53c6546eb43ea874e92c8a7b1a7ef015
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: