From 484bc409d47b8c0e7780764322422010406ce538 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 9 Jun 2021 10:58:54 +0200 Subject: [PATCH] Add support for `NotNullItems` option in collections editors #542 --- Source/Editor/CustomEditors/CustomEditor.cs | 3 +- .../CustomEditors/Editors/ArrayEditor.cs | 6 +-- .../CustomEditors/Editors/CollectionEditor.cs | 47 ++++++++++++------- .../CustomEditors/Editors/DictionaryEditor.cs | 42 +++++++---------- .../CustomEditors/Editors/ListEditor.cs | 6 +-- .../Editor/CustomEditors/SyncPointEditor.cs | 4 +- Source/Editor/Options/OptionsModule.cs | 2 +- Source/Editor/Scripting/TypeUtils.cs | 5 +- .../Attributes/CollectionAttribute.cs | 3 +- Source/Engine/Scripting/Scripting.cs | 2 +- Source/Engine/UI/GUI/Style.cs | 1 + 11 files changed, 64 insertions(+), 57 deletions(-) diff --git a/Source/Editor/CustomEditors/CustomEditor.cs b/Source/Editor/CustomEditors/CustomEditor.cs index ca45652b9..caf03bc2f 100644 --- a/Source/Editor/CustomEditors/CustomEditor.cs +++ b/Source/Editor/CustomEditors/CustomEditor.cs @@ -789,8 +789,7 @@ namespace FlaxEditor.CustomEditors /// True if allow to handle this event, otherwise false. protected virtual bool OnDirty(CustomEditor editor, object value, object token = null) { - ParentEditor.OnDirty(editor, value, token); - return true; + return ParentEditor.OnDirty(editor, value, token); } /// diff --git a/Source/Editor/CustomEditors/Editors/ArrayEditor.cs b/Source/Editor/CustomEditors/Editors/ArrayEditor.cs index af7bff167..7f023e8bc 100644 --- a/Source/Editor/CustomEditors/Editors/ArrayEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ArrayEditor.cs @@ -43,7 +43,7 @@ namespace FlaxEditor.CustomEditors.Editors // Copy old values Array.Copy(array, 0, newValues, 0, sharedCount); - if (elementType.IsValueType) + if (elementType.IsValueType || NotNullItems) { // Fill new entries with the last value for (int i = oldSize; i < newSize; i++) @@ -52,7 +52,7 @@ namespace FlaxEditor.CustomEditors.Editors else { // Initialize new entries with default values - var defaultValue = TypeUtils.GetDefaultValue(new ScriptType(elementType), NotNullItems); + var defaultValue = TypeUtils.GetDefaultValue(new ScriptType(elementType)); 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), NotNullItems); + var defaultValue = TypeUtils.GetDefaultValue(new ScriptType(elementType)); 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 424ff83ca..6c3dda04e 100644 --- a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs +++ b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs @@ -81,6 +81,7 @@ namespace FlaxEditor.CustomEditors.Editors /// Determines if value of collection can be null. /// protected bool NotNullItems; + private IntegerValueElement _size; private Color _background; private int _elementsCount; @@ -107,40 +108,34 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - _readOnly = false; - _canReorderItems = true; - NotNullItems = false; - // No support for different collections for now if (HasDifferentValues || HasDifferentTypes) return; var size = Count; + _readOnly = false; + _canReorderItems = true; + _background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor; + NotNullItems = false; // Try get CollectionAttribute for collection editor meta var attributes = Values.GetAttributes(); Type overrideEditorType = null; float spacing = 10.0f; var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute); - if (collection is null) + if (collection != 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; - _background = collection.BackgroundColor; + if (collection.BackgroundColor.HasValue) + _background = collection.BackgroundColor.Value; overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type; spacing = collection.Spacing; } // Size - if (_readOnly) + if (_readOnly || (NotNullItems && size == 0)) { layout.Label("Size", size.ToString()); } @@ -214,7 +209,8 @@ namespace FlaxEditor.CustomEditors.Editors Text = "+", TooltipText = "Add new item", AnchorPreset = AnchorPresets.TopRight, - Parent = area.ContainerControl + Parent = area.ContainerControl, + Enabled = !NotNullItems || size > 0, }; addButton.Clicked += () => { @@ -229,7 +225,7 @@ namespace FlaxEditor.CustomEditors.Editors TooltipText = "Remove last item", AnchorPreset = AnchorPresets.TopRight, Parent = area.ContainerControl, - Enabled = size > 0 + Enabled = size > 0, }; removeButton.Clicked += () => { @@ -345,5 +341,24 @@ namespace FlaxEditor.CustomEditors.Editors RebuildParentCollection(); } } + + /// + protected override bool OnDirty(CustomEditor editor, object value, object token = null) + { + if (NotNullItems) + { + if (value == null && editor.ParentEditor == this) + return false; + if (editor == this && value is IList list) + { + for (int i = 0; i < list.Count; i++) + { + if (list[i] == null) + return false; + } + } + } + return base.OnDirty(editor, value, token); + } } } diff --git a/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs b/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs index 99e84b225..ba66aa0fa 100644 --- a/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs +++ b/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs @@ -165,7 +165,6 @@ namespace FlaxEditor.CustomEditors.Editors /// public override void Initialize(LayoutElementsContainer layout) { - // No support for different collections for now if (HasDifferentValues || HasDifferentTypes) return; @@ -176,29 +175,23 @@ namespace FlaxEditor.CustomEditors.Editors 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; - if (attributes != null) + var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute); + if (collection != null) { - var collection = (CollectionAttribute)attributes.FirstOrDefault(x => x is CollectionAttribute); - 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; - } + _readOnly = collection.ReadOnly; + _notNullItems = collection.NotNullItems; + if (collection.BackgroundColor.HasValue) + _background = collection.BackgroundColor.Value; + overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type; + spacing = collection.Spacing; } // Size @@ -210,7 +203,7 @@ namespace FlaxEditor.CustomEditors.Editors { _size = layout.IntegerValue("Size"); _size.IntValue.MinValue = 0; - _size.IntValue.MaxValue = ushort.MaxValue; + _size.IntValue.MaxValue = _notNullItems ? size : ushort.MaxValue; _size.IntValue.Value = size; _size.IntValue.ValueChanged += OnSizeChanged; } @@ -259,7 +252,8 @@ namespace FlaxEditor.CustomEditors.Editors Text = "+", TooltipText = "Add new item", AnchorPreset = AnchorPresets.TopRight, - Parent = area.ContainerControl + Parent = area.ContainerControl, + Enabled = !_notNullItems, }; addButton.Clicked += () => { @@ -274,7 +268,7 @@ namespace FlaxEditor.CustomEditors.Editors TooltipText = "Remove last item", AnchorPreset = AnchorPresets.TopRight, Parent = area.ContainerControl, - Enabled = size > 0 + Enabled = size > 0, }; removeButton.Clicked += () => { @@ -414,7 +408,7 @@ namespace FlaxEditor.CustomEditors.Editors } } while (!isUnique); - newValues[Convert.ChangeType(uniqueKey, keyType)] = TypeUtils.GetDefaultValue(new ScriptType(valueType), _notNullItems); + newValues[Convert.ChangeType(uniqueKey, keyType)] = TypeUtils.GetDefaultValue(new ScriptType(valueType)); } else if (keyType.IsEnum) { @@ -435,7 +429,7 @@ namespace FlaxEditor.CustomEditors.Editors } } while (!isUnique && uniqueKeyIndex < enumValues.Length); - newValues[enumValues.GetValue(uniqueKeyIndex)] = TypeUtils.GetDefaultValue(new ScriptType(valueType), _notNullItems); + newValues[enumValues.GetValue(uniqueKeyIndex)] = TypeUtils.GetDefaultValue(new ScriptType(valueType)); } else if (keyType == typeof(string)) { @@ -455,7 +449,7 @@ namespace FlaxEditor.CustomEditors.Editors } } while (!isUnique); - newValues[uniqueKey] = TypeUtils.GetDefaultValue(new ScriptType(valueType), _notNullItems); + newValues[uniqueKey] = TypeUtils.GetDefaultValue(new ScriptType(valueType)); } else { diff --git a/Source/Editor/CustomEditors/Editors/ListEditor.cs b/Source/Editor/CustomEditors/Editors/ListEditor.cs index a8871329a..afae52139 100644 --- a/Source/Editor/CustomEditors/Editors/ListEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ListEditor.cs @@ -46,7 +46,7 @@ namespace FlaxEditor.CustomEditors.Editors for (int i = 0; i < sharedCount; i++) newValues.Add(list[i]); - if (elementType.IsValueType) + if (elementType.IsValueType || NotNullItems) { // Fill new entries with the last value for (int i = oldSize; i < newSize; i++) @@ -55,7 +55,7 @@ namespace FlaxEditor.CustomEditors.Editors else { // Initialize new entries with default values - var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType, NotNullItems); + var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType); for (int i = oldSize; i < newSize; i++) newValues.Add(defaultValue); } @@ -63,7 +63,7 @@ namespace FlaxEditor.CustomEditors.Editors else if (newSize > 0) { // Fill new entries with default value - var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType, NotNullItems); + var defaultValue = Scripting.TypeUtils.GetDefaultValue(elementType); for (int i = oldSize; i < newSize; i++) newValues.Add(defaultValue); } diff --git a/Source/Editor/CustomEditors/SyncPointEditor.cs b/Source/Editor/CustomEditors/SyncPointEditor.cs index 120648230..3555aaea4 100644 --- a/Source/Editor/CustomEditors/SyncPointEditor.cs +++ b/Source/Editor/CustomEditors/SyncPointEditor.cs @@ -112,9 +112,9 @@ namespace FlaxEditor.CustomEditors EndUndoRecord(); _setValueToken = token; - // Mark as modified and don't pass event further + // Mark as modified and don't pass event further to the higher editors (don't call parent) _isDirty = true; - return false; + return true; } /// diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs index a7f9a6dd0..fa1b46f30 100644 --- a/Source/Editor/Options/OptionsModule.cs +++ b/Source/Editor/Options/OptionsModule.cs @@ -232,7 +232,7 @@ namespace FlaxEditor.Options BorderNormal = Color.FromBgra(0xFF54545C), TextBoxBackground = Color.FromBgra(0xFF333337), TextBoxBackgroundSelected = Color.FromBgra(0xFF3F3F46), - CollectionBackgroundColor = Color.FromBgra(0x16FFFFFF), + CollectionBackgroundColor = Color.FromBgra(0x14CCCCCC), ProgressNormal = Color.FromBgra(0xFF0ad328), // Fonts diff --git a/Source/Editor/Scripting/TypeUtils.cs b/Source/Editor/Scripting/TypeUtils.cs index 3d6362d5d..60f64ab8e 100644 --- a/Source/Editor/Scripting/TypeUtils.cs +++ b/Source/Editor/Scripting/TypeUtils.cs @@ -37,9 +37,8 @@ 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, bool notNull = false) + public static object GetDefaultValue(ScriptType type) { if (type.Type == typeof(string)) return string.Empty; @@ -65,7 +64,7 @@ namespace FlaxEditor.Scripting Utilities.Utils.InitDefaultValues(value); return value; } - if (!notNull && new ScriptType(typeof(object)).IsAssignableFrom(type)) + if (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 7d854d582..8094b35aa 100644 --- a/Source/Engine/Scripting/Attributes/CollectionAttribute.cs +++ b/Source/Engine/Scripting/Attributes/CollectionAttribute.cs @@ -1,7 +1,6 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; -using FlaxEngine.GUI; namespace FlaxEngine { @@ -39,6 +38,6 @@ namespace FlaxEngine /// /// The collection background color. /// - public Color BackgroundColor = Style.Current.CollectionBackgroundColor; + public Color? BackgroundColor; } } diff --git a/Source/Engine/Scripting/Scripting.cs b/Source/Engine/Scripting/Scripting.cs index baafffd56..4d79324f9 100644 --- a/Source/Engine/Scripting/Scripting.cs +++ b/Source/Engine/Scripting/Scripting.cs @@ -221,7 +221,7 @@ namespace FlaxEngine TextBoxBackground = Color.FromBgra(0xFF333337), ProgressNormal = Color.FromBgra(0xFF0ad328), TextBoxBackgroundSelected = Color.FromBgra(0xFF3F3F46), - CollectionBackgroundColor = Color.FromBgra(0x16FFFFFF), + CollectionBackgroundColor = Color.FromBgra(0x14CCCCCC), 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 b6ca35f88..a945d1602 100644 --- a/Source/Engine/UI/GUI/Style.cs +++ b/Source/Engine/UI/GUI/Style.cs @@ -157,6 +157,7 @@ namespace FlaxEngine.GUI /// [EditorOrder(195)] public Color CollectionBackgroundColor; + /// /// The progress normal color. ///