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