Files
sbox-public/game/addons/base/code/UI/Controls/SliderControl.razor
2025-12-19 16:37:55 +00:00

192 lines
4.6 KiB
Plaintext

@using System
@namespace Sandbox.UI
@inherits BaseControl
@attribute [CustomEditor( typeof(float), WithAllAttributes = [ typeof(RangeAttribute) ] )]
<root class="slidercontrol">
@if ( ShowTextEntry )
{
<div class="entry">
<NumberEntry @ref="TextEntryPanel" Value:bind="@Value" Numeric="@true" NumberFormat="@NumberFormat"></NumberEntry>
</div>
}
<div class="inner">
@if (ShowRange)
{
<div class="values">
<div class="left">@Min.ToString( NumberFormat )</div>
<div class="right">@Max.ToString( NumberFormat )</div>
</div>
}
<div @ref="TrackPanel" class="track">
<div class="track-active" style="width: @(SliderPosition)%;"></div>
<div @ref="ThumbPanel" style="left: @(SliderPosition)%;" class="thumb">
@if (this.HasActive)
{
<div class="value-tooltip">
<label>@Value.ToString( NumberFormat )</label>
<div class="tail"></div>
</div>
}
</div>
</div>
</div>
</root>
@code
{
public override bool SupportsMultiEdit => true;
[Parameter] public Action<float> OnValueChanged { get; set; }
/// <summary>
/// The right side of the slider.
/// </summary>
[Parameter] public float Max { get; set; } = 100;
/// <summary>
/// The left side of the slider.
/// </summary>
[Parameter] public float Min { get; set; } = 0;
/// <summary>
/// If set to 1, value will be rounded to 1's
/// If set to 10, value will be rounded to 10's
/// If set to 0.1, value will be rounded to 0.1's
/// </summary>
[Parameter] public float Step { get; set; } = 0.001f;
/// <summary>
/// Show the range values above the slider
/// </summary>
[Parameter] public bool ShowRange { get; set; } = false;
/// <summary>
/// When changing the value show the tooltip
/// </summary>
[Parameter] public bool ShowValueTooltip { get; set; } = true;
/// <summary>
/// When changing the value show the tooltip
/// </summary>
[Parameter] public bool ShowTextEntry { get; set; } = false;
/// <summary>
/// How to display numbers in this control
/// </summary>
[Parameter] public string NumberFormat { get; set; } = "0.###";
float _value;
[Parameter]
public float Value
{
get => Property?.As.Float ?? _value;
set
{
if (Property is not null)
{
Property.As.Float = value;
StateHasChanged();
return;
}
if (_value == value)
return;
_value = MathX.Clamp( _value, Min, Max );
_value = value;
StateHasChanged();
}
}
Panel TrackPanel { get; set; }
Panel ThumbPanel { get; set; }
TextEntry TextEntryPanel { get; set; }
public SliderControl()
{
}
public SliderControl(float min, float max, float step = 1.0f)
{
Min = min;
Max = max;
Step = step;
}
public override void Rebuild()
{
if (Property is null) return;
ShowTextEntry = true;
if (Property.TryGetAttribute<RangeAttribute>(out var rangeAttribute))
{
Min = rangeAttribute.Min;
Max = rangeAttribute.Max;
}
if ( Property.TryGetAttribute<StepAttribute>( out var stepAttribute ) )
{
Step = stepAttribute.Step;
}
}
/// <summary>
/// Convert a screen position to a value. The value is clamped, but not snapped.
/// </summary>
public virtual float ScreenPosToValue( Vector2 pos )
{
var normalized = MathX.LerpInverse(pos.x, TrackPanel.Box.Left, TrackPanel.Box.Right, true);
var scaled = MathX.LerpTo( Min, Max, normalized, true );
return Step > 0 ? scaled.SnapToGrid( Step ) : scaled;
}
/// <summary>
/// If we move the mouse while we're being pressed then set the value
/// </summary>
protected override void OnMouseMove( MousePanelEvent e )
{
base.OnMouseMove( e );
if ( !HasActive || e.MouseButton == MouseButtons.Middle ) return;
Value = ScreenPosToValue( Mouse.Position );
OnValueChanged?.Invoke( Value );
e.StopPropagation();
}
/// <summary>
/// On mouse press jump to that position
/// </summary>
protected override void OnMouseDown( MousePanelEvent e )
{
base.OnMouseDown( e );
Value = ScreenPosToValue( Mouse.Position );
OnValueChanged?.Invoke( Value );
e.StopPropagation();
TextEntryPanel?.Blur();
}
protected override void OnMiddleClick( MousePanelEvent e )
{
base.OnMiddleClick( e );
e.StopPropagation();
}
float SliderPosition => MathX.LerpInverse(Value, Min, Max, true) * 100.0f;
}