Unity-SerializableDictionary icon indicating copy to clipboard operation
Unity-SerializableDictionary copied to clipboard

SerializedDictionary: The key is hidden in the title of the list of value

Open LanKuDot opened this issue 3 years ago • 9 comments

Thanks for the awesome project! But I got some problems while using the dictionary with a list of value.

  • Unity version: 2020.3.12f1
  • Sample Code:
public class Foo : MonoBehaviour
{
    [Serializable]
    public class StringListStorage : SerializableDictionary.Storage<List<string>> {}
    [Serializable]
    public class IntStringDictionary :
        SerializableDictionary<int, List<string>, StringListStorage> {}

    [SerializeField]
    private IntStringDictionary _dictionary;
}
  • Screenshot: screenshot1 The value of the key is shown when the mouse hovers on the title: screenshot2 And the list of values cannot be folded/unfloded by clicking the arrow.

LanKuDot avatar Aug 25 '21 02:08 LanKuDot

We're having the same issues, is there any fix for this? :)

max-critcrew avatar Sep 15 '21 21:09 max-critcrew

Hello, i've fixed the issue, in the file SerializableDictionaryPropertyDrawer you just need to swap the value and the key code blocks. Value must be drawn before the key property. Like this : image

sachapierot avatar Nov 08 '21 12:11 sachapierot

Hi, thanks! The hidden problem is solved in the almost cases. Unfortunately, I am using enum as the key, its value cannot be selected after change the drawing order.

LanKuDot avatar Nov 09 '21 03:11 LanKuDot

Hello i think i just solved the problem, i had the same issue as you, i could not click on textfield nor edit it.

The problem happens when we want to draw a dictionary which values are arrays. (ie using SerializableDictionary.Store class). I think since Unity now (2020 and later, 2019.4 was working on my pc) uses FoldoutHeaderGroup control to draw array headers, its conflicting with the editable fields which are on the same line. I did not succeed drawing a simple foldout, so i ended up doint it this way :

The StoragePropertyDrawer was causing issue, so i edited it and added a custom way of drawing it.

I first swapped back the key and value code blocks.

I then used a ReorderableList to draw elements of the underlying array in the SerializableDictionaryStoragePropertyDrawer.

Here is the code :

[CustomPropertyDrawer(typeof(SerializableDictionaryBase.Storage), true)]
public class SerializableDictionaryStoragePropertyDrawer : PropertyDrawer
{
    private Dictionary<string, ReorderableList> _dict = new Dictionary<string, ReorderableList>();
    private ReorderableList _currentList = null;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        property.Next(true);
        
        if (!property.isArray)
        {
            return;
        }
        
        ReorderableList list;
        if (_dict.ContainsKey(property.propertyPath))
        {
            list = _dict[property.propertyPath];
        }
        else
        {
            list = new ReorderableList(property.serializedObject, property, true, true, true, true);
            list.drawElementCallback += DrawElementCallback;
            list.elementHeightCallback += ElementHeightCallback;
            list.headerHeight = 0.0f;
            
            _dict.Add(property.propertyPath, list);
        }
        
        _currentList = list;
        
        if (_currentList == null)
        {
            _dict.Remove(property.propertyPath);
            return;
        }
    
        var foldoutRect = position;
        foldoutRect.height = 18;
        property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, label, true);
        if (property.isExpanded)
        {
            position.y += 20;
            position = EditorGUI.IndentedRect(position);
            list.DoList(position);
        }
    }

    private float ElementHeightCallback(int index)
    {
        if (_currentList == null)
            return 0.0f;
        
        var element = _currentList.serializedProperty.GetArrayElementAtIndex(index);
        return EditorGUI.GetPropertyHeight(element);
    }

    private void DrawElementCallback(Rect rect, int index, bool isActive, bool isFocused)
    {
        if (_currentList == null)
            return;
    
        var element = _currentList.serializedProperty.GetArrayElementAtIndex(index);
        rect.x += 10;
        rect.width -= 10;
        EditorGUI.PropertyField(rect, element, true);
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        property.Next(true);
        return EditorGUI.GetPropertyHeight(property);
    }
}

EDIT : removed useless code

sachapierot avatar Nov 09 '21 11:11 sachapierot

It works great! Thanks a lot!

LanKuDot avatar Nov 10 '21 09:11 LanKuDot

That's nice to read :)

sachapierot avatar Nov 10 '21 10:11 sachapierot

@Ornycar Thanks! It's working :)

max-critcrew avatar Nov 10 '21 10:11 max-critcrew

Yes, that's still the best solution. Thanks for sharing.

Heurazio avatar Apr 26 '23 10:04 Heurazio