private void SnappingChanged(string eventMessage)
        {
            Curve.FireBeforeChange(eventMessage);

            serializedObject.ApplyModifiedProperties();

            Curve.ApplySnapping();

            Curve.FireChange(BGCurveChangedArgs.GetInstance(Curve, BGCurveChangedArgs.ChangeTypeEnum.Snap, eventMessage));
        }
        public override void OnApply()
        {
            var curve    = Editor.Curve;
            var settings = Settings;

            // ==============================================    Closed
            if (curve.Closed != closedProperty.boolValue)
            {
                Curve.FireBeforeChange(BGCurve.EventClosed);
                serializedObject.ApplyModifiedProperties();
                Curve.FireChange(BGCurveChangedArgs.GetInstance(Curve, BGCurveChangedArgs.ChangeTypeEnum.Points, BGCurve.EventClosed));
            }

            if ((int)curve.ForceChangedEventMode != forceChangedEventModeProperty.enumValueIndex)
            {
                Curve.FireBeforeChange(BGCurve.EventForceUpdate);
                serializedObject.ApplyModifiedProperties();
                Curve.FireChange(BGCurveChangedArgs.GetInstance(Curve, BGCurveChangedArgs.ChangeTypeEnum.Curve, BGCurve.EventForceUpdate));
            }

            // ==============================================    Points store mode
            if ((int)Curve.PointsMode != pointsModeProperty.enumValueIndex)
            {
                var newPointsMode = (BGCurve.PointsModeEnum)pointsModeProperty.enumValueIndex;

                //ask for confirmation in case changes may affect something else
                if ((Curve.PointsMode == BGCurve.PointsModeEnum.Components) && !BGEditorUtility.Confirm("Convert Points",
                                                                                                        "Are you sure you want to convert points? All existing references to these points will be lost.", "Convert"))
                {
                    return;
                }

                if ((Curve.PointsMode == BGCurve.PointsModeEnum.GameObjectsNoTransform && newPointsMode != BGCurve.PointsModeEnum.GameObjectsTransform ||
                     Curve.PointsMode == BGCurve.PointsModeEnum.GameObjectsTransform && newPointsMode != BGCurve.PointsModeEnum.GameObjectsNoTransform) &&
                    !BGEditorUtility.Confirm("Convert Points", "Are you sure you want to convert points? All existing GameObjects for points will be deleted.", "Convert"))
                {
                    return;
                }

                editorSelection.Clear();

                //invoke convert
                BGPrivateField.Invoke(Curve, BGCurve.MethodConvertPoints, newPointsMode,
                                      BGCurveEditor.GetPointProvider(newPointsMode, Curve),
                                      BGCurveEditor.GetPointDestroyer(Curve.PointsMode, Curve));

                //this call is not required
                //                serializedObject.ApplyModifiedProperties();
            }

            // ==============================================    2D mode
            if ((int)curve.Mode2D != mode2DProperty.enumValueIndex)
            {
                Curve.FireBeforeChange(BGCurve.Event2D);
                serializedObject.ApplyModifiedProperties();

                var oldEventMode = Curve.EventMode;
                Curve.EventMode = BGCurve.EventModeEnum.NoEvents;

                //force points recalc
                Curve.Apply2D(Curve.Mode2D);

                if (BGEditorUtility.Confirm("Editor handles change", "Do you want to adjust configurable Editor handles (in Scene View) to chosen mode? This affects only current curve.", "Yes"))
                {
                    if (Curve.Mode2D != BGCurve.Mode2DEnum.Off)
                    {
                        Apply2D(settings.HandlesSettings);
                        Apply2D(settings.ControlHandlesSettings);
                    }
                    else
                    {
                        Apply3D(settings.HandlesSettings);
                        Apply3D(settings.ControlHandlesSettings);
                    }
                }

                Curve.EventMode = oldEventMode;

                Curve.FireChange(BGCurveChangedArgs.GetInstance(Curve, BGCurveChangedArgs.ChangeTypeEnum.Points, BGCurve.Event2D));
            }

            // ==============================================    Snapping
            if ((int)curve.SnapType != snapTypeProperty.enumValueIndex)
            {
                SnappingChanged(BGCurve.EventSnapType);
            }

            if ((int)curve.SnapAxis != snapAxisProperty.enumValueIndex)
            {
                SnappingChanged(BGCurve.EventSnapAxis);
            }

            if (Math.Abs((int)curve.SnapDistance - snapDistanceProperty.floatValue) > BGCurve.Epsilon)
            {
                SnappingChanged(BGCurve.EventSnapDistance);
            }

            if ((int)curve.SnapTriggerInteraction != snapTriggerInteractionProperty.enumValueIndex)
            {
                SnappingChanged(BGCurve.EventSnapTrigger);
            }

            if (curve.SnapToBackFaces != snapToBackFacesProperty.boolValue)
            {
                SnappingChanged(BGCurve.EventSnapBackfaces);
            }

            if (curve.SnapMonitoring != snapMonitoringProperty.boolValue)
            {
                SnappingChanged(BGCurve.EventSnapMonitoring);
            }

            // ==============================================    Event mode
            if ((int)curve.EventMode != eventModeProperty.enumValueIndex)
            {
                serializedObject.ApplyModifiedProperties();
            }

            // ==============================================    Control Type
            if ((int)settings.ControlType != controlTypeProperty.enumValueIndex)
            {
                serializedObject.ApplyModifiedProperties();
            }
        }
        private void InspectorTopSection()
        {
            if (Curve.PointsCount == 0)
            {
                EditorGUILayout.HelpBox(
                    "1) Ctrl + LeftClick in scene view to add a point and snap it to  "
                    + "\r\n    a) 3D mode: mesh with collider"
                    + "\r\n    b) 2D mode: curve's 2D plane."
                    + "\r\n"
                    + "\r\n2) Ctrl + Shift + LeftClick in Scene View to add a point unconditionally at some distance, specified in the settings."
                    + "\r\n"
                    + "\r\n3) Hold control over existing point or selection to access Scene View menu"
                    + "\r\n"
                    + "\r\n4) Hold shift + drag to use rectangular selection in Scene View"
                    + "\r\n"
                    + "\r\n5) Ctrl + LeftClick over existing spline to insert a point"
                    , MessageType.Info);
            }


            try
            {
                // Curve's block
                BGEditorUtility.VerticalBox(() =>
                {
                    //closed
                    EditorGUILayout.PropertyField(closedProperty);


                    //point's store mode
                    BGEditorUtility.Horizontal(() =>
                    {
                        EditorGUILayout.PropertyField(pointsModeProperty);

                        BGEditorUtility.DisableGui(() =>
                        {
                            BGEditorUtility.Assign(ref syncContent, () => new GUIContent("Sync", "Sort points Game Objects and update names"));

                            if (!GUILayout.Button(syncContent))
                            {
                                return;
                            }

                            BGPrivateField.Invoke(Curve, BGCurve.MethodSetPointsNames);
                        }, !BGCurve.IsGoMode(Curve.PointsMode));
                    });


                    //2D mode
                    BGEditorUtility.Horizontal(() =>
                    {
                        EditorGUILayout.PropertyField(mode2DProperty);
                        BGEditorUtility.DisableGui(() =>
                        {
                            if (!GUILayout.Button("Apply", GUI.skin.button, GUILayout.Width(80)))
                            {
                                return;
                            }

                            Curve.FireBeforeChange(BGCurve.Event2D);
                            Curve.Apply2D(Curve.Mode2D);
                            Curve.FireChange(BGCurveChangedArgs.GetInstance(Curve, BGCurveChangedArgs.ChangeTypeEnum.Points, BGCurve.Event2D));
                        }, mode2DProperty.enumValueIndex == 0);
                    });

                    //snapping
                    BGEditorUtility.VerticalBox(() =>
                    {
                        BGEditorUtility.Horizontal(() =>
                        {
                            EditorGUILayout.PropertyField(snapTypeProperty);

                            BGEditorUtility.DisableGui(() =>
                            {
                                if (!GUILayout.Button("Apply", GUI.skin.button, GUILayout.Width(80)))
                                {
                                    return;
                                }

                                Curve.FireBeforeChange(BGCurve.EventSnapType);
                                Curve.ApplySnapping();
                                Curve.FireChange(BGCurveChangedArgs.GetInstance(Curve, BGCurveChangedArgs.ChangeTypeEnum.Snap, BGCurve.EventSnapType));
                            }, snapTypeProperty.enumValueIndex == 0);
                        });

                        if (snapTypeProperty.enumValueIndex == 0)
                        {
                            return;
                        }

                        EditorGUILayout.PropertyField(snapAxisProperty);
                        EditorGUILayout.PropertyField(snapDistanceProperty);
                        EditorGUILayout.PropertyField(snapTriggerInteractionProperty);
                        EditorGUILayout.PropertyField(snapToBackFacesProperty);

                        BGEditorUtility.LayerMaskField("Snap Layer Mask", Curve.SnapLayerMask, i =>
                        {
                            Curve.FireBeforeChange(BGCurve.EventSnapTrigger);
                            Curve.SnapLayerMask = i;
                            Curve.ApplySnapping();
                            Curve.FireChange(BGCurveChangedArgs.GetInstance(Curve, BGCurveChangedArgs.ChangeTypeEnum.Snap, BGCurve.EventSnapTrigger));
                        });

                        EditorGUILayout.PropertyField(snapMonitoringProperty);
                        if (Curve.SnapMonitoring && Curve.SnapType != BGCurve.SnapTypeEnum.Off)
                        {
                            EditorGUILayout.HelpBox("You enabled snap monitoring, which monitor environment every frame and snap to it. Be aware, this is a very costly function", MessageType.Warning);
                        }
                    });

                    //event mode
                    EditorGUILayout.PropertyField(eventModeProperty);

                    //force update
                    EditorGUILayout.PropertyField(forceChangedEventModeProperty);

                    //convert control type
                    BGEditorUtility.Horizontal(() =>
                    {
                        EditorGUILayout.PropertyField(controlTypeProperty);

                        if (!BGEditorUtility.ButtonWithIcon(BGBinaryResources.BGConvertAll123, "Convert control types for all existing points ", 44))
                        {
                            return;
                        }

                        var settings = Settings;

                        foreach (var point in Curve.Points.Where(point => point.ControlType != settings.ControlType))
                        {
                            point.ControlType = settings.ControlType;
                        }
                    });
                });
            }
            catch (BGEditorUtility.ExitException)
            {
                GUIUtility.ExitGUI();
            }
        }