Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any idea how to make this work with Serializable class as opposed to only ScriptableObject and MonoBehaviours? #14

Open
perrauo opened this issue Sep 28, 2022 · 1 comment

Comments

@perrauo
Copy link

perrauo commented Sep 28, 2022

Unity Editors do not work with Serializable class. I assume we would need a PropertyDrawer. Also a custom base class of some kind in order to make it work with arrays.

using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using Cirrus.Objects;
//using Cirrus.Unity.Objects;

using UnityEngine;
using UnityEditor;
using System;
using Object = UnityEngine.Object;

namespace MarkupAttributes.Editor
{
	[Serializable]
	public class MarkupSerializableBase
	{ 
	
	}

#if UNITY_EDITOR
	[CustomPropertyDrawer(typeof(MarkupSerializableBase), true)]
	public class MarkupPropertyDrawer : PropertyDrawer
	{
        private SerializedProperty[] allProps;
        private SerializedProperty[] firstLevelProps;
        private List<PropertyLayoutData> layoutData;

        private InspectorLayoutController layoutController;
        private CallbackManager callbackManager;
        private Dictionary<SerializedProperty, InlineEditorData> inlineEditors = new Dictionary<SerializedProperty, InlineEditorData>();
        private List<TargetObjectWrapper> targetsRequireUpdate = new List<TargetObjectWrapper>();

        protected virtual void OnInitialize() { }
        protected virtual void OnCleanup() { }
        protected void AddCallback(SerializedProperty property, CallbackEvent type, Action<SerializedProperty> callback)
        {
            callbackManager.AddCallback(property, type, callback);
        }

        protected void OnEnable()
        {           
            InitializeMarkedUpEditor();
        }

        protected void OnDisable()
        {
            CleanupMarkedUpEditor();
        }

        private SerializedObject serializedObject;
        //private Object target;

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            //if(property == null) return;
            serializedObject = property.serializedObject;
            //target = property.objectReferenceValue;
            //property.tar

            DrawMarkedUpInspector();
        }

        protected void InitializeMarkedUpEditor()
        {
            EditorLayoutDataBuilder.BuildLayoutData(serializedObject, out allProps,
                out firstLevelProps, out layoutData, out inlineEditors, out targetsRequireUpdate);
            layoutController = new InspectorLayoutController(serializedObject.GetType().FullName,
                layoutData.ToArray());
            callbackManager = new CallbackManager(firstLevelProps);
            OnInitialize();
        }

        protected void CleanupMarkedUpEditor()
        {
            OnCleanup();
            foreach(var item in inlineEditors)
            {
                //DestroyImmediate(item.Value.editor);
            }
        }

        protected bool DrawMarkedUpInspector()
        {
            EditorGUI.BeginChangeCheck();
            serializedObject.UpdateIfRequiredOrScript();

            CreateInlineEditors();
            UpdateTargets();
            int topLevelIndex = 1;
            layoutController.Begin();

            if(!MarkupGUI.IsInsideInlineEditor)
            {
                using(new EditorGUI.DisabledScope(true))
                {
                    EditorGUILayout.PropertyField(allProps[0]);
                }
            }

            for(int i = 1; i < allProps.Length; i++)
            {
                layoutController.BeforeProperty(i);
                if(layoutController.ScopeVisible)
                {
                    using(new EditorGUI.DisabledScope(!layoutController.ScopeEnabled))
                    {
                        DrawProperty(i, topLevelIndex);
                    }
                }

                if(layoutController.IsTopLevel(i))
                    topLevelIndex += 1;
            }
            layoutController.Finish();

            serializedObject.ApplyModifiedProperties();
            return EditorGUI.EndChangeCheck();
        }

        private void DrawProperty(int index, int topLevelIndex)
        {
            var prop = allProps[index];
            bool topLevel = layoutController.IsTopLevel(index);

            if(topLevel) callbackManager.InvokeCallback(topLevelIndex, CallbackEvent.BeforeProperty);


            using(new EditorGUI.DisabledScope(!layoutController.IsPropertyEnabled(index)))
            {
                if(layoutController.IsPropertyVisible(index))
                {
                    if(!topLevel || !callbackManager.InvokeCallback(index, CallbackEvent.ReplaceProperty))
                    {
                        if(inlineEditors.ContainsKey(prop))
                        {
                            InlineEditorData data = inlineEditors[prop];
                            MarkupGUI.DrawEditorInline(prop, data.editor, data.mode, data.enabled);
                        }
                        else
                        {
                            EditorGUILayout.PropertyField(prop, layoutController.IncludeChildren(index));
                        }
                    }
                }
            }
            if(topLevel) callbackManager.InvokeCallback(topLevelIndex, CallbackEvent.AfterProperty);
        }

        private void CreateInlineEditors()
        {
            var props = new List<SerializedProperty>(inlineEditors.Keys);
            foreach(var prop in props)
            {
                var editor = inlineEditors[prop].editor;

                if(prop.objectReferenceValue != serializedObject.targetObject)
                {
                    Material material = prop.objectReferenceValue as Material;
                    if(material != null)
                    {
                        //CreateCachedEditor(material, typeof(HeaderlessMaterialEditor), ref editor);
                        inlineEditors[prop].enabled = AssetDatabase.GetAssetPath(material).StartsWith("Assets");
                    }
                    else
                    {
                        //CreateCachedEditor(prop.objectReferenceValue, null, ref editor);
                    }
                }
                else
                {
                    editor = null;
                    prop.objectReferenceValue = null;
                    Debug.LogError("Self reference in the InlinedEditor property is not allowed.");
                }


                inlineEditors[prop].editor = editor;
            }
        }

        private void UpdateTargets()
        {
            foreach(var wrapper in targetsRequireUpdate)
            {
                wrapper.Update();
            }
        }
    }
#endif
}
@Simply-Cods
Copy link

I know this is stale, but there are 2 built-in ways to make this work with serializable classes (and structs) without creating a custom property drawer. This package also works with arrays and lists without doing anything

MyComponent.cs

using UnityEngine;
using MarkupAttributes;
using System.Collections.Generic;

public class MyComponent : MonoBehaviour
{
    [Box("Group")]
    public MyClass1 _myClass1;

    [MarkedUpField(indentChildren:false, showControl: false)]
    public MyClass2 _myClass2;

    public float[] _myArr;

    public List<float> _myList = new List<float>();
}

[MarkedUpType(indentChildren: false, showControl: false)]
[System.Serializable]
public class MyClass1
{
    public float _myFloat1 = 1f;
}

[System.Serializable]
public class MyClass2
{
    public float _myFloat2 = 1f;
}

MyEditor.cs

using UnityEditor;
using MarkupAttributes.Editor;

[CustomEditor(typeof(MyComponent))]
public class MyEditor : MarkedUpEditor
{
}

This gives the following result
screen

You can also modify the way serializable types are shown in the inspector using the attribute parameters (both of them default to true)

Hope this answers your question

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants