You're breathtaking!
This commit is contained in:
175
Source/Editor/GUI/Input/ColorValueBox.cs
Normal file
175
Source/Editor/GUI/Input/ColorValueBox.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.GUI.Dialogs;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Color value editor with picking support.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEngine.GUI.Control" />
|
||||
[HideInEditor]
|
||||
public class ColorValueBox : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate function used for the color picker events handling.
|
||||
/// </summary>
|
||||
/// <param name="color">The selected color.</param>
|
||||
/// <param name="sliding">True if user is using a slider, otherwise false.</param>
|
||||
public delegate void ColorPickerEvent(Color color, bool sliding);
|
||||
|
||||
/// <summary>
|
||||
/// Delegate function used for the color picker close event handling.
|
||||
/// </summary>
|
||||
public delegate void ColorPickerClosedEvent();
|
||||
|
||||
/// <summary>
|
||||
/// Delegate function used to handle showing color picking dialog.
|
||||
/// </summary>
|
||||
/// <param name="targetControl">The GUI control that invokes the picker.</param>
|
||||
/// <param name="initialValue">The initial value.</param>
|
||||
/// <param name="colorChanged">The color changed event.</param>
|
||||
/// <param name="pickerClosed">The color editing end event.</param>
|
||||
/// <param name="useDynamicEditing">True if allow dynamic value editing (slider-like usage), otherwise will fire color change event only on editing end.</param>
|
||||
/// <returns>The created color picker dialog or null if failed.</returns>
|
||||
public delegate IColorPickerDialog ShowPickColorDialogDelegate(Control targetControl, Color initialValue, ColorPickerEvent colorChanged, ColorPickerClosedEvent pickerClosed = null, bool useDynamicEditing = true);
|
||||
|
||||
/// <summary>
|
||||
/// Shows picking color dialog (see <see cref="ShowPickColorDialogDelegate"/>).
|
||||
/// </summary>
|
||||
public static ShowPickColorDialogDelegate ShowPickColorDialog;
|
||||
|
||||
/// <summary>
|
||||
/// The current opened dialog.
|
||||
/// </summary>
|
||||
protected IColorPickerDialog _currentDialog;
|
||||
|
||||
/// <summary>
|
||||
/// True if slider is in use.
|
||||
/// </summary>
|
||||
protected bool _isSliding;
|
||||
|
||||
/// <summary>
|
||||
/// The value.
|
||||
/// </summary>
|
||||
protected Color _value;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when value gets changed.
|
||||
/// </summary>
|
||||
public event Action ValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when value gets changed.
|
||||
/// </summary>
|
||||
public event Action<ColorValueBox> ColorValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color value.
|
||||
/// </summary>
|
||||
public Color Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
if (_value != value)
|
||||
{
|
||||
_value = value;
|
||||
|
||||
// Fire event
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user is using a slider.
|
||||
/// </summary>
|
||||
public bool IsSliding => _isSliding;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorValueBox"/> class.
|
||||
/// </summary>
|
||||
public ColorValueBox()
|
||||
: base(0, 0, 32, 18)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorValueBox"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The initial value.</param>
|
||||
/// <param name="x">The x location</param>
|
||||
/// <param name="y">The y location</param>
|
||||
public ColorValueBox(Color value, float x, float y)
|
||||
: base(x, y, 32, 18)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when value gets changed.
|
||||
/// </summary>
|
||||
protected virtual void OnValueChanged()
|
||||
{
|
||||
ValueChanged?.Invoke();
|
||||
ColorValueChanged?.Invoke(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
var style = Style.Current;
|
||||
var r = new Rectangle(2, 2, Width - 4, Height - 4);
|
||||
|
||||
Render2D.FillRectangle(r, _value);
|
||||
Render2D.DrawRectangle(r, IsMouseOver ? style.BackgroundSelected : Color.Black);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
// Show color picker dialog
|
||||
_currentDialog = ShowPickColorDialog?.Invoke(this, _value, OnColorChanged, OnPickerClosed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnColorChanged(Color color, bool sliding)
|
||||
{
|
||||
// Force send ValueChanged event is sliding state gets modified by the color picker (e.g the color picker window closing event)
|
||||
if (_isSliding != sliding)
|
||||
{
|
||||
_isSliding = sliding;
|
||||
_value = color;
|
||||
OnValueChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = color;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPickerClosed()
|
||||
{
|
||||
_currentDialog = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (_currentDialog != null)
|
||||
{
|
||||
_currentDialog.ClosePicker();
|
||||
_currentDialog = null;
|
||||
}
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
167
Source/Editor/GUI/Input/DoubleValueBox.cs
Normal file
167
Source/Editor/GUI/Input/DoubleValueBox.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Double precision floating point value editor.
|
||||
/// </summary>
|
||||
/// <seealso cref="double" />
|
||||
[HideInEditor]
|
||||
public class DoubleValueBox : ValueBox<double>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override double Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, _min, _max);
|
||||
if (Math.Abs(_value - value) > Mathf.Epsilon)
|
||||
{
|
||||
// Set value
|
||||
_value = value;
|
||||
|
||||
// Update
|
||||
UpdateText();
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override double MinValue
|
||||
{
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_min, value))
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
|
||||
_min = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override double MaxValue
|
||||
{
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_max, value))
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
_max = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FloatValueBox"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="x">The x location.</param>
|
||||
/// <param name="y">The y location.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="min">The minimum value.</param>
|
||||
/// <param name="max">The maximum value.</param>
|
||||
/// <param name="slideSpeed">The slide speed.</param>
|
||||
public DoubleValueBox(double value, float x = 0, float y = 0, float width = 120, double min = double.MinValue, double max = double.MaxValue, float slideSpeed = 1)
|
||||
: base(Mathf.Clamp(value, min, max), x, y, width, min, max, slideSpeed)
|
||||
{
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value limits.
|
||||
/// </summary>
|
||||
/// <param name="min">The minimum value (bottom range).</param>
|
||||
/// <param name="max">The maximum value (upper range).</param>
|
||||
public void SetLimits(double min, double max)
|
||||
{
|
||||
_min = min;
|
||||
_max = Math.Max(_min, max);
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(RangeAttribute limits)
|
||||
{
|
||||
_min = limits.Min;
|
||||
_max = Math.Max(_min, limits.Max);
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(LimitAttribute limits)
|
||||
{
|
||||
_min = limits.Min;
|
||||
_max = Math.Max(_min, (double)limits.Max);
|
||||
_slideSpeed = limits.SliderSpeed;
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the other <see cref="DoubleValueBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="other">The other.</param>
|
||||
public void SetLimits(DoubleValueBox other)
|
||||
{
|
||||
_min = other._min;
|
||||
_max = other._max;
|
||||
_slideSpeed = other._slideSpeed;
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected sealed override void UpdateText()
|
||||
{
|
||||
string text;
|
||||
if (double.IsPositiveInfinity(_value) || _value == double.MaxValue)
|
||||
text = "Infinity";
|
||||
else if (double.IsNegativeInfinity(_value) || _value == double.MinValue)
|
||||
text = "-Infinity";
|
||||
else
|
||||
text = _value.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void TryGetValue()
|
||||
{
|
||||
try
|
||||
{
|
||||
Value = ShuntingYard.Parse(Text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fall back to previous value
|
||||
Editor.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ApplySliding(float delta)
|
||||
{
|
||||
Value = _startSlideValue + delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
168
Source/Editor/GUI/Input/FloatValueBox.cs
Normal file
168
Source/Editor/GUI/Input/FloatValueBox.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Floating point value editor.
|
||||
/// </summary>
|
||||
/// <seealso cref="float" />
|
||||
[HideInEditor]
|
||||
public class FloatValueBox : ValueBox<float>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override float Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, _min, _max);
|
||||
if (Math.Abs(_value - value) > Mathf.Epsilon)
|
||||
{
|
||||
// Set value
|
||||
_value = value;
|
||||
|
||||
// Update
|
||||
UpdateText();
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override float MinValue
|
||||
{
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_min, value))
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
|
||||
_min = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override float MaxValue
|
||||
{
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_max, value))
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
_max = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FloatValueBox"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="x">The x location.</param>
|
||||
/// <param name="y">The y location.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="min">The minimum value.</param>
|
||||
/// <param name="max">The maximum value.</param>
|
||||
/// <param name="slideSpeed">The slide speed.</param>
|
||||
public FloatValueBox(float value, float x = 0, float y = 0, float width = 120, float min = float.MinValue, float max = float.MaxValue, float slideSpeed = 1)
|
||||
: base(Mathf.Clamp(value, min, max), x, y, width, min, max, slideSpeed)
|
||||
{
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value limits.
|
||||
/// </summary>
|
||||
/// <param name="min">The minimum value (bottom range).</param>
|
||||
/// <param name="max">The maximum value (upper range).</param>
|
||||
public void SetLimits(float min, float max)
|
||||
{
|
||||
_min = min;
|
||||
_max = Mathf.Max(_min, max);
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(RangeAttribute limits)
|
||||
{
|
||||
_min = limits.Min;
|
||||
_max = Mathf.Max(_min, limits.Max);
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(LimitAttribute limits)
|
||||
{
|
||||
_min = limits.Min;
|
||||
_max = Mathf.Max(_min, limits.Max);
|
||||
_slideSpeed = limits.SliderSpeed;
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the other <see cref="FloatValueBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="other">The other.</param>
|
||||
public void SetLimits(FloatValueBox other)
|
||||
{
|
||||
_min = other._min;
|
||||
_max = other._max;
|
||||
_slideSpeed = other._slideSpeed;
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected sealed override void UpdateText()
|
||||
{
|
||||
string text;
|
||||
if (float.IsPositiveInfinity(_value) || _value == float.MaxValue)
|
||||
text = "Infinity";
|
||||
else if (float.IsNegativeInfinity(_value) || _value == float.MinValue)
|
||||
text = "-Infinity";
|
||||
else
|
||||
text = _value.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void TryGetValue()
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = ShuntingYard.Parse(Text);
|
||||
Value = (float)Math.Round(value, 5);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fall back to previous value
|
||||
Editor.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ApplySliding(float delta)
|
||||
{
|
||||
Value = _startSlideValue + delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
161
Source/Editor/GUI/Input/IntValueBox.cs
Normal file
161
Source/Editor/GUI/Input/IntValueBox.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Integer value editor.
|
||||
/// </summary>
|
||||
/// <seealso cref="int" />
|
||||
[HideInEditor]
|
||||
public class IntValueBox : ValueBox<int>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override int Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, _min, _max);
|
||||
if (_value != value)
|
||||
{
|
||||
// Set value
|
||||
_value = value;
|
||||
|
||||
// Update
|
||||
UpdateText();
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int MinValue
|
||||
{
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (_min != value)
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
|
||||
_min = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int MaxValue
|
||||
{
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (_max != value)
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
_max = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IntValueBox"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="x">The x location.</param>
|
||||
/// <param name="y">The y location.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="min">The minimum value.</param>
|
||||
/// <param name="max">The maximum value.</param>
|
||||
/// <param name="slideSpeed">The slide speed.</param>
|
||||
public IntValueBox(int value, float x = 0, float y = 0, float width = 120, int min = int.MinValue, int max = int.MaxValue, float slideSpeed = 1)
|
||||
: base(Mathf.Clamp(value, min, max), x, y, width, min, max, slideSpeed)
|
||||
{
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value limits.
|
||||
/// </summary>
|
||||
/// <param name="min">The minimum value (bottom range).</param>
|
||||
/// <param name="max">The maximum value (upper range).</param>
|
||||
public void SetLimits(int min, int max)
|
||||
{
|
||||
_min = min;
|
||||
_max = Mathf.Max(_min, max);
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(RangeAttribute limits)
|
||||
{
|
||||
_min = limits.Min == float.MinValue ? int.MinValue : (int)limits.Min;
|
||||
_max = Math.Max(_min, limits.Max == float.MaxValue ? int.MaxValue : (int)limits.Max);
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(LimitAttribute limits)
|
||||
{
|
||||
_min = limits.Min == float.MinValue ? int.MinValue : (int)limits.Min;
|
||||
_max = Math.Max(_min, limits.Max == float.MaxValue ? int.MaxValue : (int)limits.Max);
|
||||
_slideSpeed = limits.SliderSpeed;
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the other <see cref="IntValueBox"/>.
|
||||
/// </summary>
|
||||
/// <param name="other">The other.</param>
|
||||
public void SetLimits(IntValueBox other)
|
||||
{
|
||||
_min = other._min;
|
||||
_max = other._max;
|
||||
_slideSpeed = other._slideSpeed;
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected sealed override void UpdateText()
|
||||
{
|
||||
var text = _value.ToString();
|
||||
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void TryGetValue()
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = ShuntingYard.Parse(Text);
|
||||
Value = (int)value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fall back to previous value
|
||||
Editor.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ApplySliding(float delta)
|
||||
{
|
||||
Value = _startSlideValue + (int)delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
122
Source/Editor/GUI/Input/LongValueBox.cs
Normal file
122
Source/Editor/GUI/Input/LongValueBox.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Integer (long type) value editor.
|
||||
/// </summary>
|
||||
/// <seealso cref="long" />
|
||||
[HideInEditor]
|
||||
public class LongValueBox : ValueBox<long>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override long Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, _min, _max);
|
||||
if (_value != value)
|
||||
{
|
||||
// Set value
|
||||
_value = value;
|
||||
|
||||
// Update
|
||||
UpdateText();
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override long MinValue
|
||||
{
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (_min != value)
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
|
||||
_min = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override long MaxValue
|
||||
{
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (_max != value)
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
_max = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LongValueBox"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="x">The x location.</param>
|
||||
/// <param name="y">The y location.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="min">The minimum value.</param>
|
||||
/// <param name="max">The maximum value.</param>
|
||||
/// <param name="slideSpeed">The slide speed.</param>
|
||||
public LongValueBox(long value, float x = 0, float y = 0, float width = 120, long min = long.MinValue, long max = long.MaxValue, float slideSpeed = 1)
|
||||
: base(Mathf.Clamp(value, min, max), x, y, width, min, max, slideSpeed)
|
||||
{
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(LimitAttribute limits)
|
||||
{
|
||||
_min = limits.Min == int.MinValue ? long.MinValue : (long)limits.Min;
|
||||
_max = Math.Max(_min, limits.Max == int.MaxValue ? long.MaxValue : (long)limits.Max);
|
||||
_slideSpeed = limits.SliderSpeed;
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected sealed override void UpdateText()
|
||||
{
|
||||
var text = _value.ToString();
|
||||
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void TryGetValue()
|
||||
{
|
||||
// Try to parse long
|
||||
long value;
|
||||
if (long.TryParse(Text, out value))
|
||||
{
|
||||
// Set value
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ApplySliding(float delta)
|
||||
{
|
||||
Value = _startSlideValue + (long)delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
456
Source/Editor/GUI/Input/SliderControl.cs
Normal file
456
Source/Editor/GUI/Input/SliderControl.cs
Normal file
@@ -0,0 +1,456 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Float value editor with fixed size text box and slider.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public class SliderControl : ContainerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// The horizontal slider control.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEngine.GUI.Control" />
|
||||
[HideInEditor]
|
||||
protected class Slider : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// The default size.
|
||||
/// </summary>
|
||||
public const int DefaultSize = 16;
|
||||
|
||||
/// <summary>
|
||||
/// The default thickness.
|
||||
/// </summary>
|
||||
public const int DefaultThickness = 6;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum value (constant)
|
||||
/// </summary>
|
||||
public const float Minimum = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum value (constant).
|
||||
/// </summary>
|
||||
public const float Maximum = 100.0f;
|
||||
|
||||
private float _value;
|
||||
private Rectangle _thumbRect;
|
||||
private float _thumbCenter, _thumbSize;
|
||||
private bool _isSliding;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value (normalized to range 0-100).
|
||||
/// </summary>
|
||||
public float Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, Minimum, Maximum);
|
||||
if (!Mathf.NearEqual(value, _value))
|
||||
{
|
||||
_value = value;
|
||||
|
||||
// Update
|
||||
UpdateThumb();
|
||||
ValueChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when value gets changed.
|
||||
/// </summary>
|
||||
public Action ValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The color of the slider track line
|
||||
/// </summary>
|
||||
public Color TrackLineColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The color of the slider thumb when it's not selected
|
||||
/// </summary>
|
||||
public Color ThumbColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The color of the slider thumb when it's selected
|
||||
/// </summary>
|
||||
public Color ThumbColorSelected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user is using a slider.
|
||||
/// </summary>
|
||||
public bool IsSliding => _isSliding;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when sliding starts.
|
||||
/// </summary>
|
||||
public Action SlidingStart;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when sliding ends.
|
||||
/// </summary>
|
||||
public Action SlidingEnd;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Slider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
public Slider(float width, float height)
|
||||
: base(0, 0, width, height)
|
||||
{
|
||||
var style = Style.Current;
|
||||
TrackLineColor = style.BackgroundHighlighted;
|
||||
ThumbColor = style.BackgroundNormal;
|
||||
ThumbColorSelected = style.BackgroundSelected;
|
||||
}
|
||||
|
||||
private void UpdateThumb()
|
||||
{
|
||||
// Cache data
|
||||
float trackSize = TrackSize;
|
||||
float range = Maximum - Minimum;
|
||||
_thumbSize = Mathf.Min(trackSize, Mathf.Max(trackSize / range * 10.0f, 30.0f));
|
||||
float pixelRange = trackSize - _thumbSize;
|
||||
float perc = (_value - Minimum) / range;
|
||||
float thumbPosition = (int)(perc * pixelRange);
|
||||
_thumbCenter = thumbPosition + _thumbSize / 2;
|
||||
_thumbRect = new Rectangle(thumbPosition + 4, (Height - DefaultThickness) / 2, _thumbSize - 8, DefaultThickness);
|
||||
}
|
||||
|
||||
private void EndSliding()
|
||||
{
|
||||
_isSliding = false;
|
||||
EndMouseCapture();
|
||||
SlidingEnd?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the track.
|
||||
/// </summary>
|
||||
private float TrackSize => Width;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
// Draw track line
|
||||
var lineRect = new Rectangle(4, Height / 2, Width - 8, 1);
|
||||
Render2D.FillRectangle(lineRect, TrackLineColor);
|
||||
|
||||
// Draw thumb
|
||||
Render2D.FillRectangle(_thumbRect, _isSliding ? ThumbColorSelected : ThumbColor);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
if (_isSliding)
|
||||
{
|
||||
EndSliding();
|
||||
}
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Vector2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
float mousePosition = location.X;
|
||||
|
||||
if (_thumbRect.Contains(ref location))
|
||||
{
|
||||
// Start sliding
|
||||
_isSliding = true;
|
||||
StartMouseCapture();
|
||||
SlidingStart?.Invoke();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Click change
|
||||
Value += (mousePosition < _thumbCenter ? -1 : 1) * 10;
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Vector2 location)
|
||||
{
|
||||
if (_isSliding)
|
||||
{
|
||||
// Update sliding
|
||||
Vector2 slidePosition = location + Root.TrackingMouseOffset;
|
||||
Value = Mathf.Map(slidePosition.X, 4, TrackSize - 4, Minimum, Maximum);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _isSliding)
|
||||
{
|
||||
// End sliding
|
||||
EndSliding();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
// Check if was sliding
|
||||
if (_isSliding)
|
||||
{
|
||||
EndSliding();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnEndMouseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSizeChanged()
|
||||
{
|
||||
base.OnSizeChanged();
|
||||
|
||||
UpdateThumb();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The slider.
|
||||
/// </summary>
|
||||
protected Slider _slider;
|
||||
|
||||
/// <summary>
|
||||
/// The text box.
|
||||
/// </summary>
|
||||
protected TextBox _textBox;
|
||||
|
||||
/// <summary>
|
||||
/// The text box size (rest will be the slider area).
|
||||
/// </summary>
|
||||
protected const float TextBoxSize = 30.0f;
|
||||
|
||||
private float _value;
|
||||
private float _min, _max;
|
||||
|
||||
private bool _valueIsChanging;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when value gets changed.
|
||||
/// </summary>
|
||||
public event Action ValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
public float Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, _min, _max);
|
||||
if (Math.Abs(_value - value) > Mathf.Epsilon)
|
||||
{
|
||||
// Set value
|
||||
_value = value;
|
||||
|
||||
// Update
|
||||
_valueIsChanging = true;
|
||||
UpdateText();
|
||||
UpdateSlider();
|
||||
_valueIsChanging = false;
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum value.
|
||||
/// </summary>
|
||||
public float MinValue
|
||||
{
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_min, value))
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
|
||||
_min = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum value.
|
||||
/// </summary>
|
||||
public float MaxValue
|
||||
{
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_max, value))
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
_max = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user is using a slider.
|
||||
/// </summary>
|
||||
public bool IsSliding => _slider.IsSliding;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when sliding starts.
|
||||
/// </summary>
|
||||
public event Action SlidingStart;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when sliding ends.
|
||||
/// </summary>
|
||||
public event Action SlidingEnd;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SliderControl"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="x">The position x.</param>
|
||||
/// <param name="y">The position y.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="min">The minimum value.</param>
|
||||
/// <param name="max">The maximum value.</param>
|
||||
public SliderControl(float value, float x = 0, float y = 0, float width = 120, float min = float.MinValue, float max = float.MaxValue)
|
||||
: base(x, y, width, TextBox.DefaultHeight)
|
||||
{
|
||||
_min = min;
|
||||
_max = max;
|
||||
_value = Mathf.Clamp(value, min, max);
|
||||
|
||||
float split = Width - TextBoxSize;
|
||||
_slider = new Slider(split, Height)
|
||||
{
|
||||
Parent = this,
|
||||
};
|
||||
_slider.ValueChanged += SliderOnValueChanged;
|
||||
_slider.SlidingStart += SlidingStart;
|
||||
_slider.SlidingEnd += SlidingEnd;
|
||||
_textBox = new TextBox(false, split, 0)
|
||||
{
|
||||
Text = _value.ToString(CultureInfo.InvariantCulture),
|
||||
Parent = this,
|
||||
Location = new Vector2(split, 0),
|
||||
Size = new Vector2(Height, TextBoxSize),
|
||||
};
|
||||
_textBox.EditEnd += OnTextBoxEditEnd;
|
||||
}
|
||||
|
||||
private void SliderOnValueChanged()
|
||||
{
|
||||
if (_valueIsChanging)
|
||||
return;
|
||||
|
||||
Value = Mathf.Map(_slider.Value, Slider.Minimum, Slider.Maximum, MinValue, MaxValue);
|
||||
}
|
||||
|
||||
private void OnTextBoxEditEnd()
|
||||
{
|
||||
if (_valueIsChanging)
|
||||
return;
|
||||
|
||||
var text = _textBox.Text.Replace(',', '.');
|
||||
if (double.TryParse(text, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var value))
|
||||
{
|
||||
Value = (float)Math.Round(value, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateText();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(RangeAttribute limits)
|
||||
{
|
||||
_min = limits.Min;
|
||||
_max = Mathf.Max(_min, limits.Max);
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the text of the textbox.
|
||||
/// </summary>
|
||||
protected virtual void UpdateText()
|
||||
{
|
||||
_textBox.Text = _value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the slider value.
|
||||
/// </summary>
|
||||
protected virtual void UpdateSlider()
|
||||
{
|
||||
_slider.Value = Mathf.Map(_value, MinValue, MaxValue, Slider.Minimum, Slider.Maximum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when value gets changed.
|
||||
/// </summary>
|
||||
protected virtual void OnValueChanged()
|
||||
{
|
||||
ValueChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void PerformLayoutBeforeChildren()
|
||||
{
|
||||
base.PerformLayoutBeforeChildren();
|
||||
|
||||
float split = Width - TextBoxSize;
|
||||
_slider.Bounds = new Rectangle(0, 0, split, Height);
|
||||
_textBox.Bounds = new Rectangle(split, 0, TextBoxSize, Height);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
_slider = null;
|
||||
_textBox = null;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
132
Source/Editor/GUI/Input/ULongValueBox.cs
Normal file
132
Source/Editor/GUI/Input/ULongValueBox.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Unsigned integer (ulong type) value editor.
|
||||
/// </summary>
|
||||
/// <seealso cref="ulong" />
|
||||
[HideInEditor]
|
||||
public class ULongValueBox : ValueBox<ulong>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override ulong Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, _min, _max);
|
||||
if (_value != value)
|
||||
{
|
||||
// Set value
|
||||
_value = value;
|
||||
|
||||
// Update
|
||||
UpdateText();
|
||||
OnValueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ulong MinValue
|
||||
{
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (_min != value)
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
|
||||
_min = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ulong MaxValue
|
||||
{
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (_max != value)
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
_max = value;
|
||||
Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ULongValueBox"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="x">The x location.</param>
|
||||
/// <param name="y">The y location.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="min">The minimum value.</param>
|
||||
/// <param name="max">The maximum value.</param>
|
||||
/// <param name="slideSpeed">The slide speed.</param>
|
||||
public ULongValueBox(ulong value, float x = 0, float y = 0, float width = 120, ulong min = ulong.MinValue, ulong max = ulong.MaxValue, float slideSpeed = 1)
|
||||
: base(Mathf.Clamp(value, min, max), x, y, width, min, max, slideSpeed)
|
||||
{
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(LimitAttribute limits)
|
||||
{
|
||||
_min = limits.Min == int.MinValue ? ulong.MinValue : (ulong)limits.Min;
|
||||
_max = Math.Max(_min, limits.Max == int.MaxValue ? ulong.MaxValue : (ulong)limits.Max);
|
||||
_slideSpeed = limits.SliderSpeed;
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected sealed override void UpdateText()
|
||||
{
|
||||
var text = _value.ToString();
|
||||
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void TryGetValue()
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = ShuntingYard.Parse(Text);
|
||||
Value = (ulong)value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Fall back to previous value
|
||||
Editor.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ApplySliding(float delta)
|
||||
{
|
||||
// Check for negative overflow to positive numbers
|
||||
if (delta < 0 && _startSlideValue > delta)
|
||||
Value = (ulong)Mathf.Max(0, (long)_startSlideValue + (long)delta);
|
||||
else if (delta < 0)
|
||||
Value = _startSlideValue - (ulong)(-delta);
|
||||
else
|
||||
Value = _startSlideValue + (ulong)delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
311
Source/Editor/GUI/Input/ValueBox.cs
Normal file
311
Source/Editor/GUI/Input/ValueBox.cs
Normal file
@@ -0,0 +1,311 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for text boxes for float/int value editing. Supports slider and range clamping.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The value type.</typeparam>
|
||||
/// <seealso cref="FlaxEngine.GUI.TextBox" />
|
||||
[HideInEditor]
|
||||
public abstract class ValueBox<T> : TextBox where T : struct, IComparable<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// The sliding box size.
|
||||
/// </summary>
|
||||
protected const float SlidingBoxSize = 12.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The current value.
|
||||
/// </summary>
|
||||
protected T _value;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum value.
|
||||
/// </summary>
|
||||
protected T _min;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum value.
|
||||
/// </summary>
|
||||
protected T _max;
|
||||
|
||||
/// <summary>
|
||||
/// The slider speed.
|
||||
/// </summary>
|
||||
protected float _slideSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// True if slider is in use.
|
||||
/// </summary>
|
||||
protected bool _isSliding;
|
||||
|
||||
/// <summary>
|
||||
/// The value cached on sliding start.
|
||||
/// </summary>
|
||||
protected T _startSlideValue;
|
||||
|
||||
private Vector2 _startSlideLocation;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when value gets changed.
|
||||
/// </summary>
|
||||
public event Action ValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when value gets changed.
|
||||
/// </summary>
|
||||
public event Action<ValueBox<T>> BoxValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
public abstract T Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum value.
|
||||
/// </summary>
|
||||
public abstract T MinValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum value.
|
||||
/// </summary>
|
||||
public abstract T MaxValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user is using a slider.
|
||||
/// </summary>
|
||||
public bool IsSliding => _isSliding;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when sliding starts.
|
||||
/// </summary>
|
||||
public event Action SlidingStart;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when sliding ends.
|
||||
/// </summary>
|
||||
public event Action SlidingEnd;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the slider speed. Use value 0 to disable and hide slider UI.
|
||||
/// </summary>
|
||||
public float SlideSpeed
|
||||
{
|
||||
get => _slideSpeed;
|
||||
set => _slideSpeed = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ValueBox{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="min">The minimum.</param>
|
||||
/// <param name="max">The maximum.</param>
|
||||
/// <param name="sliderSpeed">The slider speed.</param>
|
||||
protected ValueBox(T value, float x, float y, float width, T min, T max, float sliderSpeed)
|
||||
: base(false, x, y, width)
|
||||
{
|
||||
_value = value;
|
||||
_min = min;
|
||||
_max = max;
|
||||
_slideSpeed = sliderSpeed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the text of the textbox.
|
||||
/// </summary>
|
||||
protected abstract void UpdateText();
|
||||
|
||||
/// <summary>
|
||||
/// Tries the get value from the textbox text.
|
||||
/// </summary>
|
||||
protected abstract void TryGetValue();
|
||||
|
||||
/// <summary>
|
||||
/// Applies the sliding delta to the value.
|
||||
/// </summary>
|
||||
/// <param name="delta">The delta (scaled).</param>
|
||||
protected abstract void ApplySliding(float delta);
|
||||
|
||||
/// <summary>
|
||||
/// Called when value gets changed.
|
||||
/// </summary>
|
||||
protected virtual void OnValueChanged()
|
||||
{
|
||||
ValueChanged?.Invoke();
|
||||
BoxValueChanged?.Invoke(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this value box can use sliding.
|
||||
/// </summary>
|
||||
protected virtual bool CanUseSliding => _slideSpeed > Mathf.Epsilon;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the slide rectangle.
|
||||
/// </summary>
|
||||
protected virtual Rectangle SlideRect
|
||||
{
|
||||
get
|
||||
{
|
||||
float x = Width - SlidingBoxSize - 1.0f;
|
||||
float y = (Height - SlidingBoxSize) * 0.5f;
|
||||
return new Rectangle(x, y, SlidingBoxSize, SlidingBoxSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void EndSliding()
|
||||
{
|
||||
_isSliding = false;
|
||||
EndMouseCapture();
|
||||
SlidingEnd?.Invoke();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
if (CanUseSliding)
|
||||
{
|
||||
var style = Style.Current;
|
||||
|
||||
// Draw sliding UI
|
||||
Render2D.DrawSprite(style.Scale, SlideRect, style.Foreground);
|
||||
|
||||
// Check if is sliding
|
||||
if (_isSliding)
|
||||
{
|
||||
// Draw overlay
|
||||
// TODO: render nicer overlay with some glow from the borders (inside)
|
||||
Render2D.FillRectangle(new Rectangle(Vector2.Zero, Size), Color.Orange * 0.3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
// Check if was sliding
|
||||
if (_isSliding)
|
||||
{
|
||||
EndSliding();
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnLostFocus();
|
||||
|
||||
// Update
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
ResetViewOffset();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Vector2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && CanUseSliding && SlideRect.Contains(location))
|
||||
{
|
||||
// Start sliding
|
||||
_isSliding = true;
|
||||
_startSlideLocation = location;
|
||||
_startSlideValue = _value;
|
||||
StartMouseCapture(true);
|
||||
SlidingStart?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Vector2 location)
|
||||
{
|
||||
if (_isSliding)
|
||||
{
|
||||
// Update sliding
|
||||
Vector2 slideLocation = location + Root.TrackingMouseOffset;
|
||||
ApplySliding(Mathf.RoundToInt(slideLocation.X - _startSlideLocation.X) * _slideSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _isSliding)
|
||||
{
|
||||
// End sliding
|
||||
EndSliding();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnEditEnd()
|
||||
{
|
||||
// Update value
|
||||
TryGetValue();
|
||||
|
||||
base.OnEditEnd();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
// Check if was sliding
|
||||
if (_isSliding)
|
||||
{
|
||||
EndSliding();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnEndMouseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Rectangle TextRectangle
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = base.TextRectangle;
|
||||
if (CanUseSliding)
|
||||
{
|
||||
result.Size.X -= SlidingBoxSize;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Rectangle TextClipRectangle
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = base.TextRectangle;
|
||||
if (CanUseSliding)
|
||||
{
|
||||
result.Size.X -= SlidingBoxSize;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user