void ModifyOption(SerializedProperty property)
        {
            drawOptionThisFrame = SwitchContext(property);

            SerializedObject serializedObject = property.serializedObject;

            PowerPropertyAttribute[] powerProperties = fieldInfo.GetCustomAttributes(typeof(PowerPropertyAttribute), true) as PowerPropertyAttribute[];


            foreach (var p in powerProperties)
            {
                //Process for composited power property attribute
                if (p is CompositedPowerPropertyAttribute)
                {
                    CompositedPowerPropertyAttribute com        = p as CompositedPowerPropertyAttribute;
                    PowerPropertyAttribute[]         attributes = com.GetType().GetCustomAttributes(typeof(PowerPropertyAttribute), true) as PowerPropertyAttribute[];
                    foreach (var a in attributes)
                    {
                        if (a is CompositedPowerPropertyAttribute)
                        {
                            Debug.LogError("'CompositedPowerPropertyAttribute' should not be applied onto 'CompositedPowerPropertyAttribute'");
                            continue;
                        }
                        else
                        {
                            drawOptionThisFrame.ModifyOptionIncrement(a, serializedObject, property, fieldInfo);
                        }
                    }
                }
                else
                {
                    drawOptionThisFrame.ModifyOptionIncrement(p, serializedObject, property, fieldInfo);
                }
            }
        }
        //Must seal this method to keep sub-class share same code because we can never know which attribute drawer will be created
        //if many different type of attributes are assigned
        public sealed override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            drawOptionThisFrame = SwitchContext(property);

            //Keep draw option of last frame to draw background before reset option
            DrawBackground(position, drawOptionThisFrame, 1f);
            drawOptionThisFrame.ResetOption();

            //Modify power editing option by reading all power property attributes
            ModifyOption(property);

            //Special process of 'PowerWidget' field.
            if (fieldInfo.FieldType.IsSubclassOf(typeof(PowerWidget)))
            {
                PowerWidgetDrawingTool tool = PowerWidgetDrawingToolFactory.GetWidgetDrawingTool(property);
                if (tool != null)//Display widget when target widget drawing tool class has been found in Assembly
                {
                    drawOptionThisFrame.overrideDrawer = (r, p, l) => { tool.WidgetDrawer(r, p, fieldInfo, l); return(tool.GetWidgetHeight(p, fieldInfo)); };
                }
                else
                {
                    drawOptionThisFrame.overrideDrawer = (r, p, l) =>
                    {
                        return(PowerInspectorUtility.DrawErrorMessage(position, fieldInfo.FieldType.Name + "' has no drawing tool!", (float)(1.5 * EditorGUIUtility.singleLineHeight)));
                    };
                }
            }

            drawOptionThisFrame.heightAfterDraw = DrawPowerProperty(position, property, label, drawOptionThisFrame);
            drawOptionThisFrame.firstFrameDrawn = true;
        }
 public static void DrawBackground(Rect position, PowerEditingOption option, float padding = 2f)
 {
     if (!option.visible)
     {
         return;
     }
     position.height  = option.heightAfterDraw;
     position.x      -= 20;
     position.y      -= padding;
     position.width  += 40;
     position.height += 2 * padding;
     EditorGUI.DrawRect(position, option.backgroundColor);
 }
        public sealed override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            drawOptionThisFrame = SwitchContext(property);

            if (drawOptionThisFrame.firstFrameDrawn)
            {
                return(drawOptionThisFrame.heightAfterDraw);
            }
            else
            {//This method may possibly be called before drawing, so we need to predict layout height to avoid inspector open glitch
                ModifyOption(property);
                float baseValue = base.GetPropertyHeight(property, label);
                if (drawOptionThisFrame.visible && drawOptionThisFrame.heightAfterDraw == 0)
                {
                    return(baseValue);
                }
                return(drawOptionThisFrame.heightAfterDraw);
            }
        }
        /// <summary>
        /// Powerful property drawing method
        /// </summary>
        /// <param name="position"></param>
        /// <param name="property"></param>
        /// <param name="label"></param>
        /// <param name="option">Color Theme Option</param>
        /// <returns></returns>
        public static float DrawPowerProperty(Rect position, SerializedProperty property, GUIContent label, PowerEditingOption option)
        {
            if (!option.visible)
            {
                return(0f);
            }

            float retHeight = 0f;

            position.height = option.heightBeforeDraw;

            Color color = GUI.contentColor;

            GUI.contentColor = option.fontColor;

            EditorGUI.BeginDisabledGroup(option.readOnly);
            if (option.overrideDrawer == null)
            {
                EditorGUI.PropertyField(position, property, label, true);
                retHeight = EditorGUI.GetPropertyHeight(property);
            }
            else
            {
                retHeight = option.overrideDrawer(position, property, label);
                if (GUI.changed)
                {
                    property.serializedObject.SetIsDifferentCacheDirty();
                }
            }
            EditorGUI.EndDisabledGroup();

            GUI.contentColor = color;
            return(retHeight);
        }