/// ---------------------------------------------
/// Opsive Shared
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.Shared.Editor.UIElements.Controls.Attributes
{
using Opsive.Shared.Utility;
using System;
using System.Reflection;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
/// <summary>
/// Implements AttributeControlBase for the MinMaxRange attribute.
/// </summary>
[ControlType(typeof(Shared.Utility.MinMaxRangeAttribute))]
public class MinMaxRangeAttributeControl : AttributeControlBase
{
/// <summary>
/// Does the attribute override the type control?
/// </summary>
public override bool OverrideTypeControl { get { return true; } }
/// <summary>
/// Does the control use a label?
/// </summary>
public override bool UseLabel { get { return true; } }
/// <summary>
/// Returns the attribute control that should be used for the specified AttributeControlType.
/// </summary>
/// <param name="input">The input to the control.</param>
/// <returns>The created control.</returns>
protected override VisualElement GetControl(AttributeControlInput input)
{
var rangeAttribute = input.Field.GetCustomAttribute<Shared.Utility.MinMaxRangeAttribute>();
if (rangeAttribute == null) {
return null;
}
var horizontalLayout = new VisualElement();
horizontalLayout.AddToClassList("horizontal-layout");
var minMaxValue = (MinMaxFloat)input.Value;
var minMaxSlider = new MinMaxSlider(minMaxValue.MinValue, minMaxValue.MaxValue, rangeAttribute.MinLimit, rangeAttribute.MaxLimit);
var minFloatField = new FloatField();
var maxFloatField = new FloatField();
minFloatField.value = minMaxValue.MinValue;
minFloatField.RegisterValueChangedCallback(c =>
{
if (!input.OnChangeEvent(new MinMaxFloat(c.newValue, minMaxSlider.maxValue))) {
minFloatField.SetValueWithoutNotify(c.previousValue);
} else {
minMaxSlider.SetValueWithoutNotify(new UnityEngine.Vector2(c.newValue, minMaxSlider.maxValue));
}
c.StopPropagation();
});
minFloatField.isDelayed = true;
minFloatField.style.width = 50;
horizontalLayout.Add(minFloatField);
minMaxSlider.RegisterValueChangedCallback(c =>
{
if (!input.OnChangeEvent(new MinMaxFloat(c.newValue.x, c.newValue.y))) {
minMaxSlider.SetValueWithoutNotify(c.previousValue);
} else {
minFloatField.SetValueWithoutNotify(c.previousValue.x);
maxFloatField.SetValueWithoutNotify(c.previousValue.y);
}
c.StopPropagation();
});
// Ensure the control is kept up to date as the value changes.
Action<object> onBindingUpdateEvent = (object newValue) =>
{
var newMinMaxValue = (MinMaxFloat)newValue;
minMaxSlider.SetValueWithoutNotify(new UnityEngine.Vector2(newMinMaxValue.MinValue, newMinMaxValue.MaxValue));
minFloatField.SetValueWithoutNotify(newMinMaxValue.MinValue);
maxFloatField.SetValueWithoutNotify(newMinMaxValue.MaxValue);
};
minMaxSlider.RegisterCallback<AttachToPanelEvent>(c =>
{
BindingUpdater.AddBinding(input.Field, input.ArrayIndex, input.Target, onBindingUpdateEvent);
});
minMaxSlider.RegisterCallback<DetachFromPanelEvent>(c =>
{
BindingUpdater.RemoveBinding(onBindingUpdateEvent);
});
minMaxSlider.style.flexGrow = 1;
horizontalLayout.Add(minMaxSlider);
maxFloatField.value = minMaxValue.MaxValue;
maxFloatField.RegisterValueChangedCallback(c =>
{
if (!input.OnChangeEvent(new MinMaxFloat(minMaxSlider.minValue, c.newValue))) {
maxFloatField.SetValueWithoutNotify(c.previousValue);
} else {
minMaxSlider.SetValueWithoutNotify(new UnityEngine.Vector2(minMaxSlider.minValue, c.newValue));
}
c.StopPropagation();
});
maxFloatField.isDelayed = true;
maxFloatField.style.width = 50f;
maxFloatField.style.marginRight = 0f;
horizontalLayout.Add(maxFloatField);
return horizontalLayout;
}
}
}