diff --git a/Editor/Layouts/RefTo.uxml b/Editor/Layouts/RefTo.uxml index 1ef2754..f00a571 100644 --- a/Editor/Layouts/RefTo.uxml +++ b/Editor/Layouts/RefTo.uxml @@ -7,7 +7,7 @@ - + diff --git a/Editor/RefTo/RefToContextMenu.cs b/Editor/RefTo/RefToContextMenu.cs index 7345140..596535b 100644 --- a/Editor/RefTo/RefToContextMenu.cs +++ b/Editor/RefTo/RefToContextMenu.cs @@ -29,20 +29,16 @@ private static void ShowRefToContextMenu(GenericMenu menu, SerializedProperty pr { var copy = property.Copy(); - if (RefToExtensions.TryGetRefType(copy, out var targetType)) + if (property.isArray == false && RefToExtensions.TryGetRefType(copy, out var targetType, out _)) { menu.AddItem(new GUIContent("RefTo: Reset"), false, (_) => { RefToExtensions.ResetRefTo(copy); }, null); - var isCanWriteToRef = - _copy.referenceType != null && targetType.IsAssignableFrom(_copy.referenceType); + var isSameType = _copy.referenceType != null && targetType.IsAssignableFrom(_copy.referenceType); + var typeName = _copy.referenceType?.Name; - var typeName = _copy.referenceType == null - ? string.Empty - : ObjectNames.NicifyVariableName(_copy.referenceType.Name); - - if (isCanWriteToRef) + if (isSameType) { menu.AddItem(new GUIContent($"RefTo: Paste Serialize Reference: {typeName}"), false, (_) => { PasteToProperty(copy); }, diff --git a/Editor/RefTo/RefToExtensions.cs b/Editor/RefTo/RefToExtensions.cs index 0f9fb3e..8e635fc 100644 --- a/Editor/RefTo/RefToExtensions.cs +++ b/Editor/RefTo/RefToExtensions.cs @@ -11,13 +11,15 @@ public static class RefToExtensions private const string HostPropertyName = "_host"; private const string ReferenceIdName = "_referenceId"; - public static bool TryGetRefType(SerializedProperty property, out Type refToType) + public static bool TryGetRefType(SerializedProperty property, out Type refToType, out Type hostType) { var toType = property.boxedValue?.GetType(); refToType = null; + hostType = null; if (IsGenericTypeOf(toType, typeof(RefTo<,>))) { refToType = toType.GenericTypeArguments[0]; + hostType = toType.GenericTypeArguments[1]; return true; } @@ -40,7 +42,7 @@ public static void WriteRefToFromPropertyToProperty(SerializedProperty fromPrope toProperty.serializedObject.Update(); } - public static (Object host, long id) GetRefToFieldsFromProperty(SerializedProperty property) + private static (Object host, long id) GetRefToFieldsFromProperty(SerializedProperty property) { var targetObject = property.boxedValue; if (targetObject != null) @@ -76,6 +78,73 @@ private static object GetValue(object target, string fieldName) var field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); return field?.GetValue(target); } + + public static bool TraverseProperty(SerializedProperty inProperty, string path, + Func isCompleteFunc) + { + using var currentProperty = inProperty.Copy(); + + do + { + var propertyPath = string.IsNullOrEmpty(path) ? currentProperty.name : $"{path}.{currentProperty.name}"; + + if (currentProperty.isArray && currentProperty.propertyType != SerializedPropertyType.String) + { + for (int i = 0; i < currentProperty.arraySize; i++) + { + var element = currentProperty.GetArrayElementAtIndex(i); + if (TraverseProperty(element, $"{propertyPath}[{i}]", isCompleteFunc)) + { + return true; + } + } + } + else if (currentProperty.hasVisibleChildren && currentProperty.propertyType == SerializedPropertyType.Generic) + { + if (TraverseProperty(currentProperty, propertyPath, isCompleteFunc)) + { + return true; + } + } + else + { + if (currentProperty.propertyType == SerializedPropertyType.ManagedReference) + { + if (isCompleteFunc.Invoke(currentProperty)) + { + return true; + } + } + } + } + while (currentProperty.NextVisible(false)); + + return false; + } + + public static (Type refType, Type targetType, Type hostType, Object host, bool isSameType) GetInspectorValues( + SerializedProperty property) + { + var (host, id) = GetRefToFieldsFromProperty(property); + TryGetRefType(property, out var targetType, out var hostType); + var isSameType = false; + Type refType = null; + if (host != null) + { + var reference = UnityEngine.Serialization.ManagedReferenceUtility.GetManagedReference(host, id); + if (reference != null) + { + refType = reference.GetType(); + isSameType = targetType.IsAssignableFrom(refType); + } + } + else + { + isSameType = true; + } + + return (refType, targetType, hostType, host, isSameType); + } } } #endif \ No newline at end of file diff --git a/Editor/RefTo/RefToPropertyDrawer.cs b/Editor/RefTo/RefToPropertyDrawer.cs index 14277e8..ab5745d 100644 --- a/Editor/RefTo/RefToPropertyDrawer.cs +++ b/Editor/RefTo/RefToPropertyDrawer.cs @@ -29,30 +29,41 @@ public override float GetPropertyHeight(SerializedProperty property, GUIContent public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) { var propertyRect = rect; - var (refType, targetType, host, isSameType) = GetInspectorValues(property); - var tooltip = $"Reference type: {TypeToName(refType)} \nRefTo Type: {TypeToName(targetType)}"; - label.tooltip = tooltip; + var (refType, targetType, hostType, host, isSameType) = RefToExtensions.GetInspectorValues(property); + label.tooltip = $"Target \nType - {targetType.Name} \nNamespace - {targetType.Namespace}"; EditorGUI.BeginProperty(rect, label, property); - var labelWidth = EditorGUIUtility.labelWidth > 90 ? 90 : EditorGUIUtility.labelWidth; + var labelWidth = EditorGUIUtility.labelWidth / 2; propertyRect.width = labelWidth; EditorGUI.LabelField(propertyRect, label); - var height = EditorGUIUtility.singleLineHeight; - var fieldSize = (rect.width - labelWidth) * 0.3f; + var fieldSize = (rect.width - labelWidth) * 0.5f; var labelRect = new Rect(rect.position + new Vector2(labelWidth, 0), new Vector2(rect.width - fieldSize - labelWidth, height)); var fieldRect = new Rect(labelRect.position + new Vector2(labelRect.width, 0), new Vector2(fieldSize, height)); var style = isSameType ? EditorStyles.boldLabel : ErrorStyle; - var refLabel = $"RefTo: {TypeToName(refType)} [{TypeToName(targetType)}]"; - EditorGUI.LabelField(labelRect, new GUIContent(refLabel), style); + var refLabel = $" R: {refType?.Name}"; + EditorGUI.LabelField(labelRect, + new GUIContent(refLabel, $"Reference \nType - {refType?.Name} \nNamespace - {refType?.Namespace}"), + style); + + var newValue = EditorGUI.ObjectField(fieldRect, host, hostType, true); + if (host != newValue) + { + if (newValue != null) + { + TryApplyRefToValue(newValue, property.serializedObject.targetObject, targetType, + property.propertyPath); + } + else + { + RefToExtensions.ResetRefTo(property); + } + } - EditorGUI.BeginDisabledGroup(true); - EditorGUI.ObjectField(fieldRect, host, typeof(UnityEngine.Object), true); - EditorGUI.EndDisabledGroup(); EditorGUI.EndProperty(); } @@ -61,55 +72,69 @@ private void DrawUIToolkit(VisualElement root, SerializedProperty property) var uiToolkitLayoutPath = "Packages/com.alexeytaranov.serializereferencedropdown/Editor/Layouts/RefTo.uxml"; var visualTreeAsset = AssetDatabase.LoadAssetAtPath(uiToolkitLayoutPath); root.Add(visualTreeAsset.Instantiate()); - + var propertyField = root.Q(); + propertyField.BindProperty(property); - var (_, targetType, _, _) = GetInspectorValues(property); + var (_, targetType, hostType, _, _) = RefToExtensions.GetInspectorValues(property); + + propertyField.tooltip = + $"Field: {property.name} \nTarget Type: {targetType.Name} \nNamespace: {targetType.Namespace}"; - propertyField.tooltip = $"Field: {property.name} \nTarget Type: {targetType.Name} \nNamespace: {targetType.Namespace}"; - var propertyPath = property.propertyPath; root.TrackSerializedObjectValue(property.serializedObject, RefreshDynamic); + var objectField = root.Q(); + objectField.objectType = hostType; + var targetObject = property.serializedObject.targetObject; + objectField.RegisterValueChangedCallback(ApplyRefToFromObject); RefreshDynamic(property.serializedObject); void RefreshDynamic(SerializedObject so) { using var localProperty = so.FindProperty(propertyPath); - var (refType, _, host, isSameType) = GetInspectorValues(localProperty); + var (refType, _, _, host, isSameType) = RefToExtensions.GetInspectorValues(localProperty); var refLabel = root.Q