From 6d386c544d908f6d9ff409a9ecde66719be47756 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 30 Dec 2015 15:36:49 +0800 Subject: [PATCH] [Unity] SpineAttributeDrawer Update --- .../Editor/SpineAttributeDrawers.cs | 522 +++++------------- 1 file changed, 143 insertions(+), 379 deletions(-) diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs index 17810e6e0..6bb995da9 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs @@ -1,5 +1,4 @@ - /***************************************************************************** * Spine Attribute Drawers created by Mitch Thompson * Full irrevocable rights and permissions granted to Esoteric Software @@ -8,9 +7,6 @@ using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Linq; using System.Reflection; using Spine; @@ -25,21 +21,18 @@ public struct SpineDrawerValuePair { } } -[CustomPropertyDrawer(typeof(SpineSlot))] -public class SpineSlotDrawer : PropertyDrawer { - SkeletonDataAsset skeletonDataAsset; +public abstract class SpineTreeItemDrawerBase : PropertyDrawer where T:SpineAttributeBase { + protected SkeletonDataAsset skeletonDataAsset; + protected T TargetAttribute { get { return (T)attribute; } } - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) { if (property.propertyType != SerializedPropertyType.String) { EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); return; } - - SpineSlot attrib = (SpineSlot)attribute; - - var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - + + var dataProperty = property.serializedObject.FindProperty(TargetAttribute.dataField); + if (dataProperty != null) { if (dataProperty.objectReferenceValue is SkeletonDataAsset) { skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; @@ -51,7 +44,7 @@ public class SpineSlotDrawer : PropertyDrawer { EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); return; } - + } else if (property.serializedObject.targetObject is Component) { var component = (Component)property.serializedObject.targetObject; if (component.GetComponentInChildren() != null) { @@ -59,43 +52,60 @@ public class SpineSlotDrawer : PropertyDrawer { skeletonDataAsset = skeletonRenderer.skeletonDataAsset; } } - + if (skeletonDataAsset == null) { EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); return; } - + position = EditorGUI.PrefixLabel(position, label); - + if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { Selector(property); } - + } - void Selector(SerializedProperty property) { - SpineSlot attrib = (SpineSlot)attribute; + protected virtual void Selector (SerializedProperty property) { SkeletonData data = skeletonDataAsset.GetSkeletonData(true); if (data == null) return; - + GenericMenu menu = new GenericMenu(); + PopulateMenu (menu, property, this.TargetAttribute, data); + menu.ShowAsContext(); + } - menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); - menu.AddSeparator(""); + protected abstract void PopulateMenu (GenericMenu menu, SerializedProperty property, T targetAttribute, SkeletonData data); + protected virtual void HandleSelect (object val) { + var pair = (SpineDrawerValuePair)val; + pair.property.stringValue = pair.str; + pair.property.serializedObject.ApplyModifiedProperties(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { + return 18; + } + +} + +[CustomPropertyDrawer(typeof(SpineSlot))] +public class SpineSlotDrawer : SpineTreeItemDrawerBase { + + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineSlot targetAttribute, SkeletonData data) { for (int i = 0; i < data.Slots.Count; i++) { string name = data.Slots.Items[i].Name; - if (name.StartsWith(attrib.startsWith)) { - if (attrib.containsBoundingBoxes) { - + if (name.StartsWith(targetAttribute.startsWith)) { + if (targetAttribute.containsBoundingBoxes) { + int slotIndex = i; - + List attachments = new List(); foreach (var skin in data.Skins) { skin.FindAttachmentsForSlot(slotIndex, attachments); } - + bool hasBoundingBox = false; foreach (var attachment in attachments) { if (attachment is BoundingBoxAttachment) { @@ -104,315 +114,83 @@ public class SpineSlotDrawer : PropertyDrawer { break; } } - + if (!hasBoundingBox) menu.AddDisabledItem(new GUIContent(name)); - + } else { menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } - + } - - menu.ShowAsContext(); } - void HandleSelect(object val) { - var pair = (SpineDrawerValuePair)val; - pair.property.stringValue = pair.str; - pair.property.serializedObject.ApplyModifiedProperties(); - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - return 18; - } } [CustomPropertyDrawer(typeof(SpineSkin))] -public class SpineSkinDrawer : PropertyDrawer { - SkeletonDataAsset skeletonDataAsset; - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - if (property.propertyType != SerializedPropertyType.String) { - EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); - return; - } - - SpineSkin attrib = (SpineSkin)attribute; - - var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - - if (dataProperty != null) { - if (dataProperty.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; - } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { - var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; - if (renderer != null) - skeletonDataAsset = renderer.skeletonDataAsset; - } else { - EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); - return; - } - - } else if (property.serializedObject.targetObject is Component) { - var component = (Component)property.serializedObject.targetObject; - if (component.GetComponentInChildren() != null) { - var skeletonRenderer = component.GetComponentInChildren(); - skeletonDataAsset = skeletonRenderer.skeletonDataAsset; - } - } - - if (skeletonDataAsset == null) { - EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); - return; - } - - position = EditorGUI.PrefixLabel(position, label); - - if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { - Selector(property); - } - - } - - void Selector(SerializedProperty property) { - SpineSkin attrib = (SpineSkin)attribute; - SkeletonData data = skeletonDataAsset.GetSkeletonData(true); - if (data == null) - return; - - GenericMenu menu = new GenericMenu(); +public class SpineSkinDrawer : SpineTreeItemDrawerBase { + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineSkin targetAttribute, SkeletonData data) { menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); menu.AddSeparator(""); - + for (int i = 0; i < data.Skins.Count; i++) { string name = data.Skins.Items[i].Name; - if (name.StartsWith(attrib.startsWith)) + if (name.StartsWith(targetAttribute.startsWith)) menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } - - menu.ShowAsContext(); } - void HandleSelect(object val) { - var pair = (SpineDrawerValuePair)val; - pair.property.stringValue = pair.str; - pair.property.serializedObject.ApplyModifiedProperties(); - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - return 18; - } -} - -[CustomPropertyDrawer(typeof(SpineAtlasRegion))] -public class SpineAtlasRegionDrawer : PropertyDrawer { - Component component; - SerializedProperty atlasProp; - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - if (property.propertyType != SerializedPropertyType.String) { - EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); - return; - } - - component = (Component)property.serializedObject.targetObject; - - if (component != null) - atlasProp = property.serializedObject.FindProperty("atlasAsset"); - else - atlasProp = null; - - - if (atlasProp == null) { - EditorGUI.LabelField(position, "ERROR:", "Must have AtlasAsset variable!"); - return; - } else if (atlasProp.objectReferenceValue == null) { - EditorGUI.LabelField(position, "ERROR:", "Atlas variable must not be null!"); - return; - } else if (atlasProp.objectReferenceValue.GetType() != typeof(AtlasAsset)) { - EditorGUI.LabelField(position, "ERROR:", "Atlas variable must be of type AtlasAsset!"); - } - - position = EditorGUI.PrefixLabel(position, label); - - if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { - Selector(property); - } - - } - - void Selector(SerializedProperty property) { - GenericMenu menu = new GenericMenu(); - AtlasAsset atlasAsset = (AtlasAsset)atlasProp.objectReferenceValue; - Atlas atlas = atlasAsset.GetAtlas(); - FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); - List regions = (List)field.GetValue(atlas); - - for (int i = 0; i < regions.Count; i++) { - string name = regions[i].name; - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); - } - - - menu.ShowAsContext(); - } - - void HandleSelect(object val) { - var pair = (SpineDrawerValuePair)val; - pair.property.stringValue = pair.str; - pair.property.serializedObject.ApplyModifiedProperties(); - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - return 18; - } } [CustomPropertyDrawer(typeof(SpineAnimation))] -public class SpineAnimationDrawer : PropertyDrawer { - SkeletonDataAsset skeletonDataAsset; - - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - - - if (property.propertyType != SerializedPropertyType.String) { - EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); - return; - } - - SpineAnimation attrib = (SpineAnimation)attribute; - - var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - - if (dataProperty != null) { - if (dataProperty.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; - } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { - var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; - if (renderer != null) - skeletonDataAsset = renderer.skeletonDataAsset; - } else { - EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); - return; - } - } else if (property.serializedObject.targetObject is Component) { - var component = (Component)property.serializedObject.targetObject; - if (component.GetComponentInChildren() != null) { - var skeletonRenderer = component.GetComponentInChildren(); - skeletonDataAsset = skeletonRenderer.skeletonDataAsset; - } - } - - if (skeletonDataAsset == null) { - EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); - return; - } - - position = EditorGUI.PrefixLabel(position, label); - - if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { - Selector(property); - } - - } - - void Selector(SerializedProperty property) { - - SpineAnimation attrib = (SpineAnimation)attribute; - - GenericMenu menu = new GenericMenu(); - +public class SpineAnimationDrawer : SpineTreeItemDrawerBase { + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineAnimation targetAttribute, SkeletonData data) { var animations = skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations; for (int i = 0; i < animations.Count; i++) { string name = animations.Items[i].Name; - if (name.StartsWith(attrib.startsWith)) + if (name.StartsWith(targetAttribute.startsWith)) menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } - - menu.ShowAsContext(); } - void HandleSelect(object val) { - var pair = (SpineDrawerValuePair)val; - pair.property.stringValue = pair.str; - pair.property.serializedObject.ApplyModifiedProperties(); +} + +[CustomPropertyDrawer(typeof(SpineEventData))] +public class SpineEventDataDrawer : SpineTreeItemDrawerBase { + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineEventData targetAttribute, SkeletonData data) { + var events = skeletonDataAsset.GetSkeletonData(false).Events; + for (int i = 0; i < events.Count; i++) { + string name = events.Items[i].Name; + if (name.StartsWith(targetAttribute.startsWith)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } } - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - return 18; - } } [CustomPropertyDrawer(typeof(SpineAttachment))] -public class SpineAttachmentDrawer : PropertyDrawer { +public class SpineAttachmentDrawer : SpineTreeItemDrawerBase { + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineAttachment targetAttribute, SkeletonData data) { + List validSkins = new List(); + SkeletonRenderer skeletonRenderer = null; - SkeletonDataAsset skeletonDataAsset; - SkeletonRenderer skeletonRenderer; - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { - - if (property.propertyType != SerializedPropertyType.String) { - EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); - return; - } - - SpineAttachment attrib = (SpineAttachment)attribute; - - var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - - if (dataProperty != null) { - if (dataProperty.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; - } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { - var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; - if (renderer != null) - skeletonDataAsset = renderer.skeletonDataAsset; - else { - EditorGUI.LabelField(position, "ERROR:", "No SkeletonRenderer"); - } - } else { - EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); - return; - } - - } else if (property.serializedObject.targetObject is Component) { + if (property.serializedObject.targetObject is Component) { var component = (Component)property.serializedObject.targetObject; if (component.GetComponentInChildren() != null) { skeletonRenderer = component.GetComponentInChildren(); + if (skeletonDataAsset != skeletonRenderer.skeletonDataAsset) { + Debug.LogError("DataField SkeletonDataAsset and SkeletonRenderer/SkeletonAnimation's SkeletonDataAsset do not match. Remove the explicit dataField parameter of your [SpineAttachment] field."); + } + skeletonDataAsset = skeletonRenderer.skeletonDataAsset; } } - if (skeletonDataAsset == null && skeletonRenderer == null) { - EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset or SkeletonRenderer"); - return; - } - - position = EditorGUI.PrefixLabel(position, label); - - if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { - Selector(property); - } - - } - - void Selector(SerializedProperty property) { - SkeletonData data = skeletonDataAsset.GetSkeletonData(true); - - if (data == null) - return; - - SpineAttachment attrib = (SpineAttachment)attribute; - - List validSkins = new List(); - - if (skeletonRenderer != null && attrib.currentSkinOnly) { + if (skeletonRenderer != null && targetAttribute.currentSkinOnly) { if (skeletonRenderer.skeleton.Skin != null) { validSkins.Add(skeletonRenderer.skeleton.Skin); } else { @@ -424,62 +202,61 @@ public class SpineAttachmentDrawer : PropertyDrawer { validSkins.Add(skin); } } - - GenericMenu menu = new GenericMenu(); + List attachmentNames = new List(); List placeholderNames = new List(); - + string prefix = ""; - - if (skeletonRenderer != null && attrib.currentSkinOnly) + + if (skeletonRenderer != null && targetAttribute.currentSkinOnly) menu.AddDisabledItem(new GUIContent(skeletonRenderer.gameObject.name + " (SkeletonRenderer)")); else menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); menu.AddSeparator(""); - + menu.AddItem(new GUIContent("Null"), property.stringValue == "", HandleSelect, new SpineDrawerValuePair("", property)); menu.AddSeparator(""); - + Skin defaultSkin = data.Skins.Items[0]; - - SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotField); + + SerializedProperty slotProperty = property.serializedObject.FindProperty(targetAttribute.slotField); string slotMatch = ""; if (slotProperty != null) { if (slotProperty.propertyType == SerializedPropertyType.String) { slotMatch = slotProperty.stringValue.ToLower(); } } - + foreach (Skin skin in validSkins) { string skinPrefix = skin.Name + "/"; - + if (validSkins.Count > 1) prefix = skinPrefix; - + for (int i = 0; i < data.Slots.Count; i++) { if (slotMatch.Length > 0 && data.Slots.Items[i].Name.ToLower().Contains(slotMatch) == false) continue; - + attachmentNames.Clear(); placeholderNames.Clear(); - + skin.FindNamesForSlot(i, attachmentNames); if (skin != defaultSkin) { defaultSkin.FindNamesForSlot(i, attachmentNames); skin.FindNamesForSlot(i, placeholderNames); } - - + + for (int a = 0; a < attachmentNames.Count; a++) { string attachmentPath = attachmentNames[a]; string menuPath = prefix + data.Slots.Items[i].Name + "/" + attachmentPath; string name = attachmentNames[a]; - - if (attrib.returnAttachmentPath) + + if (targetAttribute.returnAttachmentPath) name = skin.Name + "/" + data.Slots.Items[i].Name + "/" + attachmentPath; - - if (attrib.placeholdersOnly && placeholderNames.Contains(attachmentPath) == false) { + + if (targetAttribute.placeholdersOnly && placeholderNames.Contains(attachmentPath) == false) { menu.AddDisabledItem(new GUIContent(menuPath)); } else { menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); @@ -489,96 +266,83 @@ public class SpineAttachmentDrawer : PropertyDrawer { } } } - - - menu.ShowAsContext(); } - void HandleSelect(object val) { - var pair = (SpineDrawerValuePair)val; - pair.property.stringValue = pair.str; - pair.property.serializedObject.ApplyModifiedProperties(); - } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - return 18; - } } [CustomPropertyDrawer(typeof(SpineBone))] -public class SpineBoneDrawer : PropertyDrawer { - SkeletonDataAsset skeletonDataAsset; +public class SpineBoneDrawer : SpineTreeItemDrawerBase { + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineBone targetAttribute, SkeletonData data) { + menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); + menu.AddSeparator(""); + + for (int i = 0; i < data.Bones.Count; i++) { + string name = data.Bones.Items[i].Name; + if (name.StartsWith(targetAttribute.startsWith)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + } + +} + +[CustomPropertyDrawer(typeof(SpineAtlasRegion))] +public class SpineAtlasRegionDrawer : PropertyDrawer { + Component component; + SerializedProperty atlasProp; + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (property.propertyType != SerializedPropertyType.String) { EditorGUI.LabelField(position, "ERROR:", "May only apply to type string"); return; } - - SpineBone attrib = (SpineBone)attribute; - - var dataProperty = property.serializedObject.FindProperty(attrib.dataField); - - if (dataProperty != null) { - if (dataProperty.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue; - } else if (dataProperty.objectReferenceValue is SkeletonRenderer) { - var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue; - if (renderer != null) - skeletonDataAsset = renderer.skeletonDataAsset; - } else { - EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); - return; - } - - } else if (property.serializedObject.targetObject is Component) { - var component = (Component)property.serializedObject.targetObject; - if (component.GetComponentInChildren() != null) { - var skeletonRenderer = component.GetComponentInChildren(); - skeletonDataAsset = skeletonRenderer.skeletonDataAsset; - } - } - - if (skeletonDataAsset == null) { - EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); + + component = (Component)property.serializedObject.targetObject; + + if (component != null) + atlasProp = property.serializedObject.FindProperty("atlasAsset"); + else + atlasProp = null; + + + if (atlasProp == null) { + EditorGUI.LabelField(position, "ERROR:", "Must have AtlasAsset variable!"); return; + } else if (atlasProp.objectReferenceValue == null) { + EditorGUI.LabelField(position, "ERROR:", "Atlas variable must not be null!"); + return; + } else if (atlasProp.objectReferenceValue.GetType() != typeof(AtlasAsset)) { + EditorGUI.LabelField(position, "ERROR:", "Atlas variable must be of type AtlasAsset!"); } - + position = EditorGUI.PrefixLabel(position, label); - + if (GUI.Button(position, property.stringValue, EditorStyles.popup)) { Selector(property); } - + } - - void Selector(SerializedProperty property) { - SpineBone attrib = (SpineBone)attribute; - SkeletonData data = skeletonDataAsset.GetSkeletonData(true); - if (data == null) - return; - + + void Selector (SerializedProperty property) { GenericMenu menu = new GenericMenu(); - - menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name)); - menu.AddSeparator(""); - - for (int i = 0; i < data.Bones.Count; i++) { - string name = data.Bones.Items[i].Name; - if (name.StartsWith(attrib.startsWith)) - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + AtlasAsset atlasAsset = (AtlasAsset)atlasProp.objectReferenceValue; + Atlas atlas = atlasAsset.GetAtlas(); + FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); + List regions = (List)field.GetValue(atlas); + + for (int i = 0; i < regions.Count; i++) { + string name = regions[i].name; + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } - + + menu.ShowAsContext(); } - - void HandleSelect(object val) { + + static void HandleSelect (object val) { var pair = (SpineDrawerValuePair)val; pair.property.stringValue = pair.str; pair.property.serializedObject.ApplyModifiedProperties(); } - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - return 18; - } -} \ No newline at end of file + +}