protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, GUIContent label)
        {
            bool valueNeedsFixing = entry.ValueState == PropertyValueState.NullReference &&
                                    entry.SerializationBackend == SerializationBackend.Unity;

            if (valueNeedsFixing)
            {
                bool possibleRecursion = false;

                var prop = entry.Property.Parent;

                while (prop != null)
                {
                    if (prop.ValueEntry != null && (prop.ValueEntry.TypeOfValue == typeof(T) || prop.ValueEntry.BaseValueType == typeof(T)))
                    {
                        // We have a possible recursion
                        possibleRecursion = true;
                        break;
                    }

                    prop = prop.Parent;
                }

                if (possibleRecursion)
                {
                    SirenixEditorGUI.ErrorMessageBox("Possible Unity serialization recursion detected; cutting off drawing pre-emptively.");
                    return; // Get out of here
                }

                // If no recursion, fix value in layout
                if (Event.current.type == EventType.Layout)
                {
                    for (int i = 0; i < entry.ValueCount; i++)
                    {
                        object value = UnitySerializationUtility.CreateDefaultUnityInitializedObject(typeof(T));
                        entry.WeakValues.ForceSetValue(i, value);
                    }

                    entry.ApplyChanges();

                    var tree = entry.Property.Tree;

                    if (tree.UnitySerializedObject != null)
                    {
                        tree.UnitySerializedObject.ApplyModifiedPropertiesWithoutUndo();
                        Undo.RecordObjects(tree.UnitySerializedObject.targetObjects, "Odin inspector value changed");
                    }

                    entry.Property.Update(true);
                }
            }

            this.CallNextDrawer(entry, label);
        }
Exemple #2
0
            protected override void DrawPropertyLayout(IPropertyValueEntry <ToggleableAsset> entry, GUIContent label)
            {
                if (entry.SmartValue.AutoToggle)
                {
#pragma warning disable 0618 // Type or member is obsolete
                    AllEditorGUI.ObjectField(null, entry.SmartValue.Object, entry.SmartValue.Object.GetType(), false, true);
#pragma warning restore 0618 // Type or member is obsolete
                }
                else
                {
                    var rect            = GUILayoutUtility.GetRect(16, 16, GUILayoutOptions.ExpandWidth(true));
                    var toggleRect      = new Rect(rect.x, rect.y, 16, 16);
                    var objectFieldRect = new Rect(rect.x + 20, rect.y, rect.width - 20, 16);

                    if (Event.current.type != EventType.Repaint)
                    {
                        toggleRect.x      -= 5;
                        toggleRect.y      -= 5;
                        toggleRect.width  += 10;
                        toggleRect.height += 10;
                    }
                    var prevChanged = GUI.changed;

                    entry.SmartValue.Toggled = GUI.Toggle(toggleRect, entry.SmartValue.Toggled, "");

                    if (prevChanged != GUI.changed)
                    {
                        entry.ApplyChanges();
                    }

                    GUIHelper.PushGUIEnabled(entry.SmartValue.Toggled);

#pragma warning disable 0618 // Type or member is obsolete
                    AllEditorGUI.ObjectField(objectFieldRect, null, entry.SmartValue.Object, entry.SmartValue.Object.GetType(), false, true);
#pragma warning restore 0618 // Type or member is obsolete

                    GUIHelper.PopGUIEnabled();
                }
            }
Exemple #3
0
        /// <summary>
        /// Draws the property.
        /// </summary>
        protected override void DrawPropertyLayout(IPropertyValueEntry <T> entry, GUIContent label)
        {
            Context context;

            if (entry.Context.Get(this, "context", out context))
            {
                context.UniqueControlName = Guid.NewGuid().ToString();
            }

            if (!context.IsValid)
            {
                GUIHelper.PushColor(Color.red);
            }

            GUI.SetNextControlName(context.UniqueControlName);

            Rect rect = EditorGUILayout.GetControlRect();

            if (label != null)
            {
                rect = EditorGUI.PrefixLabel(rect, label);
            }

            Rect fieldRect    = rect;
            Rect dropdownRect = rect.AlignRight(18);

            // Dropdown button.
            EditorGUIUtility.AddCursorRect(dropdownRect, MouseCursor.Arrow);
            if (GUI.Button(dropdownRect, GUIContent.none, GUIStyle.none))
            {
                TypeSelector selector = new TypeSelector(AssemblyTypeFlags.All, false);

                selector.SelectionConfirmed += t =>
                {
                    var type = t.FirstOrDefault();

                    entry.Property.Tree.DelayAction(() =>
                    {
                        entry.WeakSmartValue = type;
                        context.IsValid      = true;
                        entry.ApplyChanges();
                    });
                };

                selector.SetSelection(entry.SmartValue);
                selector.ShowInPopup(rect, 350);
            }

            // Reset type name.
            if (Event.current.type == EventType.Layout)
            {
                context.TypeNameTemp = entry.SmartValue != null?Binder.BindToName(entry.SmartValue) : null;
            }

            EditorGUI.BeginChangeCheck();
            context.TypeNameTemp = SirenixEditorFields.DelayedTextField(fieldRect, context.TypeNameTemp);

            // Draw dropdown button.
            EditorIcons.TriangleDown.Draw(dropdownRect);

            if (!context.IsValid)
            {
                GUIHelper.PopColor();
            }

            bool isFocused = GUI.GetNameOfFocusedControl() == context.UniqueControlName;
            bool defocused = false;

            if (isFocused != context.WasFocusedControl)
            {
                defocused = !isFocused;
                context.WasFocusedControl = isFocused;
            }

            if (EditorGUI.EndChangeCheck())
            {
                if (string.IsNullOrEmpty(context.TypeNameTemp.Trim()))
                {
                    // String is empty
                    entry.SmartValue = null;
                    context.IsValid  = true;
                }
                else
                {
                    Type type = Binder.BindToType(context.TypeNameTemp);

                    if (type == null)
                    {
                        type = AssemblyUtilities.GetTypeByCachedFullName(context.TypeNameTemp);
                    }

                    if (type == null)
                    {
                        context.IsValid = false;
                    }
                    else
                    {
                        // Use WeakSmartValue in case of a different Type-derived instance showing up somehow, so we don't get cast errors
                        entry.WeakSmartValue = type;
                        context.IsValid      = true;
                    }
                }
            }

            if (defocused)
            {
                // Ensure we show the full type name when the control is defocused
                context.TypeNameTemp = entry.SmartValue == null ? "" : Binder.BindToName(entry.SmartValue);
                context.IsValid      = true;
            }
        }