Inheritance: UnityEditor.Editor
        override public void OnInspectorGUI()
        {
            if (needsReset)
            {
                component.Initialize();
                component.LateUpdate();
                needsReset = false;
                SceneView.RepaintAll();
            }
            serializedObject.Update();

            // FindRenderer()
            if (skeletonRenderer.objectReferenceValue == null)
            {
                SkeletonRenderer parentRenderer = BoneFollowerInspector.GetInParent <SkeletonRenderer>(component.transform);

                if (parentRenderer != null)
                {
                    Debug.Log("Inspector automatically assigned BoneFollower.SkeletonRenderer");
                    skeletonRenderer.objectReferenceValue = parentRenderer;
                }
            }

            EditorGUILayout.PropertyField(skeletonRenderer);

            if (component.valid)
            {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(boneName);
                if (EditorGUI.EndChangeCheck())
                {
                    serializedObject.ApplyModifiedProperties();
                    needsReset = true;
                    serializedObject.Update();
                }

                EditorGUILayout.PropertyField(followBoneRotation);
                EditorGUILayout.PropertyField(followZPosition);
            }
            else
            {
                GUILayout.Label("INVALID");
            }

            if (serializedObject.ApplyModifiedProperties() ||
                (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed")
                )
            {
                component.Initialize();
            }
        }
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(mode);
            if (EditorGUI.EndChangeCheck())
            {
                containsOverrides = mode.enumValueIndex == 1;
                containsFollows   = mode.enumValueIndex == 0;
            }

            using (new EditorGUI.DisabledGroupScope(multiObject)) {
                string str = boneName.stringValue;
                if (str == "")
                {
                    str = "<None>";
                }
                if (multiObject)
                {
                    str = "<Multiple>";
                }

                using (new GUILayout.HorizontalScope()) {
                    EditorGUILayout.PrefixLabel("Bone");
                    if (GUILayout.Button(str, EditorStyles.popup))
                    {
                        BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.skeletonRenderer.skeleton.Bones, "<None>", TargetBoneSelected);
                    }
                }
            }

            EditorGUILayout.PropertyField(zPosition);
            EditorGUILayout.PropertyField(position);
            EditorGUILayout.PropertyField(rotation);
            EditorGUILayout.PropertyField(scale);

            using (new EditorGUI.DisabledGroupScope(containsFollows)) {
                EditorGUILayout.PropertyField(overrideAlpha);
                EditorGUILayout.PropertyField(parentReference);
            }

            EditorGUILayout.Space();

            using (new GUILayout.HorizontalScope()) {
                EditorGUILayout.Space();
                using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || utilityBone.bone.Children.Count == 0)) {
                    if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Child Bone", Icons.bone), GUILayout.MinWidth(120), GUILayout.Height(24)))
                    {
                        BoneSelectorContextMenu("", utilityBone.bone.Children, "<Recursively>", SpawnChildBoneSelected);
                    }
                }
                using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || containsOverrides)) {
                    if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Override", Icons.poseBones), GUILayout.MinWidth(120), GUILayout.Height(24)))
                    {
                        SpawnOverride();
                    }
                }
                EditorGUILayout.Space();
            }
            EditorGUILayout.Space();
            using (new GUILayout.HorizontalScope()) {
                EditorGUILayout.Space();
                using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || !canCreateHingeChain)) {
                    if (GUILayout.Button(SpineInspectorUtility.TempContent("Create 3D Hinge Chain", Icons.hingeChain), GUILayout.MinWidth(120), GUILayout.Height(24)))
                    {
                        CreateHingeChain();
                    }
                    if (GUILayout.Button(SpineInspectorUtility.TempContent("Create 2D Hinge Chain", Icons.hingeChain), GUILayout.MinWidth(120), GUILayout.Height(24)))
                    {
                        CreateHingeChain2D();
                    }
                }
                EditorGUILayout.Space();
            }

            using (new EditorGUI.DisabledGroupScope(multiObject || boundingBoxTable.Count == 0)) {
                EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bounding Boxes", Icons.boundingBox), EditorStyles.boldLabel);

                foreach (var entry in boundingBoxTable)
                {
                    Slot slot          = entry.Key;
                    var  boundingBoxes = entry.Value;

                    EditorGUI.indentLevel++;
                    EditorGUILayout.LabelField(slot.Data.Name);
                    EditorGUI.indentLevel++;
                    {
                        foreach (var box in boundingBoxes)
                        {
                            using (new GUILayout.HorizontalScope()) {
                                GUILayout.Space(30);
                                string buttonLabel = box.IsWeighted() ? box.Name + " (!)" : box.Name;
                                if (GUILayout.Button(buttonLabel, GUILayout.Width(200)))
                                {
                                    utilityBone.bone.Skeleton.UpdateWorldTransform();
                                    var bbTransform = utilityBone.transform.Find("[BoundingBox]" + box.Name);                                     // Use FindChild in older versions of Unity.
                                    if (bbTransform != null)
                                    {
                                        var originalCollider = bbTransform.GetComponent <PolygonCollider2D>();
                                        if (originalCollider != null)
                                        {
                                            SkeletonUtility.SetColliderPointsLocal(originalCollider, slot, box);
                                        }
                                        else
                                        {
                                            SkeletonUtility.AddBoundingBoxAsComponent(box, slot, bbTransform.gameObject);
                                        }
                                    }
                                    else
                                    {
                                        var newPolygonCollider = SkeletonUtility.AddBoundingBoxGameObject(null, box, slot, utilityBone.transform);
                                        bbTransform = newPolygonCollider.transform;
                                    }
                                    EditorGUIUtility.PingObject(bbTransform);
                                }
                            }
                        }
                    }
                    EditorGUI.indentLevel--;
                    EditorGUI.indentLevel--;
                }
            }

            BoneFollowerInspector.RecommendRigidbodyButton(utilityBone);

            serializedObject.ApplyModifiedProperties();
        }
        override public void OnInspectorGUI()
        {
            if (needsReset)
            {
                targetBoneFollower.Initialize();
                targetBoneFollower.LateUpdate();
                needsReset = false;
                SceneView.RepaintAll();
            }
            serializedObject.Update();

            // Find Renderer
            if (skeletonRenderer.objectReferenceValue == null)
            {
                SkeletonRenderer parentRenderer = BoneFollowerInspector.GetInParent <SkeletonRenderer>(targetBoneFollower.transform);
                if (parentRenderer != null)
                {
                    Debug.Log("Inspector automatically assigned BoneFollower.SkeletonRenderer");
                    skeletonRenderer.objectReferenceValue = parentRenderer;
                }
            }

            EditorGUILayout.PropertyField(skeletonRenderer);

            if (targetBoneFollower.valid)
            {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(boneName);
                if (EditorGUI.EndChangeCheck())
                {
                    serializedObject.ApplyModifiedProperties();
                    needsReset = true;
                    serializedObject.Update();
                }
                EditorGUILayout.PropertyField(followBoneRotation);
                EditorGUILayout.PropertyField(followZPosition);
            }
            else
            {
                var boneFollowerSkeletonRenderer = targetBoneFollower.skeletonRenderer;
                if (boneFollowerSkeletonRenderer == null)
                {
                    EditorGUILayout.HelpBox("SkeletonRenderer is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonAnimator).", MessageType.Warning);
                }
                else
                {
                    boneFollowerSkeletonRenderer.Initialize(false);

                    if (boneFollowerSkeletonRenderer.skeletonDataAsset == null)
                    {
                        EditorGUILayout.HelpBox("Assigned SkeletonRenderer does not have SkeletonData assigned to it.", MessageType.Warning);
                    }

                    if (!boneFollowerSkeletonRenderer.valid)
                    {
                        EditorGUILayout.HelpBox("Assigned SkeletonRenderer is invalid. Check target SkeletonRenderer, its SkeletonDataAsset or the console for other errors.", MessageType.Warning);
                    }
                }
            }

            var  current = UnityEngine.Event.current;
            bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed");

            if (serializedObject.ApplyModifiedProperties() || wasUndo)
            {
                targetBoneFollower.Initialize();
            }
        }
        override public void OnInspectorGUI()
        {
            if (serializedObject.isEditingMultipleObjects)
            {
                if (needsReset)
                {
                    needsReset = false;
                    foreach (var o in targets)
                    {
                        var bf = (BoneFollower)o;
                        bf.Initialize();
                        bf.LateUpdate();
                    }
                    SceneView.RepaintAll();
                }

                EditorGUI.BeginChangeCheck();
                DrawDefaultInspector();
                needsReset |= EditorGUI.EndChangeCheck();
                return;
            }

            if (needsReset && Event.current.type == EventType.Layout)
            {
                targetBoneFollower.Initialize();
                targetBoneFollower.LateUpdate();
                needsReset = false;
                SceneView.RepaintAll();
            }
            serializedObject.Update();

            // Find Renderer
            if (skeletonRenderer.objectReferenceValue == null)
            {
                SkeletonRenderer parentRenderer = targetBoneFollower.GetComponentInParent <SkeletonRenderer>();
                if (parentRenderer != null && parentRenderer.gameObject != targetBoneFollower.gameObject)
                {
                    skeletonRenderer.objectReferenceValue = parentRenderer;
                    Debug.Log("Inspector automatically assigned BoneFollower.SkeletonRenderer");
                }
            }

            EditorGUILayout.PropertyField(skeletonRenderer);
            var skeletonRendererReference = skeletonRenderer.objectReferenceValue as SkeletonRenderer;

            if (skeletonRendererReference != null)
            {
                if (skeletonRendererReference.gameObject == targetBoneFollower.gameObject)
                {
                    skeletonRenderer.objectReferenceValue = null;
                    EditorUtility.DisplayDialog("Invalid assignment.", "BoneFollower can only follow a skeleton on a separate GameObject.\n\nCreate a new GameObject for your BoneFollower, or choose a SkeletonRenderer from a different GameObject.", "Ok");
                }
            }

            if (!targetBoneFollower.valid)
            {
                needsReset = true;
            }

            if (targetBoneFollower.valid)
            {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(boneName);
                needsReset |= EditorGUI.EndChangeCheck();

                EditorGUILayout.PropertyField(followBoneRotation);
                EditorGUILayout.PropertyField(followZPosition);
                EditorGUILayout.PropertyField(followLocalScale);
                EditorGUILayout.PropertyField(followSkeletonFlip);

                BoneFollowerInspector.RecommendRigidbodyButton(targetBoneFollower);
            }
            else
            {
                var boneFollowerSkeletonRenderer = targetBoneFollower.skeletonRenderer;
                if (boneFollowerSkeletonRenderer == null)
                {
                    EditorGUILayout.HelpBox("SkeletonRenderer is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonMecanim).", MessageType.Warning);
                }
                else
                {
                    boneFollowerSkeletonRenderer.Initialize(false);

                    if (boneFollowerSkeletonRenderer.skeletonDataAsset == null)
                    {
                        EditorGUILayout.HelpBox("Assigned SkeletonRenderer does not have SkeletonData assigned to it.", MessageType.Warning);
                    }

                    if (!boneFollowerSkeletonRenderer.valid)
                    {
                        EditorGUILayout.HelpBox("Assigned SkeletonRenderer is invalid. Check target SkeletonRenderer, its SkeletonDataAsset or the console for other errors.", MessageType.Warning);
                    }
                }
            }

            var  current = Event.current;
            bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed");

            if (wasUndo)
            {
                targetBoneFollower.Initialize();
            }

            serializedObject.ApplyModifiedProperties();
        }