static bool CompareSerializedProperty(SerializedProperty p1, SerializedProperty p2, GameObject root1, GameObject root2, ref Action apply, ref Action onGUI)
        {
            if (p1.propertyType != p2.propertyType)
            {
                Debug.LogError("SerializedPropertys have different types!");
            }

            string SIMPLE_FORMAT = string.Format("{0}.{1}: {2}", p1.serializedObject.targetObject.GetType().Name, p1.propertyPath, "{1} -> {0}");

            switch (p1.propertyType)
            {
            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Integer:
            case SerializedPropertyType.LayerMask:
            case SerializedPropertyType.Character:
            case SerializedPropertyType.ArraySize:
                apply = () =>
                {
                    p2.intValue = p1.intValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.intValue, p2.intValue));
                };
                return(p2.intValue == p1.intValue);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Boolean:
                apply = () =>
                {
                    p2.boolValue = p1.boolValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.boolValue, p2.boolValue));
                };
                return(p2.boolValue == p1.boolValue);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Float:
                apply = () =>
                {
                    p2.floatValue = p1.floatValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.floatValue, p2.floatValue));
                };
                return(p2.floatValue == p1.floatValue);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.String:
                apply = () =>
                {
                    p2.stringValue = p1.stringValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.stringValue, p2.stringValue));
                };
                return(p2.stringValue == p1.stringValue);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Color:
                apply = () =>
                {
                    p2.colorValue = p1.colorValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.colorValue.ToString255(), p2.colorValue.ToString255()));
                    EditorGUILayout.ColorField(p2.colorValue, GUILayout.Width(45));
                    EditorGUILayout.LabelField(" -> ", GUILayout.Width(35));
                    EditorGUILayout.ColorField(p1.colorValue, GUILayout.Width(45));
                };
                return(p2.colorValue == p1.colorValue);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Enum:
                apply = () =>
                {
                    p2.enumValueIndex = p1.enumValueIndex;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.enumNames[p1.enumValueIndex], p2.enumNames[p2.enumValueIndex]));
                };
                return(p2.enumValueIndex == p1.enumValueIndex);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Vector2:
                apply = () =>
                {
                    p2.vector2Value = p1.vector2Value;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.vector2Value, p2.vector2Value));
                };
                return(p2.vector2Value == p1.vector2Value);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Vector3:
                apply = () =>
                {
                    p2.vector3Value = p1.vector3Value;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.vector3Value, p2.vector3Value));
                };
                return(p2.vector3Value == p1.vector3Value);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Quaternion:
                apply = () =>
                {
                    p2.quaternionValue = p1.quaternionValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.quaternionValue.eulerAngles, p2.quaternionValue.eulerAngles));
                };
                return(p2.quaternionValue == p1.quaternionValue);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Rect:
                apply = () =>
                {
                    p2.rectValue = p1.rectValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.rectValue, p2.rectValue));
                };
                return(p2.rectValue == p1.rectValue);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.AnimationCurve:

                apply = () =>
                {
                    p2.animationCurveValue = p1.animationCurveValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(p2.serializedObject.targetObject.GetType().Name + "." + p2.propertyPath + ": animation curve changed");
                };
                return(EditorUtils.IsAnimationCurvesEqual(p2.animationCurveValue, p1.animationCurveValue));

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Bounds:
                apply = () =>
                {
                    p2.boundsValue = p1.boundsValue;
                };
                onGUI = () =>
                {
                    EditorGUILayout.LabelField(string.Format(SIMPLE_FORMAT, p1.boundsValue, p2.boundsValue));
                };
                return(p2.boundsValue == p1.boundsValue);

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.ObjectReference:
                return(CompareSerializedPropertyObjectReference(p1, p2, root1, root2, ref apply, ref onGUI));

            /////////////////////////////////////////////////////////
            case SerializedPropertyType.Generic:
                // not implemented
                return(true);

            /////////////////////////////////////////////////////////
            /////////////////////////////////////////////////////////
            default:
                // not implemented
                //Debug.LogError("Implement: " + p1.propertyType + " " + p1.propertyPath);
                return(true);
            }
        }