Fix ReadOnly attribute handling in collection editors

This commit is contained in:
Wojtek Figat
2024-05-13 16:08:50 +02:00
parent 68653fa91f
commit af08dc1c69
3 changed files with 71 additions and 49 deletions

View File

@@ -57,17 +57,18 @@ namespace FlaxEditor.CustomEditors.Editors
menu.ItemsContainer.RemoveChildren(); menu.ItemsContainer.RemoveChildren();
menu.AddButton("Copy", linkedEditor.Copy); menu.AddButton("Copy", linkedEditor.Copy);
var paste = menu.AddButton("Paste", linkedEditor.Paste); var b = menu.AddButton("Paste", linkedEditor.Paste);
paste.Enabled = linkedEditor.CanPaste; b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
menu.AddSeparator(); menu.AddSeparator();
var moveUpButton = menu.AddButton("Move up", OnMoveUpClicked); b = menu.AddButton("Move up", OnMoveUpClicked);
moveUpButton.Enabled = Index > 0; b.Enabled = Index > 0 && !Editor._readOnly;
var moveDownButton = menu.AddButton("Move down", OnMoveDownClicked); b = menu.AddButton("Move down", OnMoveDownClicked);
moveDownButton.Enabled = Index + 1 < Editor.Count; b.Enabled = Index + 1 < Editor.Count && !Editor._readOnly;
menu.AddButton("Remove", OnRemoveClicked); b = menu.AddButton("Remove", OnRemoveClicked);
b.Enabled = !Editor._readOnly;
} }
private void OnMoveUpClicked() private void OnMoveUpClicked()
@@ -177,6 +178,7 @@ namespace FlaxEditor.CustomEditors.Editors
private IntValueBox _sizeBox; private IntValueBox _sizeBox;
private Color _background; private Color _background;
private int _elementsCount, _minCount, _maxCount; private int _elementsCount, _minCount, _maxCount;
private bool _readOnly;
private bool _canResize; private bool _canResize;
private bool _canReorderItems; private bool _canReorderItems;
private CollectionAttribute.DisplayType _displayType; private CollectionAttribute.DisplayType _displayType;
@@ -209,6 +211,7 @@ namespace FlaxEditor.CustomEditors.Editors
return; return;
var size = Count; var size = Count;
_readOnly = false;
_canResize = true; _canResize = true;
_canReorderItems = true; _canReorderItems = true;
_minCount = 0; _minCount = 0;
@@ -225,6 +228,7 @@ namespace FlaxEditor.CustomEditors.Editors
if (collection != null) if (collection != null)
{ {
_canResize = !collection.ReadOnly; _canResize = !collection.ReadOnly;
_readOnly = collection.ReadOnly;
_minCount = collection.MinCount; _minCount = collection.MinCount;
_maxCount = collection.MaxCount; _maxCount = collection.MaxCount;
_canReorderItems = collection.CanReorderItems; _canReorderItems = collection.CanReorderItems;
@@ -235,6 +239,12 @@ namespace FlaxEditor.CustomEditors.Editors
spacing = collection.Spacing; spacing = collection.Spacing;
_displayType = collection.Display; _displayType = collection.Display;
} }
if (attributes != null && attributes.Any(x => x is ReadOnlyAttribute))
{
_readOnly = true;
_canResize = false;
_canReorderItems = false;
}
if (_maxCount == 0) if (_maxCount == 0)
_maxCount = ushort.MaxValue; _maxCount = ushort.MaxValue;
_canResize &= _minCount < _maxCount; _canResize &= _minCount < _maxCount;
@@ -243,8 +253,7 @@ namespace FlaxEditor.CustomEditors.Editors
dragArea.CustomControl.Editor = this; dragArea.CustomControl.Editor = this;
dragArea.CustomControl.ElementType = ElementType; dragArea.CustomControl.ElementType = ElementType;
// Check for the AssetReferenceAttribute. In JSON assets, it can be used to filter // Check for the AssetReferenceAttribute. In JSON assets, it can be used to filter which scripts can be dragged over and dropped on this collection editor
// which scripts can be dragged over and dropped on this collection editor.
var assetReference = (AssetReferenceAttribute)attributes?.FirstOrDefault(x => x is AssetReferenceAttribute); var assetReference = (AssetReferenceAttribute)attributes?.FirstOrDefault(x => x is AssetReferenceAttribute);
if (assetReference != null) if (assetReference != null)
{ {
@@ -333,6 +342,8 @@ namespace FlaxEditor.CustomEditors.Editors
var property = panel.AddPropertyItem(itemLabel); var property = panel.AddPropertyItem(itemLabel);
var itemLayout = (LayoutElementsContainer)property; var itemLayout = (LayoutElementsContainer)property;
itemLabel.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor); itemLabel.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
if (_readOnly && itemLayout.Children.Count > 0)
GenericEditor.OnReadOnlyProperty(itemLayout);
} }
else if (_displayType == CollectionAttribute.DisplayType.Header || (_displayType == CollectionAttribute.DisplayType.Default && !single)) else if (_displayType == CollectionAttribute.DisplayType.Header || (_displayType == CollectionAttribute.DisplayType.Default && !single))
{ {
@@ -340,13 +351,15 @@ namespace FlaxEditor.CustomEditors.Editors
cdp.CustomControl.Setup(this, i, _canReorderItems); cdp.CustomControl.Setup(this, i, _canReorderItems);
var itemLayout = cdp.VerticalPanel(); var itemLayout = cdp.VerticalPanel();
cdp.CustomControl.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor); cdp.CustomControl.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
if (_readOnly && itemLayout.Children.Count > 0)
GenericEditor.OnReadOnlyProperty(itemLayout);
} }
} }
} }
_elementsCount = size; _elementsCount = size;
// Add/Remove buttons // Add/Remove buttons
if (_canResize) if (_canResize && !_readOnly)
{ {
var panel = dragArea.HorizontalPanel(); var panel = dragArea.HorizontalPanel();
panel.Panel.Size = new Float2(0, 20); panel.Panel.Size = new Float2(0, 20);

View File

@@ -131,7 +131,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc /> /// <inheritdoc />
public override bool OnMouseDoubleClick(Float2 location, MouseButton button) public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
{ {
if (button == MouseButton.Left) if (button == MouseButton.Left && _editor._canEditKeys)
{ {
OnEditClicked(null); OnEditClicked(null);
return true; return true;
@@ -156,6 +156,7 @@ namespace FlaxEditor.CustomEditors.Editors
private bool _readOnly; private bool _readOnly;
private bool _notNullItems; private bool _notNullItems;
private bool _canEditKeys; private bool _canEditKeys;
private bool _canEditValues;
private bool _keyEdited; private bool _keyEdited;
private CollectionAttribute.DisplayType _displayType; private CollectionAttribute.DisplayType _displayType;
@@ -197,6 +198,11 @@ namespace FlaxEditor.CustomEditors.Editors
spacing = collection.Spacing; spacing = collection.Spacing;
_displayType = collection.Display; _displayType = collection.Display;
} }
if (attributes != null && attributes.Any(x => x is ReadOnlyAttribute))
{
_readOnly = true;
_canEditKeys = false;
}
// Size // Size
if (layout.ContainerControl is DropPanel dropPanel) if (layout.ContainerControl is DropPanel dropPanel)
@@ -239,14 +245,6 @@ namespace FlaxEditor.CustomEditors.Editors
var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType<object>(); var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType<object>();
var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray(); var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray();
var valuesType = new ScriptType(valueType); var valuesType = new ScriptType(valueType);
bool single = valuesType.IsPrimitive ||
valuesType.Equals(new ScriptType(typeof(string))) ||
valuesType.IsEnum ||
(valuesType.GetFields().Length == 1 && valuesType.GetProperties().Length == 0) ||
(valuesType.GetProperties().Length == 1 && valuesType.GetFields().Length == 0) ||
valuesType.Equals(new ScriptType(typeof(JsonAsset))) ||
valuesType.Equals(new ScriptType(typeof(SettingsBase)));
// Use separate layout cells for each collection items to improve layout updates for them in separation // Use separate layout cells for each collection items to improve layout updates for them in separation
var useSharedLayout = valueType.IsPrimitive || valueType.IsEnum; var useSharedLayout = valueType.IsPrimitive || valueType.IsEnum;
@@ -263,6 +261,8 @@ namespace FlaxEditor.CustomEditors.Editors
var property = panel.AddPropertyItem(new DictionaryItemLabel(this, key)); var property = panel.AddPropertyItem(new DictionaryItemLabel(this, key));
var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel(); var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel();
itemLayout.Object(new DictionaryValueContainer(valuesType, key, Values), overrideEditor); itemLayout.Object(new DictionaryValueContainer(valuesType, key, Values), overrideEditor);
if (_readOnly && itemLayout.Children.Count > 0)
GenericEditor.OnReadOnlyProperty(itemLayout);
} }
} }
_elementsCount = size; _elementsCount = size;

