namespace GitMerge
{
using UnityEngine;
using UnityEditor;
using System.Linq;
///
/// 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;
public MergeActionChangeValues(GameObject ours, SerializedProperty ourProperty, SerializedProperty theirProperty)
: base(ours, null)
{
this.ourProperty = ourProperty;
this.theirProperty = theirProperty;
fieldname = ourProperty.serializedObject.targetObject.GetPlainType() + "." + ourProperty.GetPlainName();
ourInitialValue = ourProperty.GetValue();
theirInitialValue = theirProperty.GetValue();
ourString = SerializedValueString(ourProperty);
theirString = SerializedValueString(theirProperty);
}
protected override void ApplyOurs()
{
ourProperty.serializedObject.ApplyModifiedProperties();
}
protected override void ApplyTheirs()
{
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))
{
ourProperty.SetValue(ourInitialValue);
UseOurs();
merged = true;
}
var c = GUI.backgroundColor;
GUI.backgroundColor = Color.white;
//GUILayout.Label(ourProperty.propertyType + "/" + ourProperty.type + ": " + ourProperty.GetValue());
PropertyField(ourProperty);
GUI.backgroundColor = c;
if (MergeButton("<<<", usingTheirs))
{
var value = theirInitialValue;
//If we're about references here, get "our" version of the object.
if (ourProperty.propertyType == SerializedPropertyType.ObjectReference)
{
var id = ObjectID.GetFor(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);
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;
}
}
}