Files
crtr/Assets/Cryville/Crtr/Config/IPropertyAdapter.cs

110 lines
3.6 KiB
C#

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;
}
}
}