dbrizov / NaughtyAttributes

Attribute Extensions for Unity
MIT License
4.56k stars 464 forks source link

[Request] Multiselect dropdown with different than enum types #134

Open Shelim opened 4 years ago

Shelim commented 4 years ago

This is effectively mixing [EnumFlags] with [Dropdown] like support.

Use case:

I need to create list of strings, where each string comes from a given (not known in compile time, but known in editor - so I cannot use enum) pool and each string can only appear once.

Example:

    [MultiDropdown("GetVectorValues")]
    public List<Vector3> AllowedDirections; // I can select more than one,
                                                // but each one at most once

    private DropdownList<Vector3> GetVectorValues()
    {
        return new DropdownList<Vector3>()
        {
            { "Right",   Vector3.right },
            { "Left",    Vector3.left },
            { "Up",      Vector3.up },
            { "Down",    Vector3.down },
            { "Forward", Vector3.forward },
            { "Back",    Vector3.back }
        };
    }
dbrizov commented 4 years ago

This is cool, I will implement it. In the meantime, you can achieve it like this. I haven't tested this code, but it should work.

public List<Direction> AllowedDirections;

[Serializable]
public struct Direction
{
    [Dropdown("GetVectorValues")]
    public Vector3 Value;

    private DropdownList<Vector3> GetVectorValues()
    {
    return new DropdownList<Vector3>()
    {
        { "Right",   Vector3.right },
        { "Left",    Vector3.left },
        { "Up",      Vector3.up },
        { "Down",    Vector3.down },
        { "Forward", Vector3.forward },
        { "Back",    Vector3.back }
    };
    }
}
Shelim commented 4 years ago

Oh, so I believe I run into bug - the value is unselectable (keeps at default, no uncaught exception is thrown), unless I change

public struct Direction

to

public class Direction

-> Then it works reasonably for now, but it - obviously - allows duplicates... 😄 Thank you for considering this improvement!

dbrizov commented 4 years ago

Sorry, I forgot that dropdowns don't work with structs. It's a known bug. I have it described in the documentation.

When nested inside a struct the value of the dropdown doesn’t update. This is because the value of the parent struct is updated via reflection. In order for the value to be updated the struct needs to be boxed and then unboxed. The struct is already passed as an object (boxed) to the dropdown drawer, but unfortunately, in order to unbox it I need to know the compile-time type of the struct, and I don’t. Nesting inside a class works as expected.

RunninglVlan commented 3 years ago

+1 for MultiDropdown - "make Dropdown* support collection fields" feature. I'm using code from "In the meantime, you can achieve it like this", and added a CustomPropertyDrawer for that inner class to get rid of unnecessary Folding in the Editor, as it's basically one field class:

[CustomPropertyDrawer(typeof(Direction))]
public class DirectionDrawer : PropertyDrawer {
    private static string Property => nameof(Direction.value);

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
        EditorGUI.PropertyField(position, property.FindPropertyRelative(Property));
    }
}
NeatWolf commented 3 years ago

+1 on this. Would be nice to either use collections or a named getter function that returns the updated values ^^ (as a List\<T> maybe? :P )

+1 for MultiDropdown - "make Dropdown* support collection fields" feature.