Search Unity

Custom Attribute : an Array Size Limiter

Discussion in 'Editor & General Support' started by DaCookie, Jan 13, 2016.

  1. DaCookie

    DaCookie

    Joined:
    Nov 4, 2014
    Posts:
    44
    Hi everybody.

    I'm trying to make a Custom Attribute to set a max size for array properties. But I have some difficulties with the SerializedProperty class' accessors...

    Here's my code :

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. #if UNITY_EDITOR
    4. using UnityEditor;
    5. #endif
    6.  
    7. public class ArrayLimitAttribute : PropertyAttribute
    8. {
    9.  
    10.     #region Members
    11.  
    12.         private    uint    m_Size    = 0;
    13.  
    14.     #endregion
    15.  
    16.  
    17.     #region Initialisation / Destruction
    18.  
    19.         private ArrayLimitAttribute()
    20.         {
    21.  
    22.         }
    23.  
    24.         public ArrayLimitAttribute(int _MaxArraySize)
    25.         {
    26.             m_Size = (_MaxArraySize < 0) ? 0 : (uint)_MaxArraySize;
    27.         }
    28.  
    29.         public ArrayLimitAttribute(uint _MaxArraySize)
    30.         {
    31.             m_Size = _MaxArraySize;
    32.         }
    33.  
    34.     #endregion
    35.  
    36.  
    37.     #region Accessors
    38.  
    39.         public int MaxSize
    40.         {
    41.             get { return (int)m_Size; }
    42.         }
    43.  
    44.     #endregion
    45.  
    46. }
    47.  
    48. #if UNITY_EDITOR
    49.  
    50. [CustomPropertyDrawer(typeof(ArrayLimitAttribute))]
    51. public class ArrayLimitDrawer : PropertyDrawer
    52. {
    53.  
    54.     #region UI
    55.  
    56.         public override void OnGUI(Rect _Position, SerializedProperty _Property, GUIContent _Label)
    57.         {
    58.             ArrayLimitAttribute limit    = attribute as ArrayLimitAttribute;
    59.             int                    maxSize = limit.MaxSize;
    60.  
    61.             if(_Property.isArray)
    62.             {
    63.                 if(_Property.arraySize > maxSize)
    64.                 {
    65.                     _Property.arraySize = maxSize;
    66.                 }
    67.             }
    68.  
    69.             else
    70.             {
    71.                 Debug.Log("The ArrayLimitAttribute is useless for properties that are not an array.");
    72.             }
    73.  
    74.             EditorGUI.PropertyField(_Position, _Property);
    75.         }
    76.  
    77.     #endregion
    78.  
    79. }
    80.  
    81. #endif
    When I use this attribute for an int array, _Property.isArray returns false. For a string array, isArray returns true. Why ? Note that when isArray is true, _Property.arraySize value is always 0.

    Results are the same if you use Lists.

    So, two questions : why the values are not the expected ones ? And How I can do my Array Size Limiter with fake values from SerializedProperty ?

    Thanks for your answers.
     
  2. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    The property drawer is executed once per item in the array, and not for the entire array as a single property..
    You can verify that by debugging and checking what is the SerializedProperty you're currently drawing.
     
  3. DaCookie

    DaCookie

    Joined:
    Nov 4, 2014
    Posts:
    44
    Ok you're right, it's clearly that. So, does it means there's no way to do what I want on the array ?

    Of course, I can do it by creating a CustomEditor for my class... But I prefer create one attribute, to avoid create tons of Custom Editor for every class that could use it !
     
  4. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    I don't think you could do that with the current support from Property drawers...

    You *could* get away with some hacked solution by defining a new wrapper type around your array. This will be a new class (or struct) that will internally hold your actual array. You could decorate this type with your attribute (getting the 1 to 1 mapping between the attribute and the property it's used on), internally you would check whether the property satisfies your condition (e.g: whether the internal array is sized within limits).

    EDIT: i just googled this and found this solution (which is pretty much what i just wrote, but takes it one step further using implicit conversions: http://answers.unity3d.com/questions/605875/custompropertydrawer-for-array-types-in-43.html)
     
    Eldoir likes this.
  5. DaCookie

    DaCookie

    Joined:
    Nov 4, 2014
    Posts:
    44
    Ok. I found this one, but the post was on version 4.3 so I hoped that's possible now. :/

    Thanks for your answers ^^