private static ExpressionFieldAttribute GetExpressionFieldAttribute(Type expressionContainingType, SerializedProperty expressionProperty) { if (!_expressionPropertyAttributesByExpressionType.ContainsKey(expressionContainingType)) { _expressionPropertyAttributesByExpressionType.Add(expressionContainingType, new Dictionary <string, ExpressionFieldAttribute>()); } var propertyCache = _expressionPropertyAttributesByExpressionType[expressionContainingType]; if (!propertyCache.ContainsKey(expressionProperty.name)) { FieldInfo fieldInfo = expressionContainingType.GetField(expressionProperty.name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy); ExpressionFieldAttribute fieldAttribute = null; if (fieldInfo != null) { ExpressionFieldAttribute[] typeAttributes = (ExpressionFieldAttribute[])fieldInfo.GetCustomAttributes(typeof(ExpressionFieldAttribute), false); if (typeAttributes.Length != 0) { fieldAttribute = typeAttributes[0]; } } propertyCache.Add(expressionProperty.name, fieldAttribute); } return(propertyCache[expressionProperty.name]); }
static LambdaExpression GetExpansion(MemberInfo mi) { ExpressionFieldAttribute efa = mi.GetCustomAttribute <ExpressionFieldAttribute>(); if (efa == null) { return(null); } if (efa.Name == "auto") { throw new InvalidOperationException($"The {nameof(ExpressionFieldAttribute)} for {mi.DeclaringType.TypeName()}.{mi.MemberName()} has the default value 'auto'.\r\nMaybe Signum.MSBuildTask is not running in assemby {mi.DeclaringType.Assembly.GetName().Name}?"); } Type type = mi.DeclaringType; FieldInfo fi = type.GetField(efa.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fi == null) { throw new InvalidOperationException("Expression field '{0}' not found on '{1}'".FormatWith(efa.Name, type.TypeName())); } var obj = fi.GetValue(null); if (obj == null) { throw new InvalidOperationException("Expression field '{0}' is null".FormatWith(efa.Name)); } var result = obj as LambdaExpression; if (result == null) { throw new InvalidOperationException("Expression field '{0}' does not contain a lambda expression".FormatWith(efa.Name, type.TypeName())); } return(result); }
public static void DrawExpressionSelector(SerializedProperty expressionProperty, Type expressionContainingType, Dictionary <string, Variable> variables) { ExpressionFieldAttribute fieldAttribute = GetExpressionFieldAttribute(expressionContainingType, expressionProperty); // Defaults for display name and required type if attribute isn't present. Type requiredExpressionValueType = fieldAttribute != null ? fieldAttribute.ExpressionType : typeof(object); string displayName = fieldAttribute != null ? fieldAttribute.DisplayName : expressionProperty.name; if (requiredExpressionValueType == typeof(Variable)) { // Special case. Show all variables: UnityEngine.Object propertyValue = expressionProperty.objectReferenceValue; if (propertyValue == null || !(propertyValue is VariableLiteralExpression)) { expressionProperty.objectReferenceValue = ScriptableObject.CreateInstance <VariableLiteralExpression>(); } VariableLiteralExpression variableExpression = (VariableLiteralExpression)expressionProperty.objectReferenceValue; GUILayout.BeginHorizontal(); GUILayout.Label(GetFriendlyPropertyDisplayName(expressionProperty), GUILayout.ExpandWidth(false)); GUILayout.FlexibleSpace(); Variable variableValue = VariableSelector(variableExpression.Value as Variable, typeof(object), variables, false); GUILayout.EndHorizontal(); variableExpression.VariableValue = variableValue; return; } // Get collection of all expression types in the project. // Filter the expression types returned to those that match the field required type. Dictionary <string, Type> expressionTypes = GetValidExpressionTypes(requiredExpressionValueType); // Get a string array of expression type names to display string[] typeArray = expressionTypes.Keys.ToArray(); // Find the current value of the expression property. UnityEngine.Object currentValue = expressionProperty.objectReferenceValue; // Find the index of the selection in the typeArray to show the correct type in the drop down string currentSelection = currentValue == null ? "-" : currentValue.GetType().Name; int currentSelectionIndex = Array.IndexOf(typeArray, currentSelection); // Show the drop down selector GUILayout.BeginHorizontal(); GUILayout.Label(displayName, GUILayout.ExpandWidth(false)); GUILayout.FlexibleSpace(); int newSelectionIndex = EditorGUILayout.Popup(currentSelectionIndex, expressionTypes.Keys.ToArray()); // If the new index isn't what we had before, find the new expression type in the dictionary by type name and assign a new instance of it. if (currentSelectionIndex != newSelectionIndex) { Type newType = expressionTypes[typeArray[newSelectionIndex]]; if (newType != null) { expressionProperty.objectReferenceValue = ScriptableObject.CreateInstance(newType); expressionProperty.serializedObject.ApplyModifiedProperties(); currentValue = expressionProperty.objectReferenceValue; } } // Now show the fields of the assigned expression object (if not null) if (currentValue != null) { SerializedObject serializedObject = new SerializedObject(currentValue); // If it's a VariableExpression, then we need to show the custom VariableSelector. if (currentValue.GetType() == typeof(VariableExpression)) { DrawVariableSelector(serializedObject, requiredExpressionValueType, variables); } else { // Otherwise, just show the properties like normal. SerializedProperty property = serializedObject.GetIterator(); property.NextVisible(true); while (property.NextVisible(false)) { GUILayout.BeginHorizontal(); GUILayout.Label(GetFriendlyPropertyDisplayName(property)); EditorGUILayout.PropertyField(property, GUIContent.none, true); serializedObject.ApplyModifiedProperties(); GUILayout.EndHorizontal(); } } } GUILayout.EndHorizontal(); }