using Cryville.Common.ComponentModel; using System; using System.ComponentModel; using System.Linq; using System.Reflection; namespace Cryville.Crtr.Config { public interface IPropertyAdapter { string Category { get; } string Name { get; } string Description { get; } PropertyType Type { get; } object[] Range { get; } object GetValue(); void SetValue(object value); event Action ValueChanged; void Invalidate(); object MapValue(object value); bool SetMapped { get; } object MapValueInverse(object value); } public enum PropertyType { Unknown, Number, NumberStepped, Boolean, String, } public class DefaultPropertyAdapter : IPropertyAdapter { readonly object _target; readonly PropertyInfo _prop; public string Category { get; private set; } public string Name { get; private set; } public string Description { get; private set; } public PropertyType Type { get; private set; } public object[] Range { get; private set; } public object GetValue() { return _prop.GetValue(_target, null); } public void SetValue(object value) { _prop.SetValue(_target, value, null); } public event Action ValueChanged; public void Invalidate() { ValueChanged?.Invoke(); } readonly double _precision; readonly double _step; readonly bool _logarithmic; public object MapValue(object value) { if (Type == PropertyType.Number || Type == PropertyType.NumberStepped) { var result = (double)value; if (_step != 0) result *= _step; if (_logarithmic) result = Math.Pow(Math.E, result); if (_precision != 0) result = Math.Round(result / _precision) * _precision; return Convert.ChangeType(result, _prop.PropertyType); } return value; } public bool SetMapped { get { return true; } } public object MapValueInverse(object value) { if (Type == PropertyType.Number || Type == PropertyType.NumberStepped) { var result = Convert.ToDouble(value); if (_logarithmic) result = Math.Log(result); if (_step != 0) result /= _step; return result; } return value; } public DefaultPropertyAdapter(object target, PropertyInfo prop) { _target = target; _prop = prop; var attrs = prop.GetCustomAttributes(typeof(CategoryAttribute), true); if (attrs.Length > 0) Category = ((CategoryAttribute)attrs.Single()).Category; Name = prop.Name; var attrs2 = prop.GetCustomAttributes(typeof(DescriptionAttribute), true); if (attrs2.Length > 0) Description = ((DescriptionAttribute)attrs2.Single()).Description; if (prop.PropertyType == typeof(bool)) Type = PropertyType.Boolean; else if (prop.PropertyType == typeof(char)) throw new NotSupportedException(); else if (prop.PropertyType.IsPrimitive) { Type = prop.GetCustomAttributes(typeof(StepAttribute), true).Length > 0 ? PropertyType.NumberStepped : PropertyType.Number; var attr = prop.GetCustomAttributes(typeof(RangeAttribute), true); if (attr.Length > 0) { var u = (RangeAttribute)attr.Single(); Range = new object[] { u.Min, u.Max }; } attr = prop.GetCustomAttributes(typeof(PrecisionAttribute), true); if (attr.Length > 0) { var u = (PrecisionAttribute)attr.Single(); _precision = u.Precision; } attr = prop.GetCustomAttributes(typeof(StepAttribute), true); if (attr.Length > 0) { var u = (StepAttribute)attr.Single(); _step = u.Step; } attr = prop.GetCustomAttributes(typeof(LogarithmicScaleAttribute), true); if (attr.Length > 0) { _logarithmic = true; } } else if (prop.PropertyType == typeof(string)) Type = PropertyType.String; else return; } } }