/// <inheritdoc /> public override void Initialize(LayoutElementsContainer layout) { // No support for different collections for now if (HasDifferentValues || HasDifferentTypes) { return; } var type = Values.Type; var size = Count; var argTypes = type.GetGenericArguments(); var keyType = argTypes[0]; var valueType = argTypes[1]; _canEditKeys = keyType == typeof(string) || keyType.IsPrimitive || keyType.IsEnum; _background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor; _readOnly = false; _notNullItems = false; // Try get CollectionAttribute for collection editor meta var attributes = Values.GetAttributes(); Type overrideEditorType = null; float spacing = 0.0f; var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute); if (collection != null) { _readOnly = collection.ReadOnly; _notNullItems = collection.NotNullItems; if (collection.BackgroundColor.HasValue) { _background = collection.BackgroundColor.Value; } overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type; spacing = collection.Spacing; } // Size if (_readOnly || !_canEditKeys) { layout.Label("Size", size.ToString()); } else { _size = layout.IntegerValue("Size"); _size.IntValue.MinValue = 0; _size.IntValue.MaxValue = _notNullItems ? size : ushort.MaxValue; _size.IntValue.Value = size; _size.IntValue.ValueChanged += OnSizeChanged; } // Elements if (size > 0) { var panel = layout.VerticalPanel(); panel.Panel.BackgroundColor = _background; var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType <object>(); var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray(); var valuesType = new ScriptType(valueType); // Use separate layout cells for each collection items to improve layout updates for them in separation var useSharedLayout = valueType.IsPrimitive || valueType.IsEnum; for (int i = 0; i < size; i++) { if (i != 0 && spacing > 0f) { if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement) { if (propertiesListElement.Labels.Count > 0) { var label = propertiesListElement.Labels[propertiesListElement.Labels.Count - 1]; var margin = label.Margin; margin.Bottom += spacing; label.Margin = margin; } propertiesListElement.Space(spacing); } else { panel.Space(spacing); } } var key = keys.ElementAt(i); var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null; var property = panel.AddPropertyItem(new DictionaryItemLabel(this, key)); var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel(); itemLayout.Object(new DictionaryValueContainer(valuesType, key, Values), overrideEditor); } } _elementsCount = size; // Add/Remove buttons if (!_readOnly && _canEditKeys) { var area = layout.Space(20); var addButton = new Button(area.ContainerControl.Width - (16 + 16 + 2 + 2), 2, 16, 16) { Text = "+", TooltipText = "Add new item", AnchorPreset = AnchorPresets.TopRight, Parent = area.ContainerControl, Enabled = !_notNullItems, }; addButton.Clicked += () => { if (IsSetBlocked) { return; } Resize(Count + 1); }; var removeButton = new Button(addButton.Right + 2, addButton.Y, 16, 16) { Text = "-", TooltipText = "Remove last item", AnchorPreset = AnchorPresets.TopRight, Parent = area.ContainerControl, Enabled = size > 0, }; removeButton.Clicked += () => { if (IsSetBlocked) { return; } Resize(Count - 1); }; } }