/// <summary> /// Initialize the parameter list view based on the given registered type that has parameters to edit. This can be /// things such as interactions, processors, or composites. /// </summary> /// <param name="registeredType">Type of object that the parameters will be passed to at runtime. /// We need this to be able to determine the possible set of parameters and their possible values. This /// can be a class implementing <see cref="IInputInteraction"/>, for example.</param> /// <param name="existingParameters">List of existing parameters. Can be empty.</param> public void Initialize(Type registeredType, ReadOnlyArray <InputControlLayout.ParameterValue> existingParameters) { if (registeredType == null) { // No registered type. This usually happens when data references a registration that has // been removed in the meantime (e.g. an interaction that is no longer supported). We want // to accept this case and simply pretend that the given type has no parameters. Clear(); return; } // Try to instantiate object so that we can determine defaults. object instance = null; try { instance = Activator.CreateInstance(registeredType); } catch (Exception) { // Swallow. If we can't create an instance, we simply assume no defaults. } var parameters = new List <EditableParameterValue>(); ////REVIEW: support properties here? // Go through public instance fields and add every parameter found on the registered // type. var fields = registeredType.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (var field in fields) { // Skip all fields that have an [InputControl] attribute. This is relevant // only for composites, but we just always do it here. if (field.GetCustomAttribute <InputControlAttribute>(false) != null) { continue; } // Determine parameter name from field. var parameter = new EditableParameterValue { field = field }; var name = field.Name; parameter.value.name = name; // Determine parameter type from field. var fieldType = field.FieldType; if (fieldType == typeof(bool)) { parameter.value.type = InputControlLayout.ParameterType.Boolean; // Determine default. if (instance != null) { parameter.defaultValue = new InputControlLayout.ParameterValue(name, (bool)field.GetValue(instance)); } } else if (fieldType == typeof(int)) { parameter.value.type = InputControlLayout.ParameterType.Integer; // Determine default. if (instance != null) { parameter.defaultValue = new InputControlLayout.ParameterValue(name, (int)field.GetValue(instance)); } } else if (fieldType == typeof(float)) { parameter.value.type = InputControlLayout.ParameterType.Float; // Determine default. if (instance != null) { parameter.defaultValue = new InputControlLayout.ParameterValue(name, (float)field.GetValue(instance)); } } else if (fieldType.IsEnum) { parameter.value.type = InputControlLayout.ParameterType.Integer; parameter.enumNames = Enum.GetNames(fieldType).Select(x => new GUIContent(x)).ToArray(); ////REVIEW: this probably falls apart if multiple members have the same value var list = new List <int>(); foreach (var value in Enum.GetValues(fieldType)) { list.Add((int)value); } parameter.enumValues = list.ToArray(); // Determine default. if (instance != null) { var defaultValue = field.GetValue(instance); var defaultValueInt = Convert.ToInt32(defaultValue); parameter.defaultValue = new InputControlLayout.ParameterValue(name, defaultValueInt); } } // If the parameter already exists in the given list, maintain its value. var existingParameterIndex = existingParameters.IndexOf(x => x.name == field.Name); if (existingParameterIndex >= 0) { // Make sure we're preserving the right type. parameter.value = existingParameters[existingParameterIndex].ConvertTo(parameter.value.type); } else { // Not assigned. Set to default. if (parameter.defaultValue != null) { parameter.value = parameter.defaultValue.Value; } } // Add. parameters.Add(parameter); } m_Parameters = parameters.ToArray(); // See if we have a dedicated parameter editor. var parameterEditorType = InputParameterEditor.LookupEditorForType(registeredType); if (parameterEditorType != null) { // Create an editor instance and hand it the instance we created. Unlike our default // editing logic, on this path we will be operating on an object instance that contains // the parameter values. So on this path, we actually need to update the object to reflect // the current parameter values. foreach (var parameter in m_Parameters) { if (parameter.isEnum) { var enumValue = Enum.ToObject(parameter.field.FieldType, parameter.value.GetIntValue()); parameter.field.SetValue(instance, enumValue); } else { switch (parameter.value.type) { case InputControlLayout.ParameterType.Float: parameter.field.SetValue(instance, parameter.value.GetFloatValue()); break; case InputControlLayout.ParameterType.Boolean: parameter.field.SetValue(instance, parameter.value.GetBoolValue()); break; case InputControlLayout.ParameterType.Integer: parameter.field.SetValue(instance, parameter.value.GetIntValue()); break; } } } m_ParameterEditor = (InputParameterEditor)Activator.CreateInstance(parameterEditorType); m_ParameterEditor.SetTarget(instance); } else { m_ParameterEditor = null; // Create parameter labels. m_ParameterLabels = new GUIContent[m_Parameters.Length]; for (var i = 0; i < m_Parameters.Length; ++i) { // Look up tooltip from field. var tooltip = string.Empty; var field = m_Parameters[i].field; var tooltipAttribute = field.GetCustomAttribute <TooltipAttribute>(); if (tooltipAttribute != null) { tooltip = tooltipAttribute.tooltip; } // Create label. var niceName = ObjectNames.NicifyVariableName(m_Parameters[i].value.name); m_ParameterLabels[i] = new GUIContent(niceName, tooltip); } } }
/// <summary> /// /// </summary> /// <param name="registeredType">Type of object that the parameters will be passed to at runtime. /// We need this to be able to determine the possible set of parameters and their possible values. This /// can be a class implementing <see cref="IInputInteraction"/>, for example.</param> /// <param name="existingParameters">List of existing parameters. Can be empty/null.</param> public void Initialize(Type registeredType, ReadOnlyArray <InputControlLayout.ParameterValue> existingParameters) { if (registeredType == null) { throw new ArgumentNullException("registeredType"); } // Try to instantiate object so that we can determine defaults. object instance = null; try { instance = Activator.CreateInstance(registeredType); } catch (Exception) { // Swallow. If we can't create an instance, we simply assume no defaults. } var parameters = new List <EditableParameterValue>(); ////REVIEW: support properties here? // Go through public instance fields and add every parameter found on the registered // type. var fields = registeredType.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (var field in fields) { // Skip all fields that have an [InputControl] attribute. This is relevant // only for composites, but we just always do it here. if (field.GetCustomAttribute <InputControlAttribute>(false) != null) { continue; } // Determine parameter name from field. var parameter = new EditableParameterValue(); var name = field.Name; parameter.value.name = name; // Determine parameter type from field. var fieldType = field.FieldType; if (fieldType == typeof(bool)) { parameter.value.type = InputControlLayout.ParameterType.Boolean; // Determine default. if (instance != null) { parameter.defaultValue = new InputControlLayout.ParameterValue(name, (bool)field.GetValue(instance)); } } else if (fieldType == typeof(int)) { parameter.value.type = InputControlLayout.ParameterType.Integer; // Determine default. if (instance != null) { parameter.defaultValue = new InputControlLayout.ParameterValue(name, (int)field.GetValue(instance)); } } else if (fieldType == typeof(float)) { parameter.value.type = InputControlLayout.ParameterType.Float; // Determine default. if (instance != null) { parameter.defaultValue = new InputControlLayout.ParameterValue(name, (float)field.GetValue(instance)); } } else if (fieldType.IsEnum) { parameter.value.type = InputControlLayout.ParameterType.Integer; parameter.enumNames = Enum.GetNames(fieldType); ////REVIEW: this probably falls apart if multiple members have the same value var list = new List <int>(); foreach (var value in Enum.GetValues(fieldType)) { list.Add((int)value); } parameter.enumValues = list.ToArray(); // Determine default. if (instance != null) { var defaultValue = field.GetValue(instance); var defaultValueInt = Convert.ToInt32(defaultValue); parameter.defaultValue = new InputControlLayout.ParameterValue(name, defaultValueInt); } } // If the parameter already exists in the given list, maintain its value. var existingParameterIndex = existingParameters.IndexOf(x => x.name == field.Name); if (existingParameterIndex >= 0) { parameter.value = existingParameters[existingParameterIndex]; } else { // Not assigned. Set to default. if (parameter.defaultValue != null) { parameter.value = parameter.defaultValue.Value; } } // Add. parameters.Add(parameter); } m_Parameters = parameters.ToArray(); }