View File

@@ -581,6 +581,43 @@ namespace FlaxEditor.CustomEditors.Editors
return layout; return layout;
} }
internal static void OnReadOnlyProperty(LayoutElementsContainer itemLayout, int labelIndex = -1)
{
PropertiesListElement list = null;
int firstChildControlIndex = 0;
bool disableSingle = true;
var control = itemLayout.Children[itemLayout.Children.Count - 1];
if (control is GroupElement group && group.Children.Count > 0)
{
list = group.Children[0] as PropertiesListElement;
disableSingle = false; // Disable all nested editors
}
else if (control is PropertiesListElement list1 && labelIndex != -1)
{
list = list1;
firstChildControlIndex = list.Labels[labelIndex].FirstChildControlIndex;
}
else if (control?.Control != null)
{
control.Control.Enabled = false;
}
if (list != null)
{
// Disable controls added to the editor
var count = list.Properties.Children.Count;
for (int j = firstChildControlIndex; j < count; j++)
{
var child = list.Properties.Children[j];
if (disableSingle && child is PropertyNameLabel)
break;
if (child != null)
child.Enabled = false;
}
}
}
/// <summary> /// <summary>
/// Evaluate the <see cref="VisibleIfAttribute"/> cache for a given property item. /// Evaluate the <see cref="VisibleIfAttribute"/> cache for a given property item.
/// </summary> /// </summary>
@@ -660,35 +697,7 @@ namespace FlaxEditor.CustomEditors.Editors
if (item.IsReadOnly && itemLayout.Children.Count > 0) if (item.IsReadOnly && itemLayout.Children.Count > 0)
{ {
PropertiesListElement list = null; OnReadOnlyProperty(itemLayout, labelIndex);
int firstChildControlIndex = 0;
bool disableSingle = true;
var control = itemLayout.Children[itemLayout.Children.Count - 1];
if (control is GroupElement group && group.Children.Count > 0)
{
list = group.Children[0] as PropertiesListElement;
disableSingle = false; // Disable all nested editors
}
else if (control is PropertiesListElement list1)
{
list = list1;
firstChildControlIndex = list.Labels[labelIndex].FirstChildControlIndex;
}
if (list != null)
{
// Disable controls added to the editor
var count = list.Properties.Children.Count;
for (int j = firstChildControlIndex; j < count; j++)
{
var child = list.Properties.Children[j];
if (disableSingle && child is PropertyNameLabel)
break;
if (child != null)
child.Enabled = false;
}
}
} }
EvaluateVisibleIf(itemLayout, item, labelIndex); EvaluateVisibleIf(itemLayout, item, labelIndex);