Editor/DoubleFloatSlider.cs
using Editor;
using Sandbox;
using System;
namespace ExtendedBox;
public sealed class DoubleFloatSlider : Widget
{
private float _valueA;
private float _valueB;
private const float BackgroundOffsetX = 2.5f;
private const float ThumbWidth = 5f;
private const float ThumbHeight = 12f;
public float Minimum { get; set; }
public float Maximum { get; set; }
public Action? OnValueEdited { get; set; }
public Color HighlightColor { get; set; } = Theme.TextLight;
public Action<Rect, float, float>? SliderPaint { get; set; }
public Action? EditingStarted { get; set; }
public Action? EditingFinished { get; set; }
public float ValueA
{
get
{
return _valueA;
}
set
{
float v = ((Step > 0f) ? value.SnapToGrid(Step) : value);
v = v.Clamp(Minimum, Maximum);
if(_valueA != v)
{
_valueA = v;
Update();
}
}
}
public float ValueB
{
get
{
return _valueB;
}
set
{
float v = ((Step > 0f) ? value.SnapToGrid(Step) : value);
v = v.Clamp(Minimum, Maximum);
if(_valueB != v)
{
_valueB = v;
Update();
}
}
}
public float DeltaValueA
{
get
{
return ValueA.LerpInverse(Minimum, Maximum);
}
set
{
float value2 = Minimum.LerpTo(Maximum, value);
ValueA = value2;
}
}
public float DeltaValueB
{
get
{
return ValueB.LerpInverse(Minimum, Maximum);
}
set
{
float value2 = Minimum.LerpTo(Maximum, value);
ValueB = value2;
}
}
public float Step { get; set; } = 0.01f;
private bool? _editingA = true;
public DoubleFloatSlider(Widget parent)
: base(parent)
{
Minimum = 0f;
Maximum = 100f;
ValueA = 25f;
ValueB = 50f;
base.MinimumSize = Theme.RowHeight;
base.MaximumSize = new Vector2(4096f, Theme.RowHeight);
Cursor = CursorShape.Arrow;
}
protected override void OnMouseEnter()
{
base.OnMouseEnter();
Update();
}
protected override void OnMouseLeave()
{
base.OnMouseLeave();
Update();
}
internal void PaintSlider(Rect rect, float deltaA, float deltaB)
{
float backgroundBorderRadius = 3f;
float thumbBorderRadius = 2f;
float backgroundHeight = 5f;
float halfHeight = rect.Height / 2f;
float width = rect.Width;
float backgroundWidth = width - BackgroundOffsetX * 2;
Color fillerColor = HighlightColor;
Paint.Antialiasing = true;
Paint.ClearPen();
//background
var backgroundPoistionY = halfHeight - backgroundHeight * 0.5f;
Color backgroundColor = fillerColor.WithAlpha(0.2f);
Paint.SetBrush(in backgroundColor);
var backgroundRect = new Rect(BackgroundOffsetX, backgroundPoistionY, in backgroundWidth, in backgroundHeight);
Paint.DrawRect(in backgroundRect, backgroundBorderRadius);
var thumbAPositionX = backgroundWidth * deltaA;
var thumbBPositionX = backgroundWidth * deltaB;
var thumpPositionY = halfHeight - ThumbHeight / 2f;
var minThumbPosition = Math.Min(thumbAPositionX, thumbBPositionX);
var maxThumbPosition = Math.Max(thumbAPositionX, thumbBPositionX);
//filler
Paint.SetBrush(in fillerColor);
var fillerRect = new Rect(minThumbPosition, backgroundPoistionY, maxThumbPosition - minThumbPosition + ThumbWidth, in backgroundHeight);
Paint.DrawRect(in fillerRect, backgroundBorderRadius);
//thumb
var thumbColor = Color.Black.WithAlpha(0.2f);
PenStyle thumbStyle = PenStyle.Solid;
Paint.SetBrush(in fillerColor);
Paint.SetPen(in thumbColor, 1f, in thumbStyle);
var thumbARect = new Rect(thumbAPositionX, in thumpPositionY, ThumbWidth, ThumbHeight);
Paint.DrawRect(in thumbARect, thumbBorderRadius);
var thumbBRect = new Rect(thumbBPositionX, in thumpPositionY, ThumbWidth, ThumbHeight);
Paint.DrawRect(in thumbBRect, thumbBorderRadius);
}
protected override void OnPaint()
{
base.OnPaint();
if(SliderPaint == null)
PaintSlider(base.LocalRect, DeltaValueA, DeltaValueB);
else
SliderPaint(base.LocalRect, DeltaValueA, DeltaValueB);
}
private void UpdateClosestFromLocalPosition(float position)
{
if(ReadOnly)
return;
float v = (position - BackgroundOffsetX) / (base.Width - BackgroundOffsetX * 2);
if(!_editingA.HasValue)
_editingA = Math.Abs(DeltaValueA - v) < Math.Abs(DeltaValueB - v);
if(_editingA.Value)
DeltaValueA = v.Clamp(0f, 1f);
else
DeltaValueB = v.Clamp(0f, 1f);
OnValueEdited?.Invoke();
SignalValuesChanged();
}
protected override void OnMousePress(MouseEvent e)
{
if(!ReadOnly)
{
e.Accepted = true;
if(e.LeftMouseButton)
{
EditingStarted?.Invoke();
UpdateClosestFromLocalPosition(e.LocalPosition.x);
}
}
}
protected override void OnMouseMove(MouseEvent e)
{
if(!ReadOnly)
{
e.Accepted = true;
if(e.ButtonState.Contains(MouseButtons.Left))
{
UpdateClosestFromLocalPosition(e.LocalPosition.x);
}
}
}
protected override void OnMouseReleased(MouseEvent e)
{
base.OnMouseReleased(e);
e.Accepted = true;
if(e.LeftMouseButton)
{
_editingA = null;
EditingFinished?.Invoke();
}
}
}