// Only EditorGUI.DefaultPropertyField is replaced with EditorGUIHelper.DefaultPropertyFieldDelayed
        private static bool OnGUIDelayed(this PropertyHandler handler, Rect position, SerializedProperty property,
                                         GUIContent label, bool includeChildren)
        {
            Rect visibleArea = new Rect(0f, 0f, float.MaxValue, float.MaxValue);

            handler.TestInvalidateCache();

            float oldLabelWidth, oldFieldWidth;

            float propHeight = position.height;

            position.height = 0;
            if (handler.m_DecoratorDrawers != null && !handler.isCurrentlyNested)
            {
                foreach (DecoratorDrawer decorator in handler.m_DecoratorDrawers)
                {
                    position.height = decorator.GetHeight();

                    oldLabelWidth = EditorGUIUtility.labelWidth;
                    oldFieldWidth = EditorGUIUtility.fieldWidth;
                    decorator.OnGUI(position);
                    EditorGUIUtility.labelWidth = oldLabelWidth;
                    EditorGUIUtility.fieldWidth = oldFieldWidth;

                    position.y += position.height;
                    propHeight -= position.height;
                }
            }

            position.height = propHeight;
            if (handler.propertyDrawer != null)
            {
                // Remember widths
                oldLabelWidth = EditorGUIUtility.labelWidth;
                oldFieldWidth = EditorGUIUtility.fieldWidth;
                // Draw with custom drawer
                handler.propertyDrawer.OnGUISafe(position, property.Copy(), label ?? EditorGUIUtility.TempContent(property.localizedDisplayName));
                // Restore widths
                EditorGUIUtility.labelWidth = oldLabelWidth;
                EditorGUIUtility.fieldWidth = oldFieldWidth;

                return(false);
            }

            if (PropertyHandler.IsNonStringArray(property))
            {
                string key = ReorderableListWrapper.GetPropertyIdentifier(property);

                if (!PropertyHandler.s_reorderableLists.TryGetValue(key, out ReorderableListWrapper reorderableList))
                {
                    throw new IndexOutOfRangeException(
                              $"collection with name \"{property.name}\" doesn't have ReorderableList assigned to it.");
                }

                reorderableList.Property = property;
                reorderableList.Draw(position, visibleArea);
                return(false);
            }

            if (!includeChildren)
            {
                return(EditorGUIHelper.DefaultPropertyFieldDelayed(position, property, label));
            }

            // Remember state
            Vector2 oldIconSize = EditorGUIUtility.GetIconSize();
            bool    wasEnabled  = GUI.enabled;
            int     origIndent  = EditorGUI.indentLevel;

            int relIndent = origIndent - property.depth;

            SerializedProperty prop = property.Copy();

            position.height = EditorGUI.GetSinglePropertyHeight(prop, label);

            // First property with custom label
            EditorGUI.indentLevel = prop.depth + relIndent;
            bool childrenAreExpanded = EditorGUIHelper.DefaultPropertyFieldDelayed(position, prop, label) && EditorGUI.HasVisibleChildFields(prop);

            position.y += position.height + EditorGUI.kControlVerticalSpacing;

            // Loop through all child properties
            if (childrenAreExpanded)
            {
                SerializedProperty endProperty = prop.GetEndProperty();
                while (prop.NextVisible(childrenAreExpanded) && !SerializedProperty.EqualContents(prop, endProperty))
                {
                    var childHandler = ScriptAttributeUtility.GetHandler(prop);
                    EditorGUI.indentLevel = prop.depth + relIndent;
                    position.height       = childHandler.GetHeight(prop, null, false);

                    if (position.Overlaps(visibleArea))
                    {
                        EditorGUI.BeginChangeCheck();
                        childrenAreExpanded = childHandler.OnGUIDelayed(position, prop, null, false) && EditorGUI.HasVisibleChildFields(prop);
                        // Changing child properties (like array size) may invalidate the iterator,
                        // so stop now, or we may get errors.
                        if (EditorGUI.EndChangeCheck())
                        {
                            break;
                        }
                    }

                    position.y += position.height + EditorGUI.kControlVerticalSpacing;
                }
            }

            // Restore state
            GUI.enabled = wasEnabled;
            EditorGUIUtility.SetIconSize(oldIconSize);
            EditorGUI.indentLevel = origIndent;

            return(false);
        }