diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs index fd8c13d94..55d1f3ae8 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs @@ -74,15 +74,16 @@ namespace Spine.Unity.Editor { return; } - var dataField = property.FindBaseOrSiblingProperty(TargetAttribute.dataField); + SerializedProperty dataField = property.FindBaseOrSiblingProperty(TargetAttribute.dataField); if (dataField != null) { - if (dataField.objectReferenceValue is SkeletonDataAsset) { - skeletonDataAsset = (SkeletonDataAsset)dataField.objectReferenceValue; - } else if (dataField.objectReferenceValue is ISkeletonComponent) { - var skeletonComponent = (ISkeletonComponent)dataField.objectReferenceValue; + var objectReferenceValue = dataField.objectReferenceValue; + if (objectReferenceValue is SkeletonDataAsset) { + skeletonDataAsset = (SkeletonDataAsset)objectReferenceValue; + } else if (objectReferenceValue is ISkeletonComponent) { + var skeletonComponent = (ISkeletonComponent)objectReferenceValue; if (skeletonComponent != null) skeletonDataAsset = skeletonComponent.SkeletonDataAsset; - } else { + } else if (objectReferenceValue != null) { EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); return; } @@ -95,7 +96,12 @@ namespace Spine.Unity.Editor { } if (skeletonDataAsset == null) { - EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); + if (TargetAttribute.fallbackToTextField) { + EditorGUI.PropertyField(position, property); //EditorGUI.TextField(position, label, property.stringValue); + } else { + EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset"); + } + skeletonDataAsset = property.serializedObject.targetObject as SkeletonDataAsset; if (skeletonDataAsset == null) return; } diff --git a/spine-unity/Assets/spine-unity/SpineAttributes.cs b/spine-unity/Assets/spine-unity/SpineAttributes.cs index 8836c0a43..5f3d7ed91 100644 --- a/spine-unity/Assets/spine-unity/SpineAttributes.cs +++ b/spine-unity/Assets/spine-unity/SpineAttributes.cs @@ -41,6 +41,7 @@ namespace Spine.Unity { public string dataField = ""; public string startsWith = ""; public bool includeNone = true; + public bool fallbackToTextField = false; } public class SpineSlot : SpineAttributeBase { @@ -52,15 +53,17 @@ namespace Spine.Unity { /// Filters popup results to elements that begin with supplied string. /// Disables popup results that don't contain bounding box attachments when true. /// If true, the dropdown list will include a "none" option which stored as an empty string. + /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives). /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. /// - public SpineSlot(string startsWith = "", string dataField = "", bool containsBoundingBoxes = false, bool includeNone = true) { + public SpineSlot (string startsWith = "", string dataField = "", bool containsBoundingBoxes = false, bool includeNone = true, bool fallbackToTextField = false) { this.startsWith = startsWith; this.dataField = dataField; this.containsBoundingBoxes = containsBoundingBoxes; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } } @@ -72,12 +75,14 @@ namespace Spine.Unity { /// If true, the dropdown list will include a "none" option which stored as an empty string. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives). - /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. + /// If left empty and the script the attribute is applied to is derived from Component, GetComponent(SkeletonRenderer)() will be called as a fallback. /// - public SpineEvent(string startsWith = "", string dataField = "", bool includeNone = true) { + /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. + public SpineEvent (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false) { this.startsWith = startsWith; this.dataField = dataField; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } } @@ -89,12 +94,14 @@ namespace Spine.Unity { /// If true, the dropdown list will include a "none" option which stored as an empty string. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives). - /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. + /// If left empty and the script the attribute is applied to is derived from Component, GetComponent(SkeletonRenderer)() will be called as a fallback. /// - public SpineIkConstraint(string startsWith = "", string dataField = "", bool includeNone = true) { + /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. + public SpineIkConstraint (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false) { this.startsWith = startsWith; this.dataField = dataField; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } } @@ -106,12 +113,13 @@ namespace Spine.Unity { /// If true, the dropdown list will include a "none" option which stored as an empty string. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives). - /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. + /// If left empty and the script the attribute is applied to is derived from Component, GetComponent(SkeletonRenderer)() will be called as a fallback. /// - public SpinePathConstraint(string startsWith = "", string dataField = "", bool includeNone = true) { + public SpinePathConstraint (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false) { this.startsWith = startsWith; this.dataField = dataField; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } } @@ -121,14 +129,16 @@ namespace Spine.Unity { /// /// Filters popup results to elements that begin with supplied string. /// If true, the dropdown list will include a "none" option which stored as an empty string. + /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives). /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. /// - public SpineTransformConstraint(string startsWith = "", string dataField = "", bool includeNone = true) { + public SpineTransformConstraint (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false) { this.startsWith = startsWith; this.dataField = dataField; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } } @@ -138,14 +148,16 @@ namespace Spine.Unity { /// /// Filters popup results to elements that begin with supplied string. /// If true, the dropdown list will include a "none" option which stored as an empty string. + /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. /// - public SpineSkin(string startsWith = "", string dataField = "", bool includeNone = true) { + public SpineSkin (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false) { this.startsWith = startsWith; this.dataField = dataField; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } } public class SpineAnimation : SpineAttributeBase { @@ -153,15 +165,17 @@ namespace Spine.Unity { /// Smart popup menu for Spine Animations /// /// Filters popup results to elements that begin with supplied string. - /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. + /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. /// If true, the dropdown list will include a "none" option which stored as an empty string. + /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. /// - public SpineAnimation(string startsWith = "", string dataField = "", bool includeNone = true) { + public SpineAnimation (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false) { this.startsWith = startsWith; this.dataField = dataField; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } } @@ -181,11 +195,12 @@ namespace Spine.Unity { /// If specified, a locally scoped field with the name supplied by in slotField will be used to limit the popup results to children of a named slot /// If specified, a locally scoped field with the name supplied by in skinField will be used to limit the popup results to entries of the named skin /// If true, the dropdown list will include a "none" option which stored as an empty string. + /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. /// - public SpineAttachment (bool currentSkinOnly = true, bool returnAttachmentPath = false, bool placeholdersOnly = false, string slotField = "", string dataField = "", string skinField = "", bool includeNone = true) { + public SpineAttachment (bool currentSkinOnly = true, bool returnAttachmentPath = false, bool placeholdersOnly = false, string slotField = "", string dataField = "", string skinField = "", bool includeNone = true, bool fallbackToTextField = false) { this.currentSkinOnly = currentSkinOnly; this.returnAttachmentPath = returnAttachmentPath; this.placeholdersOnly = placeholdersOnly; @@ -193,6 +208,7 @@ namespace Spine.Unity { this.dataField = dataField; this.skinField = skinField; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } public static SpineAttachment.Hierarchy GetHierarchy (string fullPath) { @@ -241,15 +257,17 @@ namespace Spine.Unity { /// Smart popup menu for Spine Bones /// /// Filters popup results to elements that begin with supplied string. - /// /// If true, the dropdown list will include a "none" option which stored as an empty string. + /// If true, the dropdown list will include a "none" option which stored as an empty string. + /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. /// - public SpineBone(string startsWith = "", string dataField = "", bool includeNone = true) { + public SpineBone (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false) { this.startsWith = startsWith; this.dataField = dataField; this.includeNone = includeNone; + this.fallbackToTextField = fallbackToTextField; } public static Spine.Bone GetBone(string boneName, SkeletonRenderer renderer) { @@ -265,7 +283,7 @@ namespace Spine.Unity { public class SpineAtlasRegion : PropertyAttribute { public string atlasAssetField; - public SpineAtlasRegion(string atlasAssetField = "") { + public SpineAtlasRegion (string atlasAssetField = "") { this.atlasAssetField = atlasAssetField; } }