Forcing private variables to display

Issue #128 resolved
Scott Richmond
created an issue

We use the following wrapper code to display our custom Blueprint assets:

    [OdinDrawer]
    public class BlueprintComponentWrapperDrawer<T> : OdinAttributeDrawer<BlueprintComponentWrapper, T> // Draw for any type that has a BlueprintComponentWrapperAttribute
    {
        public override bool CanDrawTypeFilter(Type type)
        {
            // Further filter so that we don't wrap the list itself, but only its elements
            return !typeof(IList).IsAssignableFrom(type);
        }

        protected override void DrawPropertyLayout(IPropertyValueEntry<T> entry, BlueprintComponentWrapper attribute, GUIContent label)
        {
            var isExpandedContext = entry.Property.Context.Get(this, "is_expanded", true); // Get a context value for the expansion toggle

            SirenixEditorGUI.BeginBox();
            //SirenixEditorGUI.BeginBoxHeader();
            {
                GUIHelper.PushIsBoldLabel(true);
                isExpandedContext.Value = SirenixEditorGUI.Foldout(isExpandedContext.Value, 
                    GUIHelper.TempContent(entry.TypeOfValue.Name));
                GUIHelper.PopIsBoldLabel();
            }
            //SirenixEditorGUI.EndBoxHeader();

            if (SirenixEditorGUI.BeginFadeGroup(UniqueDrawerKey.Create(entry, this), isExpandedContext.Value))
            {
                // Call the next drawer, which will draw all the fields of the list items
                GUIHelper.PushIndentLevel(1);
                this.CallNextDrawer(entry.Property, null);
                GUIHelper.PopIndentLevel();
            }
            SirenixEditorGUI.EndFadeGroup();
            SirenixEditorGUI.EndBox();
        }
    }
public class BlueprintContainer : ScriptableObject
{
    [SerializeField]
    private string _data;

    [NonSerialized]
    public Blueprint Blueprint;

    public IEnumerable<object> GetComponents() { return Blueprint != null ? Blueprint.Components : Enumerable.Empty<object>(); }

    public void OnEnable()
    {
        Deserialize();
    }

#if UNITY_EDITOR 
    [ShowInInspector]
    [ListDrawerSettings(DraggableItems = true, IsReadOnly = false, Expanded = true)]
    [BlueprintComponentWrapper]
    private List<object> BlueprintComponents {
        get {
            return Blueprint.Components;
        }
        set { Blueprint.Components = value; }
    }
#endif

[SNIP]
}

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class BlueprintComponentWrapper : Attribute { }

Many of our Blueprint Components contain private variables by default and although we have been using [ShowInInspector] on them, it is quickly becoming tedious as the data grows. We need a way to force show all private variables by default when inspecting through this wrapper. Is there anything we can do about this?

IE something like:

GUIHelper.PushSetting(OdinProperty.ShowInInspector, true);
this.CallNextDrawer(entry.Property, null);
GUIHelper.PopSetting(OdinProperty.ShowInInspector);

Comments (13)

  1. Tor Esa Vestergaard

    There isn't currently any way to do this, no, I'm afraid. We could add something like a [ShowPrivateMembers] and/or a [OdinSerializePrivateMembers] attribute (which in your case would have the same effect, as your data isn't serialized by Odin, but would still show up). You would then decorate each of your component data classes with this attribute, significantly cutting down on the number of attributes you need to declare, as you only have to do it once per class, on the class itself.

    Would this resolve your issue?

    A capability more exactly like what you propose is possibly on the roadmap, with the rewrite of the property system innards, hopefully upcoming within the next 2-3 months. Currently, though, the property tree is relatively static, and there is no way to push or pop changes to which properties are fundamentally included in the property tree..

  2. Scott Richmond reporter

    [ShowPrivateMembers] would certainly help. However we would require the longer term solution as well I think. I understand it would require some rework and time though.

  3. Scott Richmond

    Actually, is it possible you could point me to the location in your source where you grab the properties of the currently inspected type? I could just add my own call to some static setting file that we set/unset whilst inspecting through the above code.

  4. Tor Esa Vestergaard

    Sure - it happens per type in the InspectorPropertyInfo class, in the first TryCreate method - that's where it decides whether a member is included in the property tree. This is saved statically per type. That part of the code is a bit of a mess, though, and is as mentioned slated for a bit of a cleanup.

  5. Scott Richmond

    Oh? How so? At the moment I plan to do literally just as above and only in this instance.

    Also - We just recently discovered [ShowInInspector] does not appear to actually write back a modified value to a private property.

  6. Tor Esa Vestergaard

    Right now, which members of a given type are included in the property tree is statically cached, and is only ever evaluated once. It cannot be changed dynamically - that would require a major redesign of the entire property system, which we are currently planning. The best you can currently do, is check whether the type is one of your components, and then include all private members.

  7. Log in to comment