diff --git a/Source/Editor/CustomEditors/Editors/ArrayEditor.cs b/Source/Editor/CustomEditors/Editors/ArrayEditor.cs index 41ca6ba86..af7bff167 100644 --- a/Source/Editor/CustomEditors/Editors/ArrayEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ArrayEditor.cs @@ -52,7 +52,7 @@ namespace FlaxEditor.CustomEditors.Editors else { // Initialize new entries with default values - var defaultValue = TypeUtils.GetDefaultValue(new ScriptType(elementType)); + var defaultValue = TypeUtils.GetDefaultValue(new ScriptType(elementType), NotNullItems); for (int i = oldSize; i < newSize; i++) newValues.SetValue(defaultValue, i); } @@ -60,7 +60,7 @@ namespace FlaxEditor.CustomEditors.Editors else if (newSize > 0) { // Initialize new entries with default values - var defaultValue = TypeUtils.GetDefaultValue(new ScriptType(elementType)); + var defaultValue = TypeUtils.GetDefaultValue(new ScriptType(elementType), NotNullItems); for (int i = 0; i < newSize; i++) newValues.SetValue(defaultValue, i); } diff --git a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs index 141330aea..424ff83ca 100644 --- a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs +++ b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs @@ -77,11 +77,15 @@ namespace FlaxEditor.CustomEditors.Editors } } + /// + /// Determines if value of collection can be null. + /// + protected bool NotNullItems; private IntegerValueElement _size; + private Color _background; private int _elementsCount; private bool _readOnly; private bool _canReorderItems; - private bool _notNullItems; /// /// Gets the length of the collection. @@ -105,7 +109,7 @@ namespace FlaxEditor.CustomEditors.Editors { _readOnly = false; _canReorderItems = true; - _notNullItems = false; + NotNullItems = false; // No support for different collections for now if (HasDifferentValues || HasDifferentTypes) @@ -118,13 +122,19 @@ namespace FlaxEditor.CustomEditors.Editors Type overrideEditorType = null; float spacing = 10.0f; var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute); - if (collection != null) + if (collection is null) + { + _readOnly = false; + NotNullItems = false; + _background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor; + } + else { // TODO: handle NotNullItems by filtering child editors SetValue - _readOnly = collection.ReadOnly; _canReorderItems = collection.CanReorderItems; - _notNullItems = collection.NotNullItems; + NotNullItems = collection.NotNullItems; + _background = collection.BackgroundColor; overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type; spacing = collection.Spacing; } @@ -146,6 +156,8 @@ namespace FlaxEditor.CustomEditors.Editors // Elements if (size > 0) { + var panel = layout.VerticalPanel(); + panel.Panel.BackgroundColor = _background; var elementType = ElementType; if (_canReorderItems) { @@ -153,7 +165,7 @@ namespace FlaxEditor.CustomEditors.Editors { if (i != 0 && spacing > 0f) { - if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement) + if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement) { if (propertiesListElement.Labels.Count > 0) { @@ -166,12 +178,12 @@ namespace FlaxEditor.CustomEditors.Editors } else { - layout.Space(spacing); + panel.Space(spacing); } } var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null; - layout.Object(new CollectionItemLabel(this, i), new ListValueContainer(elementType, i, Values), overrideEditor); + panel.Object(new CollectionItemLabel(this, i), new ListValueContainer(elementType, i, Values), overrideEditor); } } else @@ -180,14 +192,14 @@ namespace FlaxEditor.CustomEditors.Editors { if (i != 0 && spacing > 0f) { - if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement) + if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement) propertiesListElement.Space(spacing); else - layout.Space(spacing); + panel.Space(spacing); } var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null; - layout.Object("Element " + i, new ListValueContainer(elementType, i, Values), overrideEditor); + panel.Object("Element " + i, new ListValueContainer(elementType, i, Values), overrideEditor); } } } @@ -229,6 +241,24 @@ namespace FlaxEditor.CustomEditors.Editors } } + /// + /// Rebuilds the parent layout if its collection. + /// + public void RebuildParentCollection() + { + if (ParentEditor is DictionaryEditor dictionaryEditor) + { + dictionaryEditor.RebuildParentCollection(); + dictionaryEditor.RebuildLayout(); + return; + } + if (ParentEditor is CollectionEditor collectionEditor) + { + collectionEditor.RebuildParentCollection(); + collectionEditor.RebuildLayout(); + } + } + private void OnSizeChanged() { if (IsSetBlocked) @@ -312,6 +342,7 @@ namespace FlaxEditor.CustomEditors.Editors if (Count != _elementsCount) { RebuildLayout(); + RebuildParentCollection(); } } } diff --git a/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs b/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs index 4a94136db..99e84b225 100644 --- a/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs +++ b/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs @@ -135,6 +135,7 @@ namespace FlaxEditor.CustomEditors.Editors } private IntegerValueElement _size; + private Color _background; private int _elementsCount; private bool _readOnly; private bool _notNullItems; @@ -164,8 +165,6 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - _readOnly = false; - _notNullItems = false; // No support for different collections for now if (HasDifferentValues || HasDifferentTypes) @@ -185,12 +184,18 @@ namespace FlaxEditor.CustomEditors.Editors if (attributes != null) { var collection = (CollectionAttribute)attributes.FirstOrDefault(x => x is CollectionAttribute); - if (collection != null) + if (collection is null) + { + _readOnly = false; + _notNullItems = false; + _background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor; + } + else { // TODO: handle ReadOnly and NotNullItems by filtering child editors SetValue - _readOnly = collection.ReadOnly; _notNullItems = collection.NotNullItems; + _background = collection.BackgroundColor; overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type; spacing = collection.Spacing; } @@ -213,13 +218,15 @@ namespace FlaxEditor.CustomEditors.Editors // Elements if (size > 0) { + var panel = layout.VerticalPanel(); + panel.Panel.BackgroundColor = _background; var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType(); var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray(); for (int i = 0; i < size; i++) { if (i != 0 && spacing > 0f) { - if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement) + if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement) { if (propertiesListElement.Labels.Count > 0) { @@ -232,13 +239,13 @@ namespace FlaxEditor.CustomEditors.Editors } else { - layout.Space(spacing); + panel.Space(spacing); } } var key = keys.ElementAt(i); var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null; - layout.Object(new DictionaryItemLabel(this, key), new DictionaryValueContainer(new ScriptType(valueType), key, Values), overrideEditor); + panel.Object(new DictionaryItemLabel(this, key), new DictionaryValueContainer(new ScriptType(valueType), key, Values), overrideEditor); } } _elementsCount = size; @@ -279,6 +286,24 @@ namespace FlaxEditor.CustomEditors.Editors } } + /// + /// Rebuilds the parent layout if its collection. + /// + public void RebuildParentCollection() + { + if (ParentEditor is DictionaryEditor dictionaryEditor) + { + dictionaryEditor.RebuildParentCollection(); + dictionaryEditor.RebuildLayout(); + return; + } + if (ParentEditor is CollectionEditor collectionEditor) + { + collectionEditor.RebuildParentCollection(); + collectionEditor.RebuildLayout(); + } + } + private void OnSizeChanged() { if (IsSetBlocked) @@ -389,7 +414,7 @@ namespace FlaxEditor.CustomEditors.Editors } } while (!isUnique); - newValues[Convert.ChangeType(uniqueKey, keyType)] = TypeUtils.GetDefaultValue(new ScriptType(valueType)); + newValues[Convert.ChangeType(uniqueKey, keyType)] = TypeUtils.GetDefaultValue(new ScriptType(valueType), _notNullItems); } else if (keyType.IsEnum) { @@ -410,7 +435,7 @@ namespace FlaxEditor.CustomEditors.Editors } } while (!isUnique && uniqueKeyIndex < enumValues.Length); - newValues[enumValues.GetValue(uniqueKeyIndex)] = TypeUtils.GetDefaultValue(new ScriptType(valueType)); + newValues[enumValues.GetValue(uniqueKeyIndex)] = TypeUtils.GetDefaultValue(new ScriptType(valueType), _notNullItems); } else if (keyType == typeof(string)) { @@ -430,7 +455,7 @@ namespace FlaxEditor.CustomEditors.Editors } } while (!isUnique); - newValues[uniqueKey] = TypeUtils.GetDefaultValue(new ScriptType(valueType)); + newValues[uniqueKey] = TypeUtils.GetDefaultValue(new ScriptType(valueType), _notNullItems); } else { @@ -454,6 +479,7 @@ namespace FlaxEditor.CustomEditors.Editors if (Count != _elementsCount) { RebuildLayout(); + RebuildParentCollection(); } } } diff --git a/Source/Editor/CustomEditors/Editors/ListEditor.cs b/Source/Editor/CustomEditors/Editors/ListEditor.cs index 0c6efaea4..a8871329a 100644 --- a/Source/Editor/CustomEditors/Editors/ListEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ListEditor.cs @@ -22,9 +22,7 @@ namespace FlaxEditor.CustomEditors.Editors var list = (IList)listType.CreateInstance(); var defaultValue = Scripting.TypeUtils.GetDefaultValue(ElementType); for (int i = 0; i < size; i++) - { list.Add(defaultValue); - } return list; } @@ -57,7 +55,7 @@ namespace FlaxEditor.CustomEditors.Editors else { // Initialize new entries with default values - var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType); + var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType, NotNullItems); for (int i = oldSize; i < newSize; i++) newValues.Add(defaultValue); } @@ -65,7 +63,7 @@ namespace FlaxEditor.CustomEditors.Editors else if (newSize > 0) { // Fill new entries with default value - var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType); + var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType, NotNullItems); for (int i = oldSize; i < newSize; i++) newValues.Add(defaultValue); } @@ -86,9 +84,7 @@ namespace FlaxEditor.CustomEditors.Editors var cloned = (IList)listType.CreateInstance(); for (int i = 0; i < size; i++) - { cloned.Add(list[i]); - } return cloned; } diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs index ea42ee99b..a7f9a6dd0 100644 --- a/Source/Editor/Options/OptionsModule.cs +++ b/Source/Editor/Options/OptionsModule.cs @@ -232,6 +232,7 @@ namespace FlaxEditor.Options BorderNormal = Color.FromBgra(0xFF54545C), TextBoxBackground = Color.FromBgra(0xFF333337), TextBoxBackgroundSelected = Color.FromBgra(0xFF3F3F46), + CollectionBackgroundColor = Color.FromBgra(0x16FFFFFF), ProgressNormal = Color.FromBgra(0xFF0ad328), // Fonts diff --git a/Source/Editor/Scripting/TypeUtils.cs b/Source/Editor/Scripting/TypeUtils.cs index 60f64ab8e..3d6362d5d 100644 --- a/Source/Editor/Scripting/TypeUtils.cs +++ b/Source/Editor/Scripting/TypeUtils.cs @@ -37,8 +37,9 @@ namespace FlaxEditor.Scripting /// Gets the default value for the given type (can be value type or reference type). /// /// The type. + /// Whether the value can be empty. If that's true, it can't. /// The created instance. - public static object GetDefaultValue(ScriptType type) + public static object GetDefaultValue(ScriptType type, bool notNull = false) { if (type.Type == typeof(string)) return string.Empty; @@ -64,7 +65,7 @@ namespace FlaxEditor.Scripting Utilities.Utils.InitDefaultValues(value); return value; } - if (new ScriptType(typeof(object)).IsAssignableFrom(type)) + if (!notNull && new ScriptType(typeof(object)).IsAssignableFrom(type)) return null; if (type.CanCreateInstance) { diff --git a/Source/Engine/Scripting/Attributes/CollectionAttribute.cs b/Source/Engine/Scripting/Attributes/CollectionAttribute.cs index 78781d3f9..7d854d582 100644 --- a/Source/Engine/Scripting/Attributes/CollectionAttribute.cs +++ b/Source/Engine/Scripting/Attributes/CollectionAttribute.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; +using FlaxEngine.GUI; namespace FlaxEngine { @@ -34,5 +35,10 @@ namespace FlaxEngine /// The spacing amount between collection items in the UI. /// public float Spacing; + + /// + /// The collection background color. + /// + public Color BackgroundColor = Style.Current.CollectionBackgroundColor; } } diff --git a/Source/Engine/Scripting/Scripting.cs b/Source/Engine/Scripting/Scripting.cs index ae7821526..baafffd56 100644 --- a/Source/Engine/Scripting/Scripting.cs +++ b/Source/Engine/Scripting/Scripting.cs @@ -221,6 +221,7 @@ namespace FlaxEngine TextBoxBackground = Color.FromBgra(0xFF333337), ProgressNormal = Color.FromBgra(0xFF0ad328), TextBoxBackgroundSelected = Color.FromBgra(0xFF3F3F46), + CollectionBackgroundColor = Color.FromBgra(0x16FFFFFF), SharedTooltip = new Tooltip(), }; style.DragWindow = style.BackgroundSelected * 0.7f; diff --git a/Source/Engine/UI/GUI/Style.cs b/Source/Engine/UI/GUI/Style.cs index 9b4f0f64e..b6ca35f88 100644 --- a/Source/Engine/UI/GUI/Style.cs +++ b/Source/Engine/UI/GUI/Style.cs @@ -152,6 +152,11 @@ namespace FlaxEngine.GUI [EditorOrder(190)] public Color TextBoxBackgroundSelected; + /// + /// The collection background color. + /// + [EditorOrder(195)] + public Color CollectionBackgroundColor; /// /// The progress normal color. ///