From 8bcc526dd61d775accc79abb160281ce52c14273 Mon Sep 17 00:00:00 2001
From: Menotdan <32620310+Menotdan@users.noreply.github.com>
Date: Mon, 1 Jan 2024 01:24:36 -0500
Subject: [PATCH] Add support for multiple VisibleIf attributes, and properly
set up the VisibleIf entries for ImportMaterialsAsInstances and
InstanceToImportAs.
---
.../CustomEditors/Editors/GenericEditor.cs | 91 +++++++++++--------
.../Attributes/Editor/VisibleIfAttribute.cs | 4 +-
Source/Engine/Tools/ModelTool/ModelTool.h | 4 +-
3 files changed, 57 insertions(+), 42 deletions(-)
diff --git a/Source/Editor/CustomEditors/Editors/GenericEditor.cs b/Source/Editor/CustomEditors/Editors/GenericEditor.cs
index 68c24a675..3359054fe 100644
--- a/Source/Editor/CustomEditors/Editors/GenericEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/GenericEditor.cs
@@ -66,9 +66,9 @@ namespace FlaxEditor.CustomEditors.Editors
public HeaderAttribute Header;
///
- /// The visible if attribute.
+ /// The visible if attributes.
///
- public VisibleIfAttribute VisibleIf;
+ public VisibleIfAttribute[] VisibleIfs;
///
/// The read-only attribute usage flag.
@@ -128,7 +128,7 @@ namespace FlaxEditor.CustomEditors.Editors
CustomEditorAlias = (CustomEditorAliasAttribute)attributes.FirstOrDefault(x => x is CustomEditorAliasAttribute);
Space = (SpaceAttribute)attributes.FirstOrDefault(x => x is SpaceAttribute);
Header = (HeaderAttribute)attributes.FirstOrDefault(x => x is HeaderAttribute);
- VisibleIf = (VisibleIfAttribute)attributes.FirstOrDefault(x => x is VisibleIfAttribute);
+ VisibleIfs = attributes.OfType().ToArray();
IsReadOnly = attributes.FirstOrDefault(x => x is ReadOnlyAttribute) != null;
ExpandGroups = attributes.FirstOrDefault(x => x is ExpandGroupsAttribute) != null;
@@ -210,17 +210,24 @@ namespace FlaxEditor.CustomEditors.Editors
private struct VisibleIfCache
{
public ScriptMemberInfo Target;
- public ScriptMemberInfo Source;
+ public ScriptMemberInfo[] Sources;
public PropertiesListElement PropertiesList;
public GroupElement Group;
- public bool Invert;
+ public bool[] InversionList;
public int LabelIndex;
public bool GetValue(object instance)
{
- var value = (bool)Source.GetValue(instance);
- if (Invert)
- value = !value;
+ bool value = true;
+
+ for (int i = 0; i < Sources.Length; i++)
+ {
+ bool currentValue = (bool)Sources[i].GetValue(instance);
+ if (InversionList[i])
+ currentValue = !currentValue;
+
+ value = value && currentValue;
+ }
return value;
}
}
@@ -298,40 +305,48 @@ namespace FlaxEditor.CustomEditors.Editors
return items;
}
- private static ScriptMemberInfo GetVisibleIfSource(ScriptType type, VisibleIfAttribute visibleIf)
+ private static ScriptMemberInfo[] GetVisibleIfSources(ScriptType type, VisibleIfAttribute[] visibleIfs)
{
- var property = type.GetProperty(visibleIf.MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
- if (property != ScriptMemberInfo.Null)
+ ScriptMemberInfo[] members = Array.Empty();
+
+ for (int i = 0; i < visibleIfs.Length; i++)
{
- if (!property.HasGet)
+ var property = type.GetProperty(visibleIfs[i].MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ if (property != ScriptMemberInfo.Null)
{
- Debug.LogError("Invalid VisibleIf rule. Property has missing getter " + visibleIf.MemberName);
- return ScriptMemberInfo.Null;
+ if (!property.HasGet)
+ {
+ Debug.LogError("Invalid VisibleIf rule. Property has missing getter " + visibleIfs[i].MemberName);
+ continue;
+ }
+
+ if (property.ValueType.Type != typeof(bool))
+ {
+ Debug.LogError("Invalid VisibleIf rule. Property has to return bool type " + visibleIfs[i].MemberName);
+ continue;
+ }
+
+ members = members.Append(property).ToArray();
+ continue;
}
- if (property.ValueType.Type != typeof(bool))
+ var field = type.GetField(visibleIfs[i].MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ if (field != ScriptMemberInfo.Null)
{
- Debug.LogError("Invalid VisibleIf rule. Property has to return bool type " + visibleIf.MemberName);
- return ScriptMemberInfo.Null;
+ if (field.ValueType.Type != typeof(bool))
+ {
+ Debug.LogError("Invalid VisibleIf rule. Field has to be bool type " + visibleIfs[i].MemberName);
+ continue;
+ }
+
+ members = members.Append(field).ToArray();
+ continue;
}
- return property;
+ Debug.LogError("Invalid VisibleIf rule. Cannot find member " + visibleIfs[i].MemberName);
}
- var field = type.GetField(visibleIf.MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
- if (field != ScriptMemberInfo.Null)
- {
- if (field.ValueType.Type != typeof(bool))
- {
- Debug.LogError("Invalid VisibleIf rule. Field has to be bool type " + visibleIf.MemberName);
- return ScriptMemberInfo.Null;
- }
-
- return field;
- }
-
- Debug.LogError("Invalid VisibleIf rule. Cannot find member " + visibleIf.MemberName);
- return ScriptMemberInfo.Null;
+ return members;
}
private static void GroupPanelCheckIfCanRevert(LayoutElementsContainer layout, ref bool canRevertReference, ref bool canRevertDefault)
@@ -575,7 +590,7 @@ namespace FlaxEditor.CustomEditors.Editors
protected virtual void SpawnProperty(LayoutElementsContainer itemLayout, ValueContainer itemValues, ItemInfo item)
{
int labelIndex = 0;
- if ((item.IsReadOnly || item.VisibleIf != null) &&
+ if ((item.IsReadOnly || item.VisibleIfs.Length > 0) &&
itemLayout.Children.Count > 0 &&
itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement propertiesListElement)
{
@@ -616,7 +631,7 @@ namespace FlaxEditor.CustomEditors.Editors
}
}
}
- if (item.VisibleIf != null && itemLayout.Children.Count > 0)
+ if (item.VisibleIfs.Length > 0 && itemLayout.Children.Count > 0)
{
PropertiesListElement list = null;
GroupElement group = null;
@@ -628,8 +643,8 @@ namespace FlaxEditor.CustomEditors.Editors
return;
// Get source member used to check rule
- var sourceMember = GetVisibleIfSource(item.Info.DeclaringType, item.VisibleIf);
- if (sourceMember == ScriptType.Null)
+ var sourceMembers = GetVisibleIfSources(item.Info.DeclaringType, item.VisibleIfs);
+ if (sourceMembers.Length == 0)
return;
// Resize cache
@@ -645,11 +660,11 @@ namespace FlaxEditor.CustomEditors.Editors
_visibleIfCaches[count] = new VisibleIfCache
{
Target = item.Info,
- Source = sourceMember,
+ Sources = sourceMembers,
PropertiesList = list,
Group = group,
LabelIndex = labelIndex,
- Invert = item.VisibleIf.Invert,
+ InversionList = item.VisibleIfs.Select((x, i) => x.Invert).ToArray(),
};
}
}
diff --git a/Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs b/Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs
index 5e690caa8..3d606370a 100644
--- a/Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs
+++ b/Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs
@@ -5,11 +5,11 @@ using System;
namespace FlaxEngine
{
///
- /// Shows property/field in the editor only if the specified member has a given value. Can be used to hide properties based on other properties (also private properties). The given member has to be bool type.
+ /// Shows property/field in the editor only if the specified member has a given value. Can be used to hide properties based on other properties (also private properties). The given member has to be bool type. Multiple VisibleIf attributes can be added for additional conditions to be met.
///
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class VisibleIfAttribute : Attribute
{
///
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.h b/Source/Engine/Tools/ModelTool/ModelTool.h
index 416505631..7ae199136 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.h
+++ b/Source/Engine/Tools/ModelTool/ModelTool.h
@@ -260,10 +260,10 @@ public:
API_FIELD(Attributes="EditorOrder(400), EditorDisplay(\"Materials\"), VisibleIf(nameof(ShowGeometry))")
bool ImportMaterials = true;
// If checked, the importer will create the model's materials as instances of a base material.
- API_FIELD(Attributes = "EditorOrder(401), EditorDisplay(\"Materials\"), VisibleIf(nameof(ImportMaterials))")
+ API_FIELD(Attributes = "EditorOrder(401), EditorDisplay(\"Materials\"), VisibleIf(nameof(ImportMaterials)), VisibleIf(nameof(ShowGeometry))")
bool ImportMaterialsAsInstances = false;
// The material used as the base material that will be instanced as the imported model's material.
- API_FIELD(Attributes = "EditorOrder(402), EditorDisplay(\"Materials\"), VisibleIf(nameof(ImportMaterialsAsInstances))")
+ API_FIELD(Attributes = "EditorOrder(402), EditorDisplay(\"Materials\"), VisibleIf(nameof(ImportMaterialsAsInstances)), VisibleIf(nameof(ShowGeometry))")
AssetReference InstanceToImportAs;
// If checked, the importer will import texture files used by the model and any embedded texture resources.
API_FIELD(Attributes="EditorOrder(410), EditorDisplay(\"Materials\"), VisibleIf(nameof(ShowGeometry))")