Can't EDIT objects derieved from Selectable

Issue #304 resolved
Andreas Podgurski created an issue

I need to derieve a class from Selectable and want to use Odin formatted dictionaries in the inspector. Sadly, the component is not rendered by Odin at all. I built this base class, similar to those included in Odin:

    [ShowOdinSerializedPropertiesInInspector]
    public abstract class SerializedSelectable : Selectable, ISerializationCallbackReceiver, ISupportsPrefabSerialization {
        [SerializeField, HideInInspector]
        private SerializationData _serializationData;

        SerializationData ISupportsPrefabSerialization.SerializationData { get { return this._serializationData; } set { this._serializationData = value; } }

        void ISerializationCallbackReceiver.OnAfterDeserialize() {
            UnitySerializationUtility.DeserializeUnityObject(this, ref this._serializationData);
            this.OnAfterDeserialize();
        }

        void ISerializationCallbackReceiver.OnBeforeSerialize() {
            UnitySerializationUtility.SerializeUnityObject(this, ref this._serializationData);
            this.OnBeforeSerialize();
        }

        protected virtual void OnAfterDeserialize() {
        }

        protected virtual void OnBeforeSerialize() {
        }
    }

If I derieve my class from this, like:

    public class MySelectable : SerializedSelectable {
        public Dictionary<String, SomeData> DicData;
    }

the dictionary is not shown. If I move the base class of SerializedSelectable down, having UIBehaviour, the base class of Selectable, as base class, the dictionary is shown. I can't figure out what disables the handling by Odin, but it would be great, if there would be a working base class similar to mine in the package. Derieving from Selectable is pretty usual when doing UI stuff...

Comments (10)

  1. Andreas Podgurski reporter
    • changed status to new

    Ok, my fault, still got Selectable as base class commented out, issue still exists in 1.0.6.1. Please fix or give a workaround, this is a showstopper for me for a week now...

  2. Andreas Podgurski reporter

    Update: Due to help of the Serialization Debugger, I can narrow the issue down to that the fields are simply not shown in the Inspector only. Serialization works and remains, if I derieve from Selectable, but the dictionary is not drawn and cannot be edited. With this hack I can at least continue development, but this is ugly as hell, so any fix is definitly appreciated...

  3. Bjarke Elias
    • changed status to open

    Hey sorry for not replying earlier on this one. And yeah you're right. That UI.SelectableEditor is the one overriding our editors.

    We'll have much better solutions with 1.1, and it'll also have much better performance. But until then you could do this as a workaround:

    using System;
    using Sirenix.OdinInspector.Editor;
    using Sirenix.Utilities.Editor;
    using UnityEditor;
    using UnityEditor.UI;
    using UnityEngine;
    
    [CustomEditor(typeof(MySelectable))]
    public class SelectableEditor : SelectableEditor
    {
        OdinEditor odinEditor;
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            if (!odinEditor)
            {
                odinEditor = CreateEditor(this.targets, typeof(OdinEditor)) as OdinEditor;
            }
    
            GUILayout.Space(10);
            OdinEditor.ForceHideMonoScriptInEditor = true;
            odinEditor.OnInspectorGUI();
            OdinEditor.ForceHideMonoScriptInEditor = false;
        }
    }
    
    [OdinDrawer]
    [DrawerPriority(double.MaxValue, 0, 0)]
    public class HideSelectableMembers<T> : OdinValueDrawer<T>
    {
        protected override void DrawPropertyLayout(IPropertyValueEntry<T> entry, GUIContent label)
        {
            // Skip all members of UnityEngine.UI.Selectable as they are already drawn
            if (entry.SerializationBackend == SerializationBackend.Unity && entry.Property.Info.MemberInfo.DeclaringType == typeof(UnityEngine.UI.Selectable))
            {
                return;
            }
    
            this.CallNextDrawer(entry, label);
        }
    }
    

    Another obvious alternative is to just make another regular SerializedBehaviour class and give it a RequireComponent(typeof(Selectable)).

  4. Andreas Podgurski reporter

    Thanks, the workaround seems to do it, although Unity crashed several times since then, have to keep an eye on this if there's a connection. Anyway, you're right, placing it in an own component parallel to the selectable would have been a way, too. I was too deep into analyzing the cause of the derivation problem to see that. If the crashes remain, I will consider this. But in the end, I still think, although there will be the 1.1 solution, the user shouldn't need to be aware of this, but decide the solution of this ticket yourself - it's working for me now. Thanks for helping out :)

  5. Log in to comment