diff --git a/Source/Engine/UI/GUI/Common/Slider.cs b/Source/Engine/UI/GUI/Common/Slider.cs
new file mode 100644
index 000000000..06c73f15e
--- /dev/null
+++ b/Source/Engine/UI/GUI/Common/Slider.cs
@@ -0,0 +1,347 @@
+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;
+
+ ///
+ /// 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 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 selected
+ ///
+ [EditorDisplay("Thumb Style"), EditorOrder(2031), 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(2032), 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;
+ 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 : 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)
+ {
+ 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();
+ }
+}