using System;
namespace FlaxEngine.GUI;
///
/// The slider control.
///
public class Slider : ContainerControl
{
///
/// The minimum value.
///
protected float _minimum;
///
/// The maximum value.
///
protected float _maximum = 100f;
///
/// Gets or sets the minimum value.
///
[EditorOrder(20), Tooltip("The minimum value.")]
public float Minimum
{
get => _minimum;
set
{
if (value > _maximum)
throw new ArgumentOutOfRangeException();
if (WholeNumbers)
value = Mathf.RoundToInt(value);
_minimum = value;
if (Value < _minimum)
Value = _minimum;
}
}
///
/// Gets or sets the maximum value.
///
[EditorOrder(30), Tooltip("The maximum value.")]
public float Maximum
{
get => _maximum;
set
{
if (value < _minimum || Mathf.IsZero(value))
throw new ArgumentOutOfRangeException();
if (WholeNumbers)
value = Mathf.RoundToInt(value);
_maximum = value;
if (Value > _maximum)
Value = _maximum;
}
}
private float _value = 100f;
private Rectangle _thumbRect;
private float _thumbCenter;
private Float2 _thumbSize = new Float2(16, 16);
private bool _isSliding;
private bool _mouseOverThumb;
///
/// Gets or sets the value (normalized to range 0-100).
///
[EditorOrder(10), Tooltip("The current value.")]
public float Value
{
get => _value;
set
{
value = Mathf.Clamp(value, Minimum, Maximum);
if (WholeNumbers)
value = Mathf.RoundToInt(value);
if (!Mathf.NearEqual(value, _value))
{
_value = value;
// Update
UpdateThumb();
ValueChanged?.Invoke();
}
}
}
///
/// The local position of the thumb center
///
[HideInEditor]
public Float2 ThumbCenter => new(_thumbCenter, Height / 2);
///
/// The local position of the beginning of the track.
///
[HideInEditor]
public Float2 TrackBeginning => new(_thumbSize.X / 2, Height / 2);
///
/// The local position of the end of the track.
///
[HideInEditor]
public Float2 TrackEnd => new(Width - _thumbSize.X / 2, Height / 2);
///
/// The height of the track.
///
[EditorOrder(40), Tooltip("The track height.")]
public int TrackHeight { get; set; } = 2;
///
/// The thumb size.
///
[EditorOrder(41), Tooltip("The size of the thumb.")]
public Float2 ThumbSize {
get => _thumbSize;
set
{
_thumbSize = value;
UpdateThumb();
}
}
///
/// Whether to fill the track.
///
[EditorOrder(42), Tooltip("Fill the track.")]
public bool FillTrack = true;
///
/// Whether to use whole numbers.
///
[EditorOrder(43), Tooltip("Use whole numbers.")]
public bool WholeNumbers = false;
///
/// The color of the slider track line
///
[EditorDisplay("Track Style"), EditorOrder(2010), Tooltip("The color of the slider track line."), ExpandGroups]
public Color TrackLineColor { get; set; }
///
/// The color of the slider fill track line
///
[EditorDisplay("Track Style"), EditorOrder(2011), VisibleIf(nameof(FillTrack)), Tooltip("The color of the slider fill track line.")]
public Color TrackFillLineColor { get; set; }
///
/// Gets the size of the track.
///
private float TrackWidth => Width;
///
/// Gets or sets the brush used for slider track drawing.
///
[EditorDisplay("Track Style"), EditorOrder(2012), Tooltip("The brush used for slider track drawing.")]
public IBrush TrackBrush { get; set; }
///
/// Gets or sets the brush used for slider fill track drawing.
///
[EditorDisplay("Track Style"), EditorOrder(2013), VisibleIf(nameof(FillTrack)), Tooltip("The brush used for slider fill track drawing.")]
public IBrush FillTrackBrush { get; set; }
///
/// The color of the slider thumb when it's not selected.
///
[EditorDisplay("Thumb Style"), EditorOrder(2030), Tooltip("The color of the slider thumb when it's not selected."), ExpandGroups]
public Color ThumbColor { get; set; }
///
/// The color of the slider thumb when it's highlighted.
///
[EditorDisplay("Thumb Style"), EditorOrder(2031), Tooltip("The color of the slider thumb when it's highlighted.")]
public Color ThumbColorHighlighted { get; set; }
///
/// The color of the slider thumb when it's selected.
///
[EditorDisplay("Thumb Style"), EditorOrder(2032), Tooltip("The color of the slider thumb when it's selected.")]
public Color ThumbColorSelected { get; set; }
///
/// Gets or sets the brush used for slider thumb drawing.
///
[EditorDisplay("Thumb Style"), EditorOrder(2033), Tooltip("The brush of the slider thumb.")]
public IBrush ThumbBrush { get; set; }
///
/// Gets a value indicating whether user is using a slider.
///
[HideInEditor]
public bool IsSliding => _isSliding;
///
/// Occurs when sliding starts.
///
public event Action SlidingStart;
///
/// Occurs when sliding ends.
///
public event Action SlidingEnd;
///
/// Occurs when value gets changed.
///
public event Action ValueChanged;
///
/// Initializes a new instance of the class.
///
public Slider()
: this(120, 30)
{
}
///
/// Initializes a new instance of the class.
///
/// The width.
/// The height.
public Slider(float width, float height)
: base(0, 0, width, height)
{
var style = Style.Current;
TrackLineColor = style.BackgroundHighlighted;
TrackFillLineColor = style.LightBackground;
ThumbColor = style.BackgroundNormal;
ThumbColorSelected = style.BackgroundSelected;
ThumbColorHighlighted = style.BackgroundHighlighted;
UpdateThumb();
}
private void UpdateThumb()
{
// Cache data
float trackSize = TrackWidth;
float range = Maximum - Minimum;
float pixelRange = trackSize - _thumbSize.X;
float perc = (_value - Minimum) / range;
float thumbPosition = (int)(perc * pixelRange);
_thumbCenter = thumbPosition + _thumbSize.X / 2;
_thumbRect = new Rectangle(thumbPosition, (Height - _thumbSize.Y) / 2, _thumbSize.X, _thumbSize.Y);
}
private void EndSliding()
{
_isSliding = false;
EndMouseCapture();
SlidingEnd?.Invoke();
}
///
public override void Draw()
{
base.Draw();
// Draw track line
//var lineRect = new Rectangle(4, (Height - TrackHeight) / 2, Width - 8, TrackHeight);
var lineRect = new Rectangle(_thumbSize.X / 2, (Height - TrackHeight) / 2, Width - _thumbSize.X, TrackHeight);
if (TrackBrush != null)
TrackBrush.Draw(lineRect, TrackLineColor);
else
Render2D.FillRectangle(lineRect, TrackLineColor);
// Draw track fill
if (FillTrack)
{
var fillLineRect = new Rectangle(_thumbSize.X / 2, (Height - TrackHeight - 2) / 2, Width - (Width - _thumbCenter) - _thumbSize.X / 2, TrackHeight + 2);
Render2D.PushClip(ref fillLineRect);
if (FillTrackBrush != null)
FillTrackBrush.Draw(lineRect, TrackFillLineColor);
else
Render2D.FillRectangle(lineRect, TrackFillLineColor);
Render2D.PopClip();
}
// Draw thumb
var thumbColor = _isSliding ? ThumbColorSelected : (_mouseOverThumb ? ThumbColorHighlighted : ThumbColor);
if (ThumbBrush != null)
ThumbBrush.Draw(_thumbRect, thumbColor);
else
Render2D.FillRectangle(_thumbRect, thumbColor);
}
///
public override void OnLostFocus()
{
if (_isSliding)
{
EndSliding();
}
base.OnLostFocus();
}
///
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (button == MouseButton.Left)
{
Focus();
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);
}
///
public override void OnMouseMove(Float2 location)
{
_mouseOverThumb = _thumbRect.Contains(location);
if (_isSliding)
{
// Update sliding
var slidePosition = location + Root.TrackingMouseOffset;
Value = Mathf.Remap(slidePosition.X, 4, TrackWidth - 4, Minimum, Maximum);
}
else
{
base.OnMouseMove(location);
}
}
///
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _isSliding)
{
EndSliding();
return true;
}
return base.OnMouseUp(location, button);
}
///
public override void OnEndMouseCapture()
{
// Check if was sliding
if (_isSliding)
{
EndSliding();
}
else
{
base.OnEndMouseCapture();
}
}
///
protected override void OnSizeChanged()
{
base.OnSizeChanged();
UpdateThumb();
}
}