using UnityEngine; using UnityEditor; using System.Collections; using System.Linq; namespace GitMerge { /// /// The MergeAction allowing to merge the value of a single property of a Component. /// public class MergeActionChangeValues : MergeAction { protected SerializedProperty ourProperty; protected SerializedProperty theirProperty; protected object ourInitialValue; protected object theirInitialValue; protected readonly string ourString; protected readonly string theirString; protected readonly string fieldname; protected Object ourObject; public MergeActionChangeValues(GameObject ours, Object ourObject, SerializedProperty ourProperty, SerializedProperty theirProperty) : base(ours, null) { this.ourObject = ourObject; this.ourProperty = ourProperty; this.theirProperty = theirProperty; fieldname = ourObject.GetPlainType() + "." + ourProperty.GetPlainName(); ourInitialValue = ourProperty.GetValue(); theirInitialValue = theirProperty.GetValue(); ourString = SerializedValueString(ourProperty); theirString = SerializedValueString(theirProperty); } protected override void ApplyOurs() { ourProperty.SetValue(ourInitialValue); ourProperty.serializedObject.ApplyModifiedProperties(); } protected override void ApplyTheirs() { var value = theirInitialValue; //If we're about references here, get "our" version of the object. if(ourProperty.propertyType == SerializedPropertyType.ObjectReference) { var id = ObjectIDFinder.GetIdentifierFor(theirInitialValue as Object); var obj = ObjectDictionaries.GetOurObject(id); //If we didn't have our own version of the object before, it must be new if(!obj) { //Get our copy of the new object if it exists obj = ObjectDictionaries.GetOurInstanceOfCopy(value as Object); } value = obj; } ourProperty.SetValue(value); ourProperty.serializedObject.ApplyModifiedProperties(); } public override void OnGUI() { GUILayout.BeginVertical(); GUILayout.Label(fieldname + ": " + ourProperty.propertyType); GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); GUILayout.Label(ourString, GUILayout.Width(100)); DisplayArray(ourInitialValue); GUILayout.EndVertical(); if(MergeButton(">>>", usingOurs)) { UseOurs(); } var c = GUI.backgroundColor; GUI.backgroundColor = Color.white; //GUILayout.Label(ourProperty.propertyType + "/" + ourProperty.type + ": " + ourProperty.GetValue()); PropertyField(ourProperty); GUI.backgroundColor = c; if(MergeButton("<<<", usingTheirs)) { UseTheirs(); } GUILayout.BeginVertical(); GUILayout.Label(theirString, GUILayout.Width(100)); DisplayArray(theirInitialValue); GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); } private void DisplayArray(object value) { if(ourProperty.IsRealArray() && ourProperty.isExpanded) { var values = (object[])value; for(int i = 0; i < values.Length; ++i) { GUILayout.Label(ValueString(values[i]), GUILayout.Width(100)); } } } /// /// Displays the property field in the center of the window. /// This method distinguishes between certain properties. /// The GameObject tag, for example, shouldn't be displayed with a regular string field. /// /// The SerializedProerty to display /// The width of the whole thing in the ui private void PropertyField(SerializedProperty p, float width = 170) { if(p.IsRealArray()) { DisplayArrayProperty(p, width); } else { var oldValue = p.GetValue(); if(fieldname == "GameObject.TagString") { var oldTag = oldValue as string; var newTag = EditorGUILayout.TagField("", oldTag, GUILayout.Width(width)); if(newTag != oldTag) { p.SetValue(newTag); } } else if(fieldname == "GameObject.StaticEditorFlags") { DisplayStaticFlagChooser(p, width); } else { EditorGUILayout.PropertyField(p, new GUIContent(""), GUILayout.Width(width)); } if(!object.Equals(p.GetValue(), oldValue)) { p.serializedObject.ApplyModifiedProperties(); UsedNew(); } } } private void DisplayArrayProperty(SerializedProperty p, float width) { GUILayout.BeginVertical(); GUILayout.BeginHorizontal(GUILayout.Width(170)); EditorGUILayout.PropertyField(p, new GUIContent("Array"), GUILayout.Width(80)); if(p.isExpanded) { var copy = p.Copy(); var size = copy.arraySize; copy.Next(true); copy.Next(true); PropertyField(copy, 70); GUILayout.EndHorizontal(); for(int i = 0; i < size; ++i) { copy.Next(false); PropertyField(copy); } } else { GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } /// /// Displays Toggles that let the user set the static flags of the object. /// /// The StaticEditorFlags SerializedProperty to display /// The width of the whole thing in the ui private void DisplayStaticFlagChooser(SerializedProperty p, float width) { var flags = (StaticEditorFlags)p.intValue; GUILayout.BeginVertical(GUILayout.Width(width)); p.isExpanded = EditorGUILayout.Foldout(p.isExpanded, SerializedValueString(p)); var allOn = true; if(p.isExpanded) { foreach(var flag in System.Enum.GetValues(typeof(StaticEditorFlags)).Cast()) { var wasOn = (flags & flag) != 0; var on = EditorGUILayout.Toggle(flag + "", wasOn); if(wasOn != on) { flags = flags ^ flag; } if(!on) { allOn = false; } } } if(allOn) { flags = (StaticEditorFlags)(-1); } p.intValue = (int)flags; GUILayout.EndVertical(); } private string SerializedValueString(SerializedProperty p) { if(fieldname == "GameObject.StaticEditorFlags") { switch(p.intValue) { case 0: return "Not static"; case -1: return "Static"; default: return "Mixed static"; } } else if(p.IsRealArray()) { return "Array[" + p.arraySize + "]"; } return ValueString(p.GetValue()); } private static string ValueString(object o) { if(o == null) { return "[none]"; } return o.ToString(); } private static bool MergeButton(string text, bool green) { if(green) { GUI.color = Color.green; } bool result = GUILayout.Button(text, GUILayout.ExpandWidth(false)); GUI.color = Color.white; return result; } } }