diff --git a/Source/Engine/UI/GUI/Common/Slider.cs b/Source/Engine/UI/GUI/Common/Slider.cs index 6dbd5082c..6332088b4 100644 --- a/Source/Engine/UI/GUI/Common/Slider.cs +++ b/Source/Engine/UI/GUI/Common/Slider.cs @@ -7,6 +7,32 @@ namespace FlaxEngine.GUI; /// public class Slider : ContainerControl { + /// + /// The slider direction + /// + public enum SliderDirection + { + /// + /// Slider direction, horizontal right + /// + HorizontalRight, + + /// + /// Slider direction, horizontal left + /// + HorizontalLeft, + + /// + /// Slider direction, vertical up + /// + VerticalUp, + + /// + /// Slider direction, vertical down + /// + VerticalDown, + } + /// /// The minimum value. /// @@ -15,26 +41,7 @@ public class Slider : ContainerControl /// /// 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; - } - } + protected float _maximum = 100; /// /// Gets or sets the maximum value. @@ -45,8 +52,8 @@ public class Slider : ContainerControl get => _maximum; set { - if (value < _minimum || Mathf.IsZero(value)) - throw new ArgumentOutOfRangeException(); + //if (value < _minimum || Mathf.IsZero(value)) + //throw new ArgumentOutOfRangeException(); if (WholeNumbers) value = Mathf.RoundToInt(value); _maximum = value; @@ -55,6 +62,40 @@ public class Slider : ContainerControl } } + /// + /// 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 slider direction. + /// + [EditorOrder(40), Tooltip("Slider Direction.")] + public SliderDirection Direction + { + get => _direction; + set + { + _direction = value; + UpdateThumb(); + } + } + + private SliderDirection _direction = SliderDirection.HorizontalRight; private float _value = 100f; private Rectangle _thumbRect; private float _thumbCenter; @@ -89,25 +130,61 @@ public class Slider : ContainerControl /// The local position of the thumb center /// [HideInEditor] - public Float2 ThumbCenter => new(_thumbCenter, Height / 2); + public Float2 ThumbCenter => (Direction is SliderDirection.HorizontalLeft or SliderDirection.HorizontalRight) ? new Float2(_thumbCenter, Height / 2) : new Float2(Width / 2, _thumbCenter); /// /// The local position of the beginning of the track. /// [HideInEditor] - public Float2 TrackBeginning => new(_thumbSize.X / 2, Height / 2); + public Float2 TrackBeginning + { + get + { + switch (Direction) + { + case SliderDirection.HorizontalRight: + return new Float2(_thumbSize.X / 2, Height / 2); + case SliderDirection.HorizontalLeft: + return new Float2(Width - _thumbSize.X / 2, Height / 2); + case SliderDirection.VerticalUp: + return new Float2(Width / 2, Height - _thumbSize.Y / 2); + case SliderDirection.VerticalDown: + return new Float2(Width / 2, _thumbSize.Y / 2); + default: break; + } + return Float2.Zero; + } + } /// /// The local position of the end of the track. /// [HideInEditor] - public Float2 TrackEnd => new(Width - _thumbSize.X / 2, Height / 2); - + public Float2 TrackEnd + { + get + { + switch (Direction) + { + case SliderDirection.HorizontalRight: + return new Float2(Width - _thumbSize.X / 2, Height / 2); + case SliderDirection.HorizontalLeft: + return new Float2(_thumbSize.X / 2, Height / 2); + case SliderDirection.VerticalUp: + return new Float2(Width / 2, _thumbSize.Y / 2); + case SliderDirection.VerticalDown: + return new Float2(Width / 2, Height - _thumbSize.Y / 2); + default: break; + } + return Float2.Zero; + } + } + /// /// The height of the track. /// [EditorOrder(40), Tooltip("The track height.")] - public int TrackHeight { get; set; } = 2; + public int TrackThickness { get; set; } = 2; /// /// The thumb size. @@ -147,9 +224,14 @@ public class Slider : ContainerControl public Color TrackFillLineColor { get; set; } /// - /// Gets the size of the track. + /// Gets the width of the track. /// - private float TrackWidth => Width; + private float TrackWidth => (Direction is SliderDirection.HorizontalLeft or SliderDirection.HorizontalRight) ? Width - _thumbSize.X : TrackThickness; + + /// + /// Gets the height of the track. + /// + private float TrackHeight => (Direction is SliderDirection.HorizontalLeft or SliderDirection.HorizontalRight) ? TrackThickness : Height - _thumbSize.Y; /// /// Gets or sets the brush used for slider track drawing. @@ -236,13 +318,32 @@ public class Slider : ContainerControl private void UpdateThumb() { // Cache data - float trackSize = TrackWidth; + var isHorizontal = Direction is SliderDirection.HorizontalRight or SliderDirection.HorizontalLeft; + float trackSize = isHorizontal ? Width : Height; float range = Maximum - Minimum; - float pixelRange = trackSize - _thumbSize.X; + float pixelRange = trackSize - (isHorizontal ? _thumbSize.X : _thumbSize.Y); 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); + switch (Direction) + { + case SliderDirection.HorizontalRight: + _thumbCenter = thumbPosition + _thumbSize.X / 2; + _thumbRect = new Rectangle(thumbPosition, (Height - _thumbSize.Y) / 2, _thumbSize.X, _thumbSize.Y); + break; + case SliderDirection.VerticalDown: + _thumbCenter = thumbPosition + _thumbSize.Y / 2; + _thumbRect = new Rectangle((Width - _thumbSize.X) / 2, thumbPosition, _thumbSize.X, _thumbSize.Y); + break; + case SliderDirection.HorizontalLeft: + _thumbCenter = Width - thumbPosition - _thumbSize.X / 2; + _thumbRect = new Rectangle(Width - thumbPosition - _thumbSize.X, (Height - _thumbSize.Y) / 2, _thumbSize.X, _thumbSize.Y); + break; + case SliderDirection.VerticalUp: + _thumbCenter = Height - thumbPosition - _thumbSize.Y / 2; + _thumbRect = new Rectangle((Width - _thumbSize.X) / 2, Height - thumbPosition - _thumbSize.Y, _thumbSize.X, _thumbSize.Y); + break; + default: break; + } } private void EndSliding() @@ -256,19 +357,37 @@ public class Slider : ContainerControl public override void Draw() { base.Draw(); - + + // Set rectangles + var lineRect = new Rectangle(_thumbSize.X / 2, (Height - TrackThickness) / 2, Width - _thumbSize.X, TrackThickness); + var fillLineRect = new Rectangle(_thumbSize.X / 2 - 1, (Height - TrackThickness - 2) / 2, Width - (Width - _thumbCenter) - _thumbSize.X / 2 + 1, TrackThickness + 2); + switch (Direction) + { + case SliderDirection.HorizontalRight: + break; + case SliderDirection.VerticalDown: + lineRect = new Rectangle((Width - TrackThickness) / 2 , _thumbSize.Y / 2, TrackThickness, Height - _thumbSize.Y); + fillLineRect = new Rectangle((Width - TrackThickness - 2) / 2, _thumbSize.Y / 2 - 1, TrackThickness + 2, Height - (Height - _thumbCenter) - _thumbSize.Y / 2 + 1); + break; + case SliderDirection.HorizontalLeft: + fillLineRect = new Rectangle(Width - (Width - _thumbCenter) - 1, (Height - TrackThickness - 2) / 2, Width - _thumbCenter + 1, TrackThickness + 2); + break; + case SliderDirection.VerticalUp: + lineRect = new Rectangle((Width - TrackThickness) / 2 , _thumbSize.Y / 2, TrackThickness, Height - _thumbSize.Y); + fillLineRect = new Rectangle((Width - TrackThickness - 2) / 2, Height - (Height - _thumbCenter) - 1, TrackThickness + 2, Height - _thumbCenter + 1); + break; + default: break; + } + // 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); - + Render2D.FillRectangle(lineRect, TrackLineColor); + // Draw track fill if (FillTrack) { - var fillLineRect = new Rectangle(_thumbSize.X / 2 - 1, (Height - TrackHeight - 2) / 2, Width - (Width - _thumbCenter) - _thumbSize.X / 2, TrackHeight + 2); Render2D.PushClip(ref fillLineRect); if (FillTrackBrush != null) FillTrackBrush.Draw(lineRect, TrackFillLineColor); @@ -276,13 +395,13 @@ public class Slider : ContainerControl Render2D.FillRectangle(lineRect, TrackFillLineColor); Render2D.PopClip(); } - + // Draw thumb - var thumbColor = _isSliding ? ThumbColorSelected : (_mouseOverThumb ? ThumbColorHighlighted : ThumbColor); + var thumbColorV = _isSliding ? ThumbColorSelected : (_mouseOverThumb ? ThumbColorHighlighted : ThumbColor); if (ThumbBrush != null) - ThumbBrush.Draw(_thumbRect, thumbColor); + ThumbBrush.Draw(_thumbRect, thumbColorV); else - Render2D.FillRectangle(_thumbRect, thumbColor); + Render2D.FillRectangle(_thumbRect, thumbColorV); } /// @@ -302,7 +421,7 @@ public class Slider : ContainerControl if (button == MouseButton.Left) { Focus(); - float mousePosition = location.X; + float mousePosition = Direction is SliderDirection.HorizontalRight or SliderDirection.HorizontalLeft ? location.X : location.Y; if (_thumbRect.Contains(ref location)) { @@ -315,7 +434,16 @@ public class Slider : ContainerControl else { // Click change - Value += (mousePosition < _thumbCenter ? -1 : 1) * 10; + switch (Direction) + { + case SliderDirection.HorizontalRight or SliderDirection.VerticalDown: + Value += (mousePosition < _thumbCenter ? -1 : 1) * 10; + break; + case SliderDirection.HorizontalLeft or SliderDirection.VerticalUp: + Value -= (mousePosition < _thumbCenter ? -1 : 1) * 10; + break; + default: break; + } } } @@ -330,7 +458,22 @@ public class Slider : ContainerControl { // Update sliding var slidePosition = location + Root.TrackingMouseOffset; - Value = Mathf.Remap(slidePosition.X, 4, TrackWidth - 4, Minimum, Maximum); + switch (Direction) + { + case SliderDirection.HorizontalRight: + Value = Mathf.Remap(slidePosition.X, 4, Width - 4, Minimum, Maximum); + break; + case SliderDirection.VerticalDown: + Value = Mathf.Remap(slidePosition.Y, 4, Height - 4, Minimum, Maximum); + break; + case SliderDirection.HorizontalLeft: + Value = Mathf.Remap(slidePosition.X, Width - 4, 4, Minimum, Maximum); + break; + case SliderDirection.VerticalUp: + Value = Mathf.Remap(slidePosition.Y, Height - 4, 4, Minimum, Maximum); + break; + default: break; + } } else